From 5b1266233dc891b089e19da764b9c06136674c30 Mon Sep 17 00:00:00 2001 From: ludamad Date: Mon, 17 Apr 2023 14:24:41 -0400 Subject: [PATCH 001/166] chore: remove circuits before inline aztec3-circuits --- circuits | 1 - 1 file changed, 1 deletion(-) delete mode 160000 circuits diff --git a/circuits b/circuits deleted file mode 160000 index f1dc5d36c5f..00000000000 --- a/circuits +++ /dev/null @@ -1 +0,0 @@ -Subproject commit f1dc5d36c5fb3684c8d38ce59ce9b23bc71e4f7d From 607a236680a4bab5b0effcab27c1743063524312 Mon Sep 17 00:00:00 2001 From: iAmMichaelConnor Date: Tue, 22 Feb 2022 17:09:05 +0000 Subject: [PATCH 002/166] feat: aztec 3 book --- circuits/specs/README.md | 49 ++ circuits/specs/book.toml | 19 + circuits/specs/macros.txt | 59 +++ circuits/specs/src/QUESTIONS.md | 60 +++ circuits/specs/src/SUMMARY.md | 70 +++ .../app-circuits/public-input-abis.md | 166 ++++++ .../src/architecture/contracts/contracts.md | 21 + .../src/architecture/contracts/deployment.md | 115 +++++ .../architecture/contracts/function-types.md | 71 +++ .../src/architecture/contracts/l1-calls.md | 217 ++++++++ .../contracts/states-and-storage.md | 114 +++++ .../architecture/contracts/transactions.md | 148 ++++++ .../specs/src/architecture/contracts/trees.md | 35 ++ circuits/specs/src/architecture/fees/fees.md | 1 + .../contract-deployment-kernel.md | 284 +++++++++++ .../kernel-circuits/kernel-circuits.md | 33 ++ .../kernel-circuits/private-kernel.md | 292 +++++++++++ .../kernel-circuits/public-kernel.md | 301 +++++++++++ .../rollup-circuits/base-rollup.md | 428 ++++++++++++++++ .../rollup-circuits/l1-results-copier.md | 55 ++ .../rollup-circuits/merge-rollup.md | 155 ++++++ .../rollup-circuits/rollup-circuits.md | 7 + .../standard-plonk-converter.md | 4 + .../src/examples/erc20/appendix/appendix.md | 3 + .../erc20/appendix/portal-contract.md | 198 ++++++++ .../erc20/appendix/rollup-processor.md | 213 ++++++++ .../specs/src/examples/erc20/deployment.md | 189 +++++++ circuits/specs/src/examples/erc20/deposit.md | 42 ++ .../src/examples/erc20/erc20-shielding.md | 5 + circuits/specs/src/examples/erc20/transfer.md | 12 + circuits/specs/src/examples/erc20/withdraw.md | 26 + circuits/specs/src/intro.md | 19 + .../specs/src/noir-stuff/extremes/call-l1.md | 479 ++++++++++++++++++ .../src/noir-stuff/extremes/call-private.md | 150 ++++++ .../noir-stuff/extremes/call-public-same.md | 147 ++++++ .../src/noir-stuff/extremes/call-public.md | 147 ++++++ .../specs/src/noir-stuff/extremes/callback.md | 1 + .../src/noir-stuff/extremes/claim-simple.md | 190 +++++++ .../noir-stuff/extremes/decr-private-owned.md | 272 ++++++++++ .../noir-stuff/extremes/deploy-contract.md | 293 +++++++++++ .../src/noir-stuff/extremes/edit-public.md | 66 +++ .../src/noir-stuff/extremes/emit-event.md | 109 ++++ .../specs/src/noir-stuff/extremes/extremes.md | 28 + .../src/noir-stuff/extremes/global-vars.md | 10 + .../extremes/incr-private-not-owned.md | 83 +++ .../noir-stuff/extremes/incr-private-owned.md | 286 +++++++++++ .../src/noir-stuff/extremes/read-public.md | 67 +++ circuits/specs/src/noir-stuff/noir-stuff.md | 4 + circuits/specs/theme/css/general.css | 215 ++++++++ circuits/specs/theme/css/style.css | 42 ++ circuits/specs/theme/css/variables.css | 255 ++++++++++ circuits/specs/theme/index.hbs | 310 ++++++++++++ circuits/specs/theme/sidebar.js | 66 +++ 53 files changed, 6631 insertions(+) create mode 100644 circuits/specs/README.md create mode 100644 circuits/specs/book.toml create mode 100644 circuits/specs/macros.txt create mode 100644 circuits/specs/src/QUESTIONS.md create mode 100644 circuits/specs/src/SUMMARY.md create mode 100644 circuits/specs/src/architecture/app-circuits/public-input-abis.md create mode 100644 circuits/specs/src/architecture/contracts/contracts.md create mode 100644 circuits/specs/src/architecture/contracts/deployment.md create mode 100644 circuits/specs/src/architecture/contracts/function-types.md create mode 100644 circuits/specs/src/architecture/contracts/l1-calls.md create mode 100644 circuits/specs/src/architecture/contracts/states-and-storage.md create mode 100644 circuits/specs/src/architecture/contracts/transactions.md create mode 100644 circuits/specs/src/architecture/contracts/trees.md create mode 100644 circuits/specs/src/architecture/fees/fees.md create mode 100644 circuits/specs/src/architecture/kernel-circuits/contract-deployment-kernel.md create mode 100644 circuits/specs/src/architecture/kernel-circuits/kernel-circuits.md create mode 100644 circuits/specs/src/architecture/kernel-circuits/private-kernel.md create mode 100644 circuits/specs/src/architecture/kernel-circuits/public-kernel.md create mode 100644 circuits/specs/src/architecture/rollup-circuits/base-rollup.md create mode 100644 circuits/specs/src/architecture/rollup-circuits/l1-results-copier.md create mode 100644 circuits/specs/src/architecture/rollup-circuits/merge-rollup.md create mode 100644 circuits/specs/src/architecture/rollup-circuits/rollup-circuits.md create mode 100644 circuits/specs/src/architecture/rollup-circuits/standard-plonk-converter.md create mode 100644 circuits/specs/src/examples/erc20/appendix/appendix.md create mode 100644 circuits/specs/src/examples/erc20/appendix/portal-contract.md create mode 100644 circuits/specs/src/examples/erc20/appendix/rollup-processor.md create mode 100644 circuits/specs/src/examples/erc20/deployment.md create mode 100644 circuits/specs/src/examples/erc20/deposit.md create mode 100644 circuits/specs/src/examples/erc20/erc20-shielding.md create mode 100644 circuits/specs/src/examples/erc20/transfer.md create mode 100644 circuits/specs/src/examples/erc20/withdraw.md create mode 100644 circuits/specs/src/intro.md create mode 100644 circuits/specs/src/noir-stuff/extremes/call-l1.md create mode 100644 circuits/specs/src/noir-stuff/extremes/call-private.md create mode 100644 circuits/specs/src/noir-stuff/extremes/call-public-same.md create mode 100644 circuits/specs/src/noir-stuff/extremes/call-public.md create mode 100644 circuits/specs/src/noir-stuff/extremes/callback.md create mode 100644 circuits/specs/src/noir-stuff/extremes/claim-simple.md create mode 100644 circuits/specs/src/noir-stuff/extremes/decr-private-owned.md create mode 100644 circuits/specs/src/noir-stuff/extremes/deploy-contract.md create mode 100644 circuits/specs/src/noir-stuff/extremes/edit-public.md create mode 100644 circuits/specs/src/noir-stuff/extremes/emit-event.md create mode 100644 circuits/specs/src/noir-stuff/extremes/extremes.md create mode 100644 circuits/specs/src/noir-stuff/extremes/global-vars.md create mode 100644 circuits/specs/src/noir-stuff/extremes/incr-private-not-owned.md create mode 100644 circuits/specs/src/noir-stuff/extremes/incr-private-owned.md create mode 100644 circuits/specs/src/noir-stuff/extremes/read-public.md create mode 100644 circuits/specs/src/noir-stuff/noir-stuff.md create mode 100644 circuits/specs/theme/css/general.css create mode 100644 circuits/specs/theme/css/style.css create mode 100644 circuits/specs/theme/css/variables.css create mode 100644 circuits/specs/theme/index.hbs create mode 100644 circuits/specs/theme/sidebar.js diff --git a/circuits/specs/README.md b/circuits/specs/README.md new file mode 100644 index 00000000000..e4093278335 --- /dev/null +++ b/circuits/specs/README.md @@ -0,0 +1,49 @@ +# Aztec 3 Book + +## To view the book +### One-off steps + +Install mdBook: + +1. [Rust](https://www.rust-lang.org/tools/install): `curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh` +2. [mdbook](https://rust-lang.github.io/mdBook/guide/installation.html#build-from-source-using-rust): `cargo install mdbook` +3. [mdbook-katex](https://github.com/lzanini/mdbook-katex): `cargo install mdbook-katex` + +Configure port forwarding, so you can write markdown code on mainframe, but view the book in your local browser: + +- `command` + `shift` + `p` to open the command pallette +- Type and select `Remote ssh open ssh configuration file` +- Select `/Users//.ssh/config` from the drop-down menu +- Below all your existing `LocalForward` instructions, add another: + ``` + LocalForward 3000 :3000 + ``` + +The IP address (of the form `_._._._`) to use is the same as all the other LocalForward instructions you already have in your config. +If you already use port `3000` for something, choose something else. + +### To view the book + +- `cd aztec-internal` +- `cd markdown/specs/aztec3` +- `mdbook serve -p 3000 -n ` + + +Open a browser on your local machine and navigate to `localhost:3000`. The book should appear. `mdbook serve` has built the book and is serving the book in 'watch' mode, so any changes you make to the book on mainframe can be viewed by refreshing your browser. + +Alternatively, you can use a vscode extension to preview the book's pages (shortcut to previewing is `command`+`shift`+`v`), but it won't be as easily navigable (from page to page) as through the browser. + +> **Note** The book is also searchable which is AWESOME (click the magnifying glass when viewing in the browser). + +## To edit the book + +Just change the files in `src/`. + +## What are all the other files in here? + +``` +book.toml - used by mdbook to build the book +macros.txt - latex macros +sidebar.js & style.css - an add-on to mdbook to show a sidebar of a page's headers, at the right (it's clunky, but mdbook without it isn't nice). +dist/ - the built book, updated each time you save, when running `mdbook serve ...` +``` \ No newline at end of file diff --git a/circuits/specs/book.toml b/circuits/specs/book.toml new file mode 100644 index 00000000000..281eb34033e --- /dev/null +++ b/circuits/specs/book.toml @@ -0,0 +1,19 @@ +[book] +authors = ["Aztec"] +language = "en" +multilingual = false +src = "src" +title = "Aztec 3.0" + +[output.html] +additional-css = ["theme/css/style.css"] +additional-js = ["theme/sidebar.js"] +# site-url = "/aztec3/" + +[build] +build-dir = "dist" + +# [output.katex] + +[preprocessor.katex] +macros = "macros.txt" \ No newline at end of file diff --git a/circuits/specs/macros.txt b/circuits/specs/macros.txt new file mode 100644 index 00000000000..970320d7334 --- /dev/null +++ b/circuits/specs/macros.txt @@ -0,0 +1,59 @@ +\field:{\mathbb{F}} +\group:{\mathbb{G}} +\setup:{\textnormal{Setup}} +\prover:{\mathcal{P}} +\verifier:{\mathcal{V}} +\sec:{\lambda} +\negl:{\textnormal{negl}(\lambda)} +\pp:{\mathsf{pp}} +\ip:{\textnormal{IP}} +\relation:{\mathcal{R}} +\a:{\mathcal{A}} +\sim:{\mathcal{S}} +\tr:{\textnormal{tr}} +\srs:{\textnormal{SRS}} +\srwee:{\textnormal{sr-wee}} +\real:{\textnormal{real}} +\ideal:{\textnormal{ideal}} +\weereal:{\textnormal{WEE-real}} +\weeideal:{\textnormal{WEE-ideal}} +\oracle:{\mathcal{O}} +\ch:{\mathsf{Ch}} +\badch:{\mathsf{BadCh}} +\adv:{\mathsf{Adv}} +\bottom:{\perp} +\alg:{#1_\textnormal{alg}} +\zero:{\mathcal{O}} +\dlrel:{\mathsf{dl-rel}} +\game:{\mathsf{G}} +\innerprod:{\langle{#1},{#2}\rangle} +\dlgame:{\mathsf{G}^\dlrel_{\group,n}} +\distinguisher:{\mathcal{D}} +\extractor:{\mathcal{E}} +\state:{\mathsf{st}_{#1}} +\halo:{\textsf{Halo}} +\lo:{\textnormal{lo}} +\hi:{\textnormal{hi}} +\protocol:{\halo} + +\note:{\textsf{note}} +\value:{\textsf{val}} +\ivalue:{\textcolor{red}{\value_{#1}^{(\text{in})}}} +\ovalue:{\textcolor{green}{\value_{#1}^{(\text{out})}}} +\account:{\textsf{acc}} +\claim:{\textsf{acc}} +\defi:{\textsf{defi}} +\owner:{\mathcal{O}} +\null:{\mathsf{N}} +\comm:{\mathsf{C}} +\creator:{\mathsf{P}} +\bool:{\mathbb{B}} + +\dtree:{\mathbb{D}} +\ntree:{\mathbb{N}} +\rtree:{\mathbb{R}} +\itree:{\mathbb{I}} +\droot:{\mathcal{D}} +\nroot:{\mathcal{N}} +\rroot:{\mathcal{R}} +\iroot:{\mathcal{I}} \ No newline at end of file diff --git a/circuits/specs/src/QUESTIONS.md b/circuits/specs/src/QUESTIONS.md new file mode 100644 index 00000000000..9718fa3523f --- /dev/null +++ b/circuits/specs/src/QUESTIONS.md @@ -0,0 +1,60 @@ +# Questions + +A list of random thoughts and questions that haven't been fully considered yet. + +This isn't a comprehensive list of questions - there are loads dotted around these pages. + +- Where to develop the code? + - Will need to make significant edits to Falafel. + - Aztec Connect circuits aren't needed. +- How should I proceeed? + - I could plan out lots of distinct tasks. + - Roadmap: + - Releases with milestones of functionality? + - One final big release at the end? + - E.g. Charlie suggested ignoring Public circuit functionality altogether initially. + - I can start writing kernel circuits, rollup circuits, making changes to falafel, writing smart contracts. +- Components: + - Smart contract language: Noir? + - Testing framework: also Noir? + - Rollup provider full node: Falafel? + - Receives tx requests + - Creates rollups + - Coordinates delegation of proofs (future enhancement) + - Tracks the entire L2 state + - Rollup delegate node: Falafel in different 'mode'. + - Can be given / takes instructions to generate proofs for the rollup. + - Incentivisation mechanism needed? I think we can avoid this. + - User node: Also Falafel in a different 'mode', or separate? + - For generating client-side proofs + - Submitting proofs to the Rollup Provider pool + - For keeping minimal user state witnesses and querying stuff. + - User node: non-browser version? + - web3.js/ethers.js pacakge to convert JS tx requests into the Aztec 3 ABI format. +- Noir - how 'high-level' should it be? + - One extreme: it 'abstracts away' all of Aztec 3's architecture from the developer. + - Problem: one API for developer, and another ABI for the underlying circuit. + - Either need Noir plugged into a DB (but I'd prefer it to be stateless) + - Or need an ethers.js program to take a JS tx, query the falafel DB, then send an ABI-style tx to Noir. + - If we make architecture changes to the Public Inputs ABIs (which we will when optimising), Noir would need corresponding changes. + - Other extreme: a developer needs to write, in detail, circuits which conform to the Aztec 3 spec. +- Once the HONK backend is ready, will we be able to simply 'swap' our kernel circuits' backend from PLONK to HONK? +- Ask about callbacks: + - One-time-use callbacks (my preference) vs callback behaviour designed by each dev. + - Dedicated, decorated callback functions vs general functions that don't even _know_ they're a callback. + - If decorated as callback, the function can contain L1 result reconciliation logic. + - If general functions, then the L1 result reconciliation must happen in the kernel circuit / base rollup circuit. +- Meh: Take a look at an [alternative suggestion for callbacks](./architecture/contracts/l1-calls.md#alternative-approach-to-callbacks), and decide which is best. +- Decentralisation Roadmap: + - Rollup provider selection process? + - Aztec Token tokenomics. + - Tx pool - p2p messaging layer? Or direct messaging (if the Rollup Provider is the same for a period of time)? +- Revisit discussion on fees and attributing L2 fees payments to provers based on their proving work. +- Use ETH as L2 gas payment currency, or allow any general function to be labelled as a 'fee paying' currency? + - If we have specific gas costs relating to SLOAD / GEN_PROOF, then these will need to be paid in ETH surely? +- Ask about dynamic arrays and what the limitations are in UltraPlonk. + - Pushing to all of these callStacks is going to expensive (constraint-wise), especially if we want to tightly pack pushes. Lots of O(n^2) searching for correct positions in arrays. + - Unless we can do some clever dynamic array stuff with ultraplonk / honk? +- Do we need to emit all events to a special log that can be parsed? Like an L2 version of Ethereum's logs? + - E.g. how can app-specific javascript code 'react' to an event emitted by an L2 function? + - How does Ethereum do it? diff --git a/circuits/specs/src/SUMMARY.md b/circuits/specs/src/SUMMARY.md new file mode 100644 index 00000000000..0f9633bec31 --- /dev/null +++ b/circuits/specs/src/SUMMARY.md @@ -0,0 +1,70 @@ +# Summary + +[Introduction](intro.md) + +# Contracts + +- [Overview](./architecture/contracts/contracts.md) +- [Trees](./architecture/contracts/trees.md) +- [Function Types](./architecture/contracts/function-types.md) +- [States & Storage](./architecture/contracts/states-and-storage.md) +- [Contract Deployment](./architecture/contracts/deployment.md) +- [Transactions (Calls)](./architecture/contracts/transactions.md) +- [L1 Calls](architecture/contracts/l1-calls.md) + +# Fees + +- [Fees](./architecture/fees/fees.md) + +# App-specific Circuits + +- [Public Input ABIs](./architecture/app-circuits/public-input-abis.md) + +# Kernel Circuits + +- [Intro](./architecture/kernel-circuits/kernel-circuits.md) +- [Private Kernel Circuit](./architecture/kernel-circuits/private-kernel.md) +- [Public Kernel Circuit](./architecture/kernel-circuits/public-kernel.md) +- [Contract Deployment Kernel Circuit](./architecture/kernel-circuits/contract-deployment-kernel.md) + +# Rollup Circuits + +- [Intro](./architecture/rollup-circuits/rollup-circuits.md) +- [Base Rollup Circuit](./architecture/rollup-circuits/base-rollup.md) +- [Merge Rollup Circuit](./architecture/rollup-circuits/merge-rollup.md) +- [L1 Results Copier Circuit](./architecture/rollup-circuits/l1-results-copier.md) +- [Standard Plonk Converter Circuit](./architecture/rollup-circuits/standard-plonk-converter.md) + +# Examples + +- [ERC20 Shielding](./examples/erc20/erc20-shielding.md) + - [Deployment](./examples/erc20/deployment.md) + - [Deposit](./examples/erc20/deposit.md) + - [Transfer](./examples/erc20/transfer.md) + - [Withdraw](./examples/erc20/withdraw.md) + - [Appendix](./examples/erc20/appendix/appendix.md) + - [RollupProcessor Contract](./examples/erc20/appendix/rollup-processor.md) + - [Portal Contract](./examples/erc20/appendix/portal-contract.md) + +# Noir Stuff +- [Intro](./noir-stuff/noir-stuff.md) +- [Extremes](./noir-stuff/extremes/extremes.md) + - [incrementation of private state _not_ owned by caller](./noir-stuff/extremes/incr-private-not-owned.md) + - [incrementation of private state owned by the caller](./noir-stuff/extremes/incr-private-owned.md) + - [decrementation of private state owned by the caller](./noir-stuff/extremes/decr-private-owned.md) + - [editing a public state](./noir-stuff/extremes/edit-public.md) + - [reading a public state](./noir-stuff/extremes/read-public.md) + - [calling a private function of a different contract](./noir-stuff/extremes/call-private.md) + - [calling a public function of a different contract](./noir-stuff/extremes/call-public.md) + - [calling a public function from a private function of the same contract](./noir-stuff/extremes/call-public-same.md) + - [calling an L1 function](./noir-stuff/extremes/call-l1.md) + - [emitting an 'event'](./noir-stuff/extremes/emit-event.md) + - [executing a function as a callback, following an L1 result](./noir-stuff/extremes/callback.md) + - [deploying a contract from a private/public function](./noir-stuff/extremes/deploy-contract.md) + - [new contract constructors]() + - ['globally' available variables](./noir-stuff/extremes/global-vars.md) + - [Aztec Connect claim example](./noir-stuff/extremes/claim-simple.md) + +# Open Questions + +- [Questions](./QUESTIONS.md) \ No newline at end of file diff --git a/circuits/specs/src/architecture/app-circuits/public-input-abis.md b/circuits/specs/src/architecture/app-circuits/public-input-abis.md new file mode 100644 index 00000000000..7fd33a5821c --- /dev/null +++ b/circuits/specs/src/architecture/app-circuits/public-input-abis.md @@ -0,0 +1,166 @@ +# Public Input ABIs + +The following describes how many public inputs each public/private circuit will have and how they will be interpreted. + + +## Private Circuit ABI + +All private contract circuits have a fixed number of public inputs. Most of these public inputs will eventually be swallowed by the [private kernel circuit](../kernel-circuits/private-kernel.md). Under some circumstances, some public inputs will be optionally revealed to the 'public world, depending on the various booleans in this table. + +> Note: some of these inputs might be packed into 1 field for efficiencies in the implementation, but for ease of understanding they're kept separate here. + + +| Data type | Description | +| -------- | -------- | +| `customPublicInputs` | Up to 32 circuit-specific inputs passed into this circuit. All of these inputs will be 'swallowed' by the private kernel snark.
Note: for a private circuit, we don't need a field for 'custom outputs' from the circuit, since all inputs/output must be known in advance, and so for simplicity can all be considered 'inputs'. | +| `emittedPublicInputs` | Public inputs which will be revealed to the 'public world' (L1 or L2). E.g. allowing certain inputs to be more-easily extracted by the RollupProcessor contract (rather than having to unpack this vast ABI object of inputs, which would cost too much hash-wise). An example of its usefulness is passing a value from L1 to L2 when doing an L1->L2 tx (see 'deposit' example in the other doc). TODO: consider whether this could be a single value, for simplicity. It could be a hash of data if more values need to be exposed. If so, we'll rename to `emittedPublicInputsHash`. | +| `executedCallback: {` | Populated if this circuit is a callback, so that the purported L1 Result to which this circuit is responding can be validated against the l1ResultsTree. | +| `- l1ResultHash`, | If this function is a callback function, following some L1 call, then it needs to expose the `l1ResultHash` to ensure the callback is actually using data emitted by L1. The preimage of the `l1ResultHash` will need to be passed in as private inputs to the circuit. Note: the `l1ResultHash` MUST be computed with a sha256 hash, because that's what the RollupProcessor will have used. This is unfortunate, as it forces apps to adhere to a specific calculation within their circuits. | +| `- l1ResultsTreeLeafIndex`, | Communicates to the rollup provider the correct leaf to prove membership against in the l1ResultsTree. Only if we don't want to hide the callback will the rollup provider perform the membership check (within the Base Rollup Circuit). Otherwise it'll be performed in the Private Kernel Circuit. | +| `}`| +| `outputCommitments` | output notes to be added into the `privateDataTree` (up to 16) | +| `inputNullifiers` | input nullifiers to be added into the `nullifierTree` (up to 16) | +| `privateCallStack` | additional private calls created by this transaction (up to 16) | +| `publicCallStack` | additional public calls created by this transaction (up to 16) | +| `contractDeploymentCallStack` | additional calls which _deploy contracts_, created by this transaction (up to 1?) | +| `partialL1CallStack` | additional calls to L1 created by this transaction (up to 16). "Partial" because the kernel circuit will add the correct portal contract address to 'complete' the call into a proper L1 CallStack Item. See [here](../contracts/l1-calls.md). | +|
callbackStack = [{
  callbackPublicKey,
  successCallbackCallHash,
  failureCallbackCallHash,
  successResultArgMapAcc,
},...]
| An element in the array for each new L1 call on the `l1CallStack`. See [more](../contracts/l1-calls.md). We need to expose all of this data so that the kernel snark ensures the callback is a function of the same contract which made the call. | +| `oldPrivateDataTreeRoot` | used to query the `privateDataTree` | +| Booleans: | | +| `bool isFeePayment` | Notifies the kernel circuit that the following public inputs of this private circuit MUST be revealed to the public kernel circuit:
  • `functionSignature` - so that the rollup provider can see how they're to be paid
  • `emittedPublicInputs` - so that the rollup provider can validate the amount they'll be paid (they'll need to be provided with the underlying public inputs separately, to validate the hash).
| +| `bool payFeeFromL1`| Provides a way of paying for private L2 function execution from L1 (the RollupProcessor.sol could provide the interface for ETH or ERC20... but we could generalise this by somehow pointing to a particular 'other' payment L1 contract state?). "Submit on-chain the callHash and state a fee (in L1 currency) for the L2 tx, and then when the L2 tx is executed, the rollup provider may redeem the previously-published fee".

Notifies the kernel circuit that the following public inputs of this private circuit MUST be revealed to the public kernel circuit:
  • `callHash` - no other data is needed (in order to allow the user to keep the function they've actually executed private).
| +| `bool payFeeFromPublicL2`| Provides a way of paying for private L2 function execution from a public L2 circuit. This input being `true` will cause the rollup provider to look for an `isFeePayment` tx in the _public_ callStack. | +| `bool calledFromL1` | If the L1 contract wants to call a specific L2 circuit, then the function signature needs to be revealed on-chain so that it can be checked that the correct, intended function was executed.

Notifies the private kernel circuit that an L1 contract wants to call this specific private L2 circuit, and so the following MUST be revealed to the public kernel circuit:
  • `functionSignature` - needed so the L1 contract can confirm the intended function was executed on L2. Although a callHash contains the functionSignature, the L1 contract wouldn't (cheaply) be able to unpack the callHash. So we expose the function signature as well to keep costs down. Although this leaks the function which was called, there's no way around that; this is an L1 -> L2 call after all.
  • `callHash` - used as a 'lookup' key. The RollupProcessor will store this `callHash`, and await an L2 tx with this `callHash` before triggering a callback to the L1 contract which made this L1 -> L2 call in the first place.
  • `emittedPublicInputs` - needed so that a set of values can be emitted by an L2 function and exposed to L1. It would be too expensive to unpack the callHash and extract all of the custom public inputs of a circuit. This is much cheaper, and is very similar to how the EVM exposes only a few values (via event emissions) to JavaScript (for example).


We need this convoluted process, because the RollupProcessor has to be _sure_ an L1 fee has been set-aside for them, before they add any corresponding L2 states. | +| Global vars: | | +| `minTimestamp` | a timestamp value that must be exceeded when the block containing this txn is mined | + +Apart from the public input API, the structure of a private contract circuit is undefined by the Aztec 3 architecture. + +> In practice we will be using Noir to compile programs into circuits that conform to the above ABI. In theory we could, in the future, write Solidity or ewasm transpilers. + +:heavy_exclamation_mark: I think a circuit should only be able to make an L1 call to _its_ portal contract. The portal contract can then make calls to other L1 contracts, using its address as msg.sender. We don't want to circuits to be able to make calls from the RollupProcessor.sol, as it should never 'own state' in any Eth contracts on behalf of a specific aztec app. States should be siloed by app - that's the point of the portal contract. + + +> **Aside:** A loose argument against the need for public -> private calls: +>- Suppose we support public -> private calls. +>- A user will need to generate the private call's proof with some custom public inputs. This proof will be called by a public circuit, and so the private function being executed can't be hidden. +>- The public circuit calls the private circuit. +> - I.e. the public circuit will push a private call onto its private callStack (which includes the publicInputsHash of the public inputs that will be passed to the private circuit). +>- Clearly, the inputs that are passed to the private circuits must be known in advance (since the proof has already been generated), so cannot depend on any mutable public states. +>- In which case the private circuit could have come _first_ in the chain of calls, and so public -> private functionality isn't needed. +> +>Now... +>- If a public circuit wanted to pass dynamic inputs (inputs which depend on mutable public state) to a private circuit, that's not really possible (since the rollup provider would produce the public proof and then have to wait for the user to inject secrets into a private proof and generate it). +>- What _can_ be done is a defi-bridge-like chain of events: a private circuit generates a partial commitment, and then the public circuit completes that partial commitment with some public state and adds it to the privateDataTree. But that doesn't require explicit public -> private calls. + + +> **Aside:** we don't think we need chained transactions for Aztec 3. Recall: chained transactions give the ability to nullify a newly-created commitment _within_ the same rollup; before it's been added to the dataTree. This isn't needed. For a user to chain state to themselves, they can just create a callstack. The notion of chaining _between_ users is really complicated, and possibly not useful in practice. In particular, chaining doesn't play well with the idea of binary rollup trees, since the number of 'chaining' comparisons would blow up exponentially with the level of the rollup tree (meaning we'd need to build differently-sized rollup circuits per level). Recall: linked transactions give the ability to 'await' the inclusion of 'other' transactions in the rollup, before processing 'this' transaction. Unsure whether that's needed. + + + + + + +## Public Circuit ABI + +The public contract ABI is similar to the private one. + +Whilst the _user_ provides all the values specified by this Public Circuit ABI, it's the _rollup provider_ who actually generates public contract proofs. This is because the rollup provider is the only party with perfect knowledge of the current Merkle roots, meaning only they can access/update the public data tree, as well as know the exact block number etc. + + +| Data Type | Description | +| -------- | -------- | +| `customPublicInputs` | Up to 32 circuit-specific inputs passed into this circuit. All of these inputs will be 'swallowed' by the public kernel circuit. | +| `customOutputs` | Up to 32 variables 'returned' by calling this function. All of these inputs will be 'swallowed' by the public kernel circuit. Note, unlike the private circuit ABI (which doesn't have a `customOutputs` field like this), it's possible for public circuit execution to output values which were derived from the current state of the public data tree - such values cannot have been known by the caller of the function, and hence can truly be considered 'outputs'. Note, since the caller won't necessarily known what these outputs will be when they make the call, this entire `customOutputs` field is omitted from the `callStackItemHash` when the user makes the call. | +| `emittedPublicInputs` | Public inputs which may be revealed to L1. E.g. allowing certain inputs to be more-easily extracted by the RollupProcessor contract (rather than having to unpack this vast ABI object of inputs, which would cost too much hash-wise). An example of its usefulness is passing a value from L1 to L2 when doing an L1->L2 tx (see 'deposit' example in the other doc). | +| `emittedOutputs` | As above, except these values won't necessarily be known when the call is made; only when the rollup provider is generating the witness for this function's execution. Note, since the caller won't necessarily known what these outputs will be when they make the call, this entire `customOutputs` field is omitted from the `callStackItemHash` when the user makes the call. | +| `executedCallback: {` | Populated if this circuit is a callback, so that the purported L1 Result to which this circuit is responding can be validated against the l1ResultsTree. | +| `- l1ResultHash`, | If this function is a callback function, following some L1 call, then it needs to expose the `l1ResultHash` to ensure the callback is actually using data emitted by L1. The preimage of the `l1ResultHash` will need to be passed in as private inputs to the circuit. Note: the `l1ResultHash` MUST be computed with a sha256 hash, because that's what the RollupProcessor will have used. This is unfortunate, as it forces apps to adhere to a specific calculation within their circuits. | +| `- l1ResultsTreeLeafIndex`, | Communicates to the rollup provider the correct leaf to prove membership against in the l1ResultsTree. Only if we don't want to hide the callback will the rollup provider perform the membership check (within the Base Rollup Circuit). Otherwise it'll be performed in the Private Kernel Circuit. | +| `}`| +| 256 `stateTransitions` | Describes up to 256 `publicDataTree` read+write operations.
A 'state transition' is expressed as:
`[storageSlot, old_value, new_value]`.
:heavy_exclamation_mark: For state transitions, the caller might not know the `old_value` nor the `new_value` when they make the call (i.e. when they add the call to their callStack), since the value will depend on the current state of the publicDataTree. (Imagine if the storage slot represented total liquidity in some pool which changes frequently. Then the old and new values are only known at the time the rollup processor actually organises the ordering of txs in their block). Conclusion: the `publicInputsHash` which is included in a public call's `callStackItemHash` cannot include the `old_value` nor `new_value` inputs.

Therefore, the `stateTransitions` that are populated by a user and hashed when generating the `callStackItemHash` will have `0`-valued placeholders for `old_value` and `new_value`.

Pure reads can be emulated by setting a new write value to equal the read value. However, for this tree, we could halve the amount of hashing for pure reads by having a separate `reads` set of inputs. A read can be done without a write for this tree (see next field). | +| `stateReads` | Pure reads. Each 'read' request is simply the `[storageSlot, current_value]`. As explained above, the `current_value` won't necessarily be known by the user when they generate the call, so `current_value` is replaced with `0` when the `callStackItemHash` is generated for calls to a public function. | +| `publicCallStack` | additional public calls to be made by this transaction (up to 16) | +| `contractDeploymentCallStack` | additional calls which _deploy contracts_, created by this transaction (up to 1?) | +| `partialL1CallStack` | Additional L1 calls to be made by this transaction (up to 16). "Partial" because the kernel circuit will add the correct portal contract address to 'complete' the call into a proper L1 CallStack Item. See [here](../contracts/l1-calls.md). | +|
callbackStack = [{
  callbackPublicKey,
  successCallbackCallHash,
  failureCallbackCallHash,
  successResultArgMapAcc,
},...]
| An element in the array for each new L1 call on the `partialL1CallStack`. See [more](../contracts/l1-calls.md). We need to expose all of this data so that the kernel snark ensures the callback is a function of the same contract which made the call. | +| `oldPrivateDataTreeRoot` | used to query the `privateDataTree` | +| `proverAddress` | Who is going to be generating the proof for this circuit (any value can be injected here by the prover). :question: IS THIS ALLOWED HERE? It can be allowed here as long as Noir abstracts its existence away from the circuit developer. | +| Booleans: | | +| `bool isFeePayment` | Notifies the rollup provider that this function pays them their fee. The rollup provider will need a way to interpret the many ways it can be paid. :question: Perhaps a fee payment ABI is required for the structure of the `emittedPublicInputs`, for example? | +| `bool payFeeFromL1`| Provides a way of paying for L2 function execution from L1 (the RollupProcessor.sol could provide the interface for ETH or ERC20... but we could generalise this by somehow pointing to a particular 'other' payment L1 contract state?). "Submit on-chain the callHash and state a fee (in L1 currency) for the L2 tx, and then when the L2 tx is executed, the rollup provider may redeem the previously-published fee".

Notifies the kernel circuit that the following public inputs of this public circuit MUST also be revealed by the public kernel circuit:
  • `callHash`
| +| `bool calledFromL1` | If the L1 contract wants to call a specific L2 circuit, then the function signature needs to be revealed on-chain so that it can be checked that the correct, intended function was executed.

Notifies the public kernel circuit that an L1 contract wants to call this specific public L2 circuit, and so the following MUST be revealed by the public kernel circuit:
  • `functionSignature`
  • `callHash`
  • `emittedPublicInputs` (possibly)


We need this convoluted process, because the RollupProcessor has to be _sure_ an L1 fee has been set-aside for them, before they add any corresponding L2 states. | +| Global vars: | | +| `block.timestamp` | aztec block timestamp | +| `block.number` | aztec block number | +| `prevBlock.ethTimestamp` | Ethereum timestamp of block that contained previous Aztec 3 block | +| `prevBlock.ethNumber` | block number of Ethereum block that contained previous Aztec 3 block | + +### publicInputsHash + +As explained briefly in the table above, for calls to a public circuit, certain inputs are _not_ known when the user makes the call (since their values might depend on the state of the public data tree at the time of proof generation (rather than at the time of making the call)). Therefore, the `publicInputsHash` for public calls is defined as the hash of the above ABI data, _except_ for the following modifications to the preimage: +- `customOutputs` fields are completely omitted from the preimage. +- `emittedOutputs` fields are completely omitted from the preimage. +- Each state transition is truncated to be `storageSlot` (instead of `[storageSlot, old_value, new_value]`). +- Each state read is truncated to be `storageSlot` (instead of `[storageSlot, current_value]`). + + + + + + + + + +## Contract Deployment ABI + +Recall: + +Contracts can be deployed to Aztec's Layer 2. A contract comprises: +- a set of functions, each encapsulated by a `(vk, proving_key, circuit)` tuple, with the hash of the `vk` being a succinct and unique representation of each function. +- state variables, split across these trees: + - `publicDataTree` + - `privateDataTree` + +A contract deployment ABI, therefore, needs to communicate this information to the rollup provider. + +This is the ABI for the public inputs that must be specified when making a call to deploy a new contract. These public inputs will then be hashed into a `publicInputsHash` which will form part of the [`callStackItemHash`](../contracts/transactions.md#callstackitemhash) which will get added to the `contractDeploymentCallStack`. + +**Important note**: Unlike for the above Public Input ABIs for private circuits and public circuits, we don't actually have a 'contract deployment' _circuit_. These public inputs are simply defined so that a callStackItem can be created. These public inputs (and others) are then fed directly into a [Contract Deployment _Kernel_ Circuit](../kernel-circuits/contract-deployment-kernel.md). + + +TODO: we might be able to remove some of these public inputs and provide them privately instead; but such optimisations can happen _much_ later in this project. + +| Data Type | Description | +| -------- | -------- | +| `privateConstructorPublicInputsHash` | So that vested parties (with access to the underlying public inputs) can confirm the constructor was executed with the correct params. Note: a user (or contract) cannot provide a conventional callStackItem to make a call to a private constructor, because the constructor's function signature isn't known until the contract address is known, but the contract address needs to contain the constructor arguments (i.e. the privateConstructorPublicInputsHash), so we'd get a cyclic dependency. | +| `publicConstructorPublicInputsHash` | As above, but public. | +| `privateConstructorVKHash` | The hash of the vk that was used to verify the private constructor, so that vested parties can confirm the correct function was run as a constructor (the vk itself may OPTIONALLY be submitted on-chain as calldata (for data availability), but some users might want to keep that private).
(Note, we can't use function signatures here, because the contract hasn't yet been deployed, so no contract address exists!) | +| `publicConstructorVKHash` | As above, but public. | +| `contractAddress` | The proposed contract address that this new contract will be deployed to. | +| `salt` | The salt used in the preimage of the contractAddress derivation - to have some control over the contract address | +| `vkRoot` | The root of the mini merkle tree of VKs. Note: the underlying data (the circuit's compressed ACIR representation) can optionally be submitted on-chain as calldata (for data availability), but some users might want to keep that info private, or might not want to pay for that. | +| `circuitDataKeccakHash` | For example, a hash of the circuit's compressed ACIR representation. This value will be read on-chain by the RollupProcessor.sol. If it's `0`, it's assumed the user didn't want data to be submitted (to keep their contract logic private). If it's nonzero, the rollup provider MUST submit the hash's preimage as calldata. To ensure the rollup provider does actually submit, the RollupProcessor.sol will try to reconcile the hash, and reject if it doesn't reconcile. Note, there's no explicit checks that can be done (within a snark or on-chain, due to expense) to ensure this `circuitDataKeccakHash` actually corresponds to the `vkRoot`. Clients (off-chain) must decompress the submitted circuit data, recreate the verification keys, then recreate the `vkRoot`, to be convinced the deployed contract actually represents the logic they expect. If circuit data isn't submitted here (to keep the logic of the contract private), then the developer must find another way (off-chain) to circulate the ACIR representations of the circuits to their users. | +| `portalContractAddress` | Gets calculated within the circuit and stored in the `contractTree` (within the same leaf as the contract's vkTree). We expose it here, because the RollupProcessor will need redo this calculation to ensure it's been done correctly. | + + + + + + + ## Custom inputs ABI + +Circuits have up to 32 custom 'inputs' (and 'outputs' for public circuits). Each Noir data type that is set to be a public input is represented by a single field element (we don't need to do this for private inputs). If the data type is >1 field element, the data is Pedersen hashed. We apply this heuristic recursively for structs and nested data. e.g. for + +``` +struct foo { + field a; + bytes b[256]; +}; +``` + +`b = pedersen(b.values), foo = pedersen(b, a)` + +:question: Can we instead go for `foo = pedersen(a, b)`? Hmmm, actually, maybe it is easier to mirror the Solidity ABI, to avoid mistakes? + +The full, uncompressed values will be attached to the transaction as 'auxiliary data', used by the proof creator to unpack the hashed values. This data will be swallowed before the transaction gets mined into a block. Literally nothing is broadcast on-chain except for non-validium state changes. \ No newline at end of file diff --git a/circuits/specs/src/architecture/contracts/contracts.md b/circuits/specs/src/architecture/contracts/contracts.md new file mode 100644 index 00000000000..56f18859669 --- /dev/null +++ b/circuits/specs/src/architecture/contracts/contracts.md @@ -0,0 +1,21 @@ +# Contracts + +## An overview + +Much of the functionality of Aztec 3's contracts are inspired by Ethereum contracts; it's just we'll be adding privacy to the mix. + +A contract is simply a collection of [functions](./function-types.md) and [state variables](./states-and-storage.md). A function can only make edits to its own contract's state variables. For a function to edit _another_ contract's state, that function must make a call to a function of the other contract. Inter-contract calls are essential for many applications (e.g. An exchange triggering `transferFrom` calls on two token contracts). + +A '[transaction](./transactions.md)' is an execution flow, triggered when a user calls a function with a set of inputs. The initially-called function might make calls to other functions, which themselves might make calls to other functions. + +In the 'conventional' world of Ethereum, a transaction is completed when the originally-called function eventually completes (having possibly called several other functions along the way). Indeed, conventional programs execute in the order dictated by their code: if a line makes a call to another function, the program will 'jump into' that function and start executing its code, and so-on in a big nesting of calls, until eventually the inner-most call completes and returns some variables. Then program starts unwinding back up the nesting to the originally-called function. That's perhaps not the best mental model for Aztec programs ('transactions')... + +As you might have guessed, 'functions' in Aztec's L2 will actually be circuits. Execution of a function will be performed by generating a zk-snark to prove its correct execution with a particular set of inputs. If a function makes a call to another function, a proof of each function's execution must be made _separately_. We need to then 'connect' those two proofs in a way which says "this function made a call to this other function, it passed-in these arguments and received these values in return". To do this, we make use of zk-snark recursion and a special 'callstack'. Notice that if each function must be executed as a standalone lego brick (a proof), then all input arguments and return values of every function call in a transaction must be known ahead of time, so that each proof can be generated separately. That'll be a fun engineering challenge! + +This is all expanded-on later in this book. When a function calls another function, we'll add details of the function _being called_ to a callstack[^1]: the contract address, the function signature, arguments, return values and a call context. We describe a 'Kernel Snark' which: pops the first proof off the callstack, verifies it, then adds new callstack items for any functions which the first function called. Kernel Snark execution proceeds recursively: the next Kernel Snark will verify the previous Kernel Snark's correctness, then will pop the next proof off the callstack, and add even more callstack items for any functions which this latest function has called. The 'stitching together' of arguments passed to functions and values returned from functions is implicit in this process, since each callstack item contains this information. + +This protocol describes 'private states' (a state whose value is known by a single user) and 'public states' (states whose values are visible to everyone). To edit these different states, we need two different kinds of circuits: private circuits and public circuits. + +> Whenever we refer to 'contract' in this document, we'll be referring to an Aztec 3 L2 contract (which may comprise both public and private functions). If we're talking about an Ethereum contract, we'll explicitly say something like 'Ethereum contract' or 'L1 contracct' or 'Portal contract'. + +[^1]: More 'conventional' callstacks will push a 'return address' to the callstack, so that when the program finishes executing a called function, it knows where to return to, to continue execution of the _calling_ function. In our protocol, we push details of the next function to be called, instead. diff --git a/circuits/specs/src/architecture/contracts/deployment.md b/circuits/specs/src/architecture/contracts/deployment.md new file mode 100644 index 00000000000..342112c52fb --- /dev/null +++ b/circuits/specs/src/architecture/contracts/deployment.md @@ -0,0 +1,115 @@ +# Contract Deployment + +A contract is a collection of functions and state variables. Each 'function' is expressed as a circuit, and each circuit can be represented by its verification key. I.e. each verification key represents a callable function in the smart contract. + +The set of functions of a contract is represented as a mini Merkle tree of verification keys - a `vkTree` - with the root node - `vkRoot` - being a leaf in the `contractTree`. + + +**Deployment topics:** +- Constructor functions (to populate initial state variables). +- Specifying an L2 contract address +- Distributing L2 contract data +- Linking to an L1 Portal Contract + +These topics are reflected in the layout of the [Contract Deployment ABI](../../architecture/app-circuits/public-input-abis.md#contract-deployment-abi): +```js +publicInputs = { + // Constructor functions + privateConstructorPublicInputsHash, + publicConstructorPublicInputsHash, + privateConstructorVKHash, + publicConstructorVKHash, + + // L2 contract address (create2-like) + contractAddress, + vkRoot, + + // Distributing L2 contract data + circuitDataKeccakHash, + + // Linking to an L1 Portal Contract + portalContractAddress, +} +``` + +Note: the distribution of L2 data on-chain is optional and can be done by submitting a compression of the ACIR representation of a circuit as calldata. + +## Constructor functions + +Constructor functions can be called when deploying a contract, to populate the contract with some initial state variables. A private constructor can be called to populate private states, and a public constructor can be called to populate pulic sates. TODO: we might be able to get away with a single constructor. + +The [contract deployment kernel circuit](../../architecture/kernel-circuits/contract-deployment-kernel.md) verifies the constructors' executions. + +### Private constructor +A private constructor is only needed if we'd like private states to exist at the beginning of our contract's life. Since private states must be private _to_ a person (i.e. _owned_ by a person), such states would only be created at deployment if we want the _deployer_ to own something privately. + +An example might be if someone was creating a completely private cryptocurrency directly on aztec's L2, and they minted the total supply at once for themselves (to distribute themselves). Then initially, the deployer of the contract might be in control of a single 'value note' representing the entire initial supply. They could then distribute value notes thereafter by running a private circuit for 'transferring value' multiple times. +As an extension of this example, the deployer might wish bake-into the private constructor the token distribution logic. Then with the private constructor, they could distribute value immediately and privately to a group of people by creating up-to 64 commitments (actual value TBD). + +### Public constructor + +Adds initial public state variables to the public data tree. + + + +## L2 Contract Address + +The contract address is calculated by the contract deployer, deterministically, as: + +- `contractAddress = hash(deployerAddress, salt, vkRoot, constructorHash)` + +> The EVM's CREATE2 does `contractAddress = hash(0xff, deployerAddress, salt, keccak(bytecode))` - we've taken this as inspiration. + +- `deployerAddress` is included to prevent frontrunning of deployment requests, but it does reveal who is deploying the contract. To remain anonymous a user would have to use a burner address, or deploy a contract _through_ a private contract which can deploy contracts. :question: Why does CREATE2 include a deployerAddress? +- `salt` gives the deployer some 'choice' over the eventual contract address; they can loop through salts until they find an address they like. +- `vkRoot` is like the bytecode without constructors or constructor arguments. This allows people to validate the functions of the contract. +- `constructorHash = hash(privateConstructorPublicInputsHash, publicConstructorPublicInputsHash, privateConstructorVKHash, publicConstructorVKHash)` - this allows people to validate the initial states of the contract. (Note: this is similar to how the `bytecode` in create2 includes an encoding of the constructor arguments). + +To prevent duplicate contract addresses existing, a 'nullifier' is submitted when each new contract is deployed. `newContractAddressNullifier = hash(newContractAddress)`. See [here](../kernel-circuits/contract-deployment-kernel.md#execution-logic). + +In order to link a `contractAddress`, with with a leafIndex in the `contractTree`, we reserve the storageSlot `0` of each contract's public data tree storage to store that leafIndex. + +The `contractAddress` is stored within the contract's leaf of the `contractTree`, so that the private kernel circuit may validate contract address <-> vk relationships. + +> Aside: It would have been neat for a contract's address to be the leaf index of its mini Merkle tree (i.e. the root of the `vkTree`) in the`contractTree`. However, the leaf index is only known at the time the rollup provider runs the 'contract deployment kernel snark', whereas we need the contract address to be known earlier, at the time the deployer generates the private constructor proof. Without a contract address, the private constructor would not be able to: call other functions (and pass them a valid callContext); or [silo](./states-and-storage.md#preventing-private-state-collisions) newly created commitments. + +## L1 Portal Contract + +> (Referring to it as an "L1 Portal" Contract is pleonastic - a portal contract can _only_ be deployed to L1 by its definition, so saying "Portal Contract" is fine). + +Each L2 contract will have its own Portal Contract deployed to L1, so that the contract may make [calls to L1](./l1-calls.md). See also the [example](../../examples/erc20/deployment.md#motivation), which gives more reasoning for the need for a Portal Contract. + +### Deployment of Portal Contract + +There are 3 options for linking an L2 contract with a portal contract, all with pros & cons. TODO: decide which is best. + +1. Deploy the L1 portal contract at the same time as deploying an L2 contract (by providing the L1 portal contract’s bytecode and CREATE2 parameters as public inputs to the Contract Deployment ABI, so that the RollupProcessor can deploy the portal contract). +2. Deploy the L1 portal contract first, tell the Rollup Processor the address, then deploy this L2 contract (providing the L1 address of the portal contract). +3. Deploy this L2 contract, note the deployer’s L1 user address, and allow that same person to later deploy an L1 portal contract and link it with this L2 contract. + +Option 1 initially sounds nice and clean, but L1 contract deployment is _expensive_, so just a few portal contract deployments would use all the gas in an L1 block; not leaving enough room for logic to verify the L2 rollup etc. But the most difficult thing about this option would be we'd have to _await_ the success of the Portal Contract deployment attempt on L1 before allowing the L2 contract to be 'finalised', which would need callbacks and painful logic that we'd rather avoid (for contract deployment, at least) if we can. + +Option 2 is a nice option, although it doesn't allow for deployment of the Portal Contract to be paid-for from the privacy of aztec's L2 - a user would need public Eth to deploy it. + +Option 3 is possible. The L1 portal contract's address would need to be known in advance, in order to deploy the L2 contract (because the portal contract address is embedded within the leaf of the contract tree). Then we'd need to figure out how to deploy and link the L1 contract. + + + +To prevent two contracts from pointing to the same Portal Contract, a 'nullifier' is submitted when each new contract is deployed, as a way of 'reserving' that Portal Contract's address. `newPortalContractAddressNullifier = hash(newPortalContractAddress)`. See [here](../kernel-circuits/contract-deployment-kernel.md#execution-logic). + +The `portalContractAddress` is stored within the contract's leaf of the `contractTree`, so that both the private & public kernel circuits may validate portal contract address <-> vk relationships. + + + + +## Distributing L2 contract data + +A contract developer might not want to distribute the logic of their contract (e.g. the terms of any business agreement in the real world are always confidential). Therefore, distribution of data on-chain is _not_ enforced. On-chain distribution ensures permanent data availability of the contract's code, so that it can always be executed. But other means of distibution might also be acceptable to users. A developer can optionally submit a representation of their circuits on-chain as calldata for others to validate. A compression of the circuit's ACIR representation might be the most succinct representation of a circuit. + +The reason we'd want to distribute a representation of the circuit's logic (rather than just verification keys or something) is because from the circuit logic, everyone can generate the VKs and proving keys of the circuit. The VKs can be used to validate the correctness of the submitted `vkRoot`. Any deployments which fail such validation can be rejected (not used) by users. + +## See also... + +- _Lots_ more detail is given in the [ERC20 walkthrough](../../examples/erc20/deployment.md). +- [Contract Deployment Public Inputs ABI](../app-circuits/public-input-abis.md#contract-deployment-abi). +- [Contract Deployment Kernel Circuit](../kernel-circuits/contract-deployment-kernel.md). \ No newline at end of file diff --git a/circuits/specs/src/architecture/contracts/function-types.md b/circuits/specs/src/architecture/contracts/function-types.md new file mode 100644 index 00000000000..17c92180ec3 --- /dev/null +++ b/circuits/specs/src/architecture/contracts/function-types.md @@ -0,0 +1,71 @@ +# Function Types + +There are 3 types of function in Aztec 3: +- Private (L2) +- Public (L2) +- L1 + +The need for private functions you'll be familiar with: a user needs to be able to manage states which are secrets, known only to themselves. + +L1 functions are simply functions in regular Ethereum smart contracts. L1 functions are public by definition; all state changes are visible. + +Public functions on _L2_ are also supported, and are important to save users significant costs. L1 public state changes and logic execution are _very_ expensive - prohibitively so for many users. L2 public state changes will likely spur better adoption of Aztec 3. Also, it'll make it possible for entire apps to 'live' completely on Aztec 2 without any L1 interactions. + +## Private Function + +Private functions have a few distinguishing characteristics: +- Only private functions may _edit_ private states. + - I.e. only private functions can produce nullifiers. +- Private functions insert _secret_ data into commitments which are then added into the `privateDataTree`. Note: public functions can also add commitments to the `privateDataTree`, but that'll be in the context of _completing_ partial commitments whose secrets were previously injected by a _private_ function. +- The execution of a particular private function may be _hidden_, so that no observers can tell which function has been executed; only that "the rules of some function have been correctly followed". + - :warning: This second characteristic is optional. If a private function calls a public function (on L2 or L1), then this will leak information about which private function has been executed. Further, if a private function is _called by_ an L1 function, this will completely reveal the function that's been executed. + +For a private function which doesn't 'interact' with the 'public world', then the msg.sender's identity, any state changes, the function itself, and the L2 contract address of the function are all hidden. Private state changes use an encrypted UTXO state model. Private circuit proofs are generated by msg.sender's client, and are hidden by the client by verifying the proof inside a private kernel circuit (thereby hiding which verification key in the contractTree has been used). + +_Note_: input and output values will also be hidden, unless calling a public or L1 function, in which case any arguments passed to the public or L1 function will need to be public. The number of such arguments and the values of such arguments might leak information about the nature of the private function being executed. This must be clear to developers who write private functions. +_Note_: The function and contract address are hidden _up-to_ the number of commitments and nullifiers (so observers might be able to 'guess' the function being called from this info). This can be mitigated by adding an extra call at the end of the private callstack (see later) which calls a special 'padding' function which adds extra commitments/nullifiers to the kernel snark's `end` arrays. + +## Public Function + +As mentioned, in addition to private transactions and calls to L1 contracts, it will be valuable to add support for general-purpose 'public' functions, that are not privacy preserving. These will be necessary to implement (affordable) public-facing components of privacy-preserving systems (e.g. automated market makers, DAOs, components of Aztec Connect). + +The msg.sender, any state changes, the function itself, and the contract address of the function will be public. Public state changes use an account-based state model via an updateable Merkle tree. + +Importantly, if an app needs logic which reads from or make edits to the _public_ state tree, then that logic will need to be in a public circuit. Only a public circuit can 'touch' the public data tree, since the 'current state' of the public data tree is only known by the rollup provider who orders transactions in the rollup. + +Public functions can be triggered from private functions. + +## L1 Function + +An external call to an Ethereum L1 smart contract that uses the Aztec-Connect-like interface. (we'll provisionally call such contracts Portal Contracts, because they link the L1 and L2 worlds). + +> Don't confuse the `public`, `private` or `external` wording with the Solidity keywords; they're different concepts! + +> Also don't confuse the `public` and `private` wording with class access specifiers in C++ and other languages; they're _very_ different concepts! + + +## Examples + +For those familiar with Aztec Connect, we can categorise those functions into the Aztec 3 framework. + +> See the related [examples](./states-and-storage.md#examples) in the 'states & storage' section for Aztec3-categorisation of Aztec2's various notes. + +> See also the detailed walkthrough example of deploying an ERC20 shielding protocol (effectively zk-money) to Aztec 3 [here](../../examples/erc20/erc20-shielding.md). + +**Join-split circuit: deposit mode** +This is a **private** circuit, BUT it needs to share the `amount` deposited with L1, and so the function executed (a 'deposit') will NOT be hidden. + +**Join-split circuit: transfer mode** +This is a **private** circuit. Even the function executed will be hidden by the private kernel snark. + +**Join-split circuit: withdraw mode** +This is a **private** circuit, BUT it needs to share the `amount` withdrawn and the withdrawal address with L1, and so the function executed (a 'withdrawal') will NOT be hidden. + +**Join-split circuit: defi-deposit mode** +This is a **private** circuit, since it nullifies value notes, BUT it needs to share information about the deposit and intended bridge contract with the rollup provider, and so the function executed (a 'defi deposit') will NOT be hidden. + +**Claim circuit** +This is a **public** circuit. No private states are nullified. Its logic is executed by the rollup provider (and so must be public logic). It _does_ add output commitments to the `privateDataTree`, but the secrets which form part of those commitments were injected by the defi deposit circuit; the claim circuit simply 'completes' the commitments with public data. + +**Account circuit** +This can probably be a **public** circuit. I won't explore it deeply, because Aztec 3 will use Ethereum ECDSA signatures, so account notes won't be used. \ No newline at end of file diff --git a/circuits/specs/src/architecture/contracts/l1-calls.md b/circuits/specs/src/architecture/contracts/l1-calls.md new file mode 100644 index 00000000000..2f4ef93e164 --- /dev/null +++ b/circuits/specs/src/architecture/contracts/l1-calls.md @@ -0,0 +1,217 @@ +# L1 --> L2 / L2 --> L1 calls + + +Although the dedicated pages on each circuit contain ABIs & logic relating to interactions with L1, it's a pretty complicated subject, so this is a page which focuses on L1 interaction logic alone. + + +## L1 --> L2 calls + +See the [deposit](../../examples/erc20/deposit.md) example for more details. + + +## L2 --> L1 calls + + +Calling L1 is tricky. Aztec Connect did a lot of the thinking, and here we're just trying to generalise those ideas beyond the single 'defi interaction' interface. + +Firstly, in order for a contract (or user) to make a call to an L1 function, they need an L1 address. That's one of the main purposes of the Portal Contract; to provide an Aztec L2 contract with an L1 contract address through which it can make calls to other L1 functions. So an L2 contract MUST make L1 calls _through_ its Portal Contract. I.e. _all_ calls from an L2 contract will be _to_ that contract's Portal Contract. It's then up to the logic of the Portal Contract to forward calls to other L1 contracts' functions. + +Now, an L2 circuit might both make state changes _and_ make calls to L1. The L2 circuit's execution MUST NOT be considered 'final', until the L1 calls have been mined, as only then can we know if the L1 calls were successful/unsuccessful. That means any state changes which the L2 circuit is proposing to make (to either the `privateDataTree` or the `publicDataTree`) MUST NOT be included (as final states) in the trees until the L1 execution completes. Furthermore, the L2 circuit might also be 'awaiting' some values or on-chain state updates from the L1 call(s) before being able to insert new L2 states into the trees. + +> An example is Aztec Connect's defi interactions. You can think of the 'defi deposit' circuit as calling a bridge on L1. We _want_ to create states containing the user's share of funds _returned_ by the L1 bridge. But the defi deposit circuit cannot make such state updates. So it instead creates a partial commitment (which in Aztec 3 we can add to a state variable in the public data tree). It's only after the L1 tx is completed that we know the value to inject into that partial (or 'pending') state. The claim circuit then injects the value and adds the _finalised_ state to the privateDataTree. See more on this example [here](./function-types.md#examples). + +As a generalisation for Aztec 3, we we can think of the claim circuit as a 'callback function', which is executed after the result of the L1 tx is known. + +We outline a general protocol below. Here are the main differences from Aztec Connect: +- For each L1 call, two 'callback functions' are submitted; one to be executed upon success, and one upon failure of the L1 tx. +- Whereas 'defi deposits' are summed in the rollup circuit in Aztec Connect, that cannot happen in Aztec 3, because app specific logic must not live in a rollup circuit. Instead, such app-specific logic would need to be in a public circuit. See the dedicated example [TODO: EXAMPLE] for more details. +- In Aztec Connect, the rollup circuit expects a defi interaction note to have a specific format (that of a defi interaction). In Aztec 3, the rollup circuit has no knowledge of the number of values contained in an L1 result; it deals with already-compressed (hashed) leaves which contain callback and result data. +- In Aztec Connect, there's no callback in case a withdrawal's L1 call fails. If it fails, a user has spent money on L2, but hasn't received money on L1 (they've lost money effectively). In Aztec 3, we could specify a failure callback which could reinstate the user's L2 balance (for example). + + + +### Protocol for L2 --> L1 calls. + + +#### Overview + +- L2 function makes call to L1 +- Two callback hashes (see below) get encoded into a single leaf of the `l1ResultsTree` - one for success and one for failure. + - A callback hash contains a: + - function selector + - a set of `emittedPublicInputs` that must be emitted by the callback. + - Leaves without data relating to the success/failure of the L1 call are considered "pending". +- The RollupProcessor.sol makes an L1 call for every callstack item on the `l1Callstack`. +- The return data of each L1 call is sha256-hashed into an `l1ResultHash` (singular). + - If the L1 call failed, this is also encoded in the `l1ResultHash`. +- Those hashes are all sha256-hashed together into a single `l1ResultsHash` (plural), to save on storage costs. The RollupProcessor.sol stores this for reference, so it may do a comparison against the next rollup. +- In the very next rollup, the rollup provider is _forced_ to execute an "L1 Results Copier Circuit" which copies all L1 results of the previous rollup over to L2, so that L2 circuits may access the results more easily. + - The circuit "finalises" each "pending" leaf of the `l1ResultsTree` by adding the `l1ResultHash` to the leaf. The leaf will be structured in such a way that a success result will be stored against the success callback. + - The RollupProcessor.sol will check the "L1 Results Copier Circuit" was executed correctly, by checking: + - The `l1ResultsHash` matches that which was stored. + - The leaf indices of the `l1ResultsTree` which were updated, were the correct leaves to update. +- A user can then call the relevant L2 callback function of a particular 'completed' L1 call. + - Public/Private circuit ABIs contain an `isCallback` indicator, to enable the kernel/rollup circuits to perform extra checks on the validity of this callback, relative to the data in the `l1ResultsTree`. + - The callback circuit will expose: + - its `emittedPublicInputs` + - The `l1ResultHash` of the L1 call to which this callback is responding. Note, there's no enforcement of _how_ this app-specific circuit makes use of this `l1ResultsHash` or the `emittedPublicInputs`. +- The kernel snark which processes the callback circuit will: + - Recalculate this callback's `callbackHash`. + - 'Complete' it with the callback's exposed `l1ResultsHash`. + - Check this 'finalised' callback leaf exists in the `l1ResultsTree`. + - Expose the root of the old `l1ResultsTree` that was used in the membership check. + - Calculate and expose a `callbackNullifier`, to prevent this L1 interaction's callback from being called again. + + +#### More details + +When an L2 circuit makes a call to L1, it exposes the following data to the kernel circuit (amongst other things): +- [`l1CallStackItem`](./transactions.md#l1-callstack-items) +- [`callbackStackItem`](#callbackstackitem) + +##### `callback` + +A call to a callback looks like any other call, except certain public inputs are omitted from the callStackItem's calculation (and hence also the callbackCallHash's calculation), since stuff like the L1 Result aren't known at the time the callback is added to the L1 Results Tree. + + +> Note: we must enforce (in the kernel circuits) that a callback can only be made to a function of the _same_ contract which made the L1 call in the first place. This is to prevent malicious callbacks which are able to add state to any contract's storage space. (At least, I think this restriction is required...?). + + +##### `callbackCallHash` + +A special type of `callHash`, which omits values which aren't known at the time the callback is added to the L1 Results Tree. + + +##### `callbackStackItem` + +```js +callbackStackItem = { + callbackPublicKey, + successCallbackCallHash, + failureCallbackCallHash, + successResultArgMapAcc, +} +``` +Where: +- `callbackPublicKey` allows a callback to be nullified in a private circuit (by the owner of the `callbackPrivateKey`), so that it isn't revealed _which_ callback has been executed. The `callbackPrivateKey` must be provided to the private kernel circuit in such cases, for the callback's execution to be permitted. +- `successCallbackCallHash` - details of the callback that must be called if the L1 call is successful. +- `failureCallbackCallHash` - details of the callback that must be called if the L1 call fails. +- `successResultArgMapAcc` - a basic accumulator value which details how elements of the L1 Result's array should be mapped to positions of the success callback's arguments. This ensures the L1 Result is fed into the callback's arguments correctly. (See more below). + +##### `callbackStackItemHash` + +```js +callbackStackItemHash = hash(callbackStackItem) +``` + + + +##### L1 Results Tree + +The 'Base Rollup Circuit' will need to add details of the L1 call's callbacks to the `l1ResultsTree`. Notice, we add callback data to the results tree _before_ the L1 results are known. Once an L1 result is known, the same leaf of the tree will be updated with the result. + + +A leaf's value is a hash of data of the form: + +`{ isFinalised, l1ResultHash, callbackStackItemHash }` + +- Before the L1 result is known: + - `leafValue = callbackStackItemHash` +- After the L1 result is known: + - `leafValue = hash(l1ResultHash || 0, callbackStackItemHash)` + +> Note: these hashes might need different Pedersen generators to avoid collisions. + +> Note: if the L1 call failed or ran out of gas, then `l1ResultHash = 0` will be returned by the RollupProcessor contract. + + +``` +Example showing 3 stages of leaves of the l1ResultsTree. + + + / \ / \ / + / \ / \ / \ / \ / \ +leafIndex 0 1 2 3 4 5 6 7 8 9 ... +callbackPublicKey - 0x.. - - - 0x.. - - - - +successCallbackHash 0x.. 0x.. 0x.. 0x.. 0x.. 0x.. 0x.. - - - +failureCallbackHash 0x.. 0x.. 0x.. 0x.. 0x.. 0x.. 0x.. - - - +successResultArgMap 0x.. 0x.. 0x.. 0x.. 0x.. 0x.. 0x.. - - - +successResultHash 0x.. 0x.. - - - - - - - - +isFinalised 1 1 1 0 0 0 0 - - - +^ ________________ ______________________ ______________ +Data in each leaf Completed L1 L1 calls which haven't Empty leaves. +is hashed. results. been updated with + a result yet. +``` + +Notes: +- Notice: there's no failure result hash, because 'failure' includes the possibility that the L1 call ran out of gas or failed in such a way that the RollupProcessor.sol wasn't able to hash anything. + - This is why we allow `customPublicInputs` to be exposed by the callback function when it's executed. Such data can then be used to revert state changes on L2 if no result was provided by L1. + + + +The RollupProcessor.sol will keep track of (for the `l1ResultsTree`): +- `firstEmptyLeafIndex` +- `firstPendingCallbackLeafIndex` - the left-most leafIndex whose entry is pending (i.e. which hasn't been finalised with an L1 result yet). +- These will be used to ensure the rollup provider is updating the tree in the correct places, within the circuits. + + + + +##### `successResultArgMapAcc` + +Eventually, we'd like to call L1 functions and await a promise (which will eventually resolve to the L1 result). The syntax might look something like the below, where we intentially use the result in a tricky way: + +```js +uint x; + +L1Promise promise = await L1_Portal_Contract.my_l1_function(amount_a); + +promise.then( + result => fn1(result[1], x, result[0], result[2]), // on success, the result will + // effectively be an array of + // values. + fn2(x), // results cannot be passed to the failure + // callback. +); + +function fn1(uint a, uint b, uint c, uint d) { + // do stuff +} + +function fn2(uint a) { + // do stuff +} +``` + +Notice how, upon success of the `promise`, the `result` array (in this example) is passed to `fn1` in a funny order. This is what the `successResultArgMapAcc` is for (until we find a better method). For now, we can create a simple 'accumulator' (although it's not a one-way function) using prime numbers. Later, we can do something cleverer (although anything more than 10 L1 Results and plookup might not be an option, since 11! = 40 million mapping combos). With this 'simple' approach, we can allow up to 10 result values to be returned (since `max := 29^10 * 23^9 * 19^8 * 17^7 * 13^6 * 11^5 * 7^4 * 5^3 * 3^2 * 2^1` doesn't overflow (it's 214-bits), but `31^11 * max` is 269-bits. Actually, initially let's allow 8 L1 Results + +``` +result index: 0, 1, 2, 3, 4, 5, 6, 7, +... maps to arg position: 3, 1, 4, -, -, -, -, -, (indexed from 1) +prime for this arg position: 2, 3, 5, 7, 11, 13, 17, 19, + + +successResultArgMapAcc = 2^3 * 3^1 * 5^4 = 15000 // we can do powers, since the power is + // always bounded by 8. It's messy + // though. +``` + +When the callback is eventually executed, it'll expose its `customPublicInputs`, the `successResultArgMapAcc`, and the `l1ResultHash` to the kernel circuit. In this 'simple' solution, we can also pass binary decompositions of the arg positions (`l1SuccessResultArgPositions`) and the underlying values of the `l1ResultHash` (`l1ResultValues`) as private inputs to the kernel circuit. Using these, we can ensure the results were mapped to the correct argument positions of the callback circuit. + +## Alternative approach to callbacks + +The approach to callbacks described in this book (at the moment) is that a callback can only be executed once, and then it's 'nullified' from the L1 Results Tree by the kernel circuit (or rollup circuit). That means an L1 result can only be 'referred-to' once, by a single callback. This differs from Aztec Connect's claim circuit functionality, where the L1 Result (the defi interaction note) can be referred-to many times by the claim circuit; it's up to the claim circuit to ensure it has logic to allow multiple 'nullifications' of the L1 result. We _could_ adopt a similar approach; leaving handling of nullification of an L1 Result to the callback circuit (rather than nullifying in the kernel), but that would require much more care from users to ensure the nullifier is well defined. + +**Pros** (of the approach currently described in this book): +- The kernel snarks handle all callback handling logic and L1 Result nullification logic, so it's simpler for users (devs). + - A 'nullifier' of an L1 Result can always be understood to be a 'one time use' thing. + - In the 'alternative approach', 'nullification' logic (of L1 Results) is up to the developer. +- The L1 Result callbacks are structured similarly to other languages, e.g. in Rust, a Result has an 'OK' and an 'Err' callback, and the callback can only be called once. + +**Cons** +- To achieve defi-bridge logic with this book's approach, there needs to be an extra step: + - The L1 Result callback would need to copy the L1 Result (the 'total amounts' from the defi interaction) into the public data tree. + - Then individual 'claim circuits' could be executed - they'd lookup the 'total amounts' from the public data tree (not from the L1 Result tree, since an L1 result can only be referred-to once, before it gets nullified). +- The 'alternative approach' is perhaps more flexible if a dev knows what they're doing. +- The 'alternative approach' might make kernel and rollup snarks slightly cleaner. \ No newline at end of file diff --git a/circuits/specs/src/architecture/contracts/states-and-storage.md b/circuits/specs/src/architecture/contracts/states-and-storage.md new file mode 100644 index 00000000000..2c7e4126d25 --- /dev/null +++ b/circuits/specs/src/architecture/contracts/states-and-storage.md @@ -0,0 +1,114 @@ +# States & Storage + +# States + +There are 3 kinds of state to be aware of in Aztec 3, and these reflect the [function types](./function-types.md) of Aztec 3: + +- Private States (L2) +- Public States (L2) +- L1 states (public by definition) + + +## Private States + +Private states are state variables which are private to a single user (or a group of users if we do multisig stuff). Each state is represented by a commitment (or a set of UTXO commitments) in the `privateDataTree`. A state can be edited by producing and submitting a nullifier for one (or multiple) commitments to the nullifier tree. + +### Commitment preimage layout + +This is just a suggestion for a general commitment preimage layout. + +Note: app developers will technically have 'free reign' over the preimage layouts of their commitments (and similarly of their nullifiers). In practice, though, if they use Noir to produce their Aztec 3 circuits, the layouts will likely follow a prescribed format. + +Suggestion: + +A private state with key:value pair `storageSlot:value` could have layout: + +`commitment = h(storageSlot, value, owner, creator, salt, inputNullifier)` + +where: +- `storageSlot` - a unique slot for this particular private state, determined (most likely) by Noir. Assignment could be similar to the [storage slots in Solidity](https://docs.soliditylang.org/en/v0.8.9/internals/layout_in_storage.html), which are assigned based on the order variables are declared (with a few caveats for complex types). +- `value` - the secret value being stored. +- `owner` - A public key. Every secret has a secret holder, or 'owner' (otherwise it wouldn't be secret, or it would be known to no-one (which would be useless)). Note, this might not be needed for all apps. :question: Perhaps for some apps, knowledge of the commitment's `salt` will be enough to allow the state to be nullified (so no owner is required). +- `creator` - the public key of the user who wrote this secret state to the `publicDataTree` (might not be needed for all apps!) +- `salt` - Every commitment needs some randomness to hide the contents. +- `inputNullifier` - This ensures uniqueness of the commitment. Perhaps this is an app-specific requirement that isn't needed in general; maybe other apps could ensure uniqueness in some other way? Not sure. + +Note: in some cases, the `owner` and `value` might be the same, e.g. for NFTs (where NFT states are represented by `ownerOf[tokenId]`). + +> More on `storageSlot`: Whereas the only 'private state variable' which exists for an "Aztec 2.0 join-split tx" is a user's balance (represented as a set of UTXO commitments), more generally a private contract might contain many private state variables, and a private circuit might read/write several of them. + +> For mappings and arrays of secret variables (if in-scope), we might wish to use a more snark-friendly method for deriving storageSlots, since Solidity uses keccak hashing. + +> A consistent commitment layout might be produced by Noir. Note, though, that apps don't necessarily _have_ to follow this layout; a app's circuit can do whatever it wants, as long as it conforms to the circuit Public Inputs ABI. + + +### Nullifier preimage layout + +Perhaps a good layout for a nullifier would be: + +`nullifier = h(commitment, user_private_key)` + +> A consistent nullifier layout might be produced by Noir. Note, though, that apps don't necessarily _have_ to follow this layout; a app's circuit can do whatever it wants, as long as it conforms to the circuit Public Inputs ABI. + +> Note: In Aztec 2 we also had an `is_real` boolean inside the nullifier, which was needed because every circuit _needed_ to produce two nullifiers, even if some were 'fake'. In Aztec 3, we aren't restricted in that way. A circuit can create any number of nullifiers (even none). Fake nullifiers can be added to a private kernel snark's output (in order to mask the function that was executed) by, for example, calling a special 'padding' circuit of another contract which produces dummy nullifiers in such a way that doesn't require an `is_real` component. + +> Note: In Aztec 2, the Account Circuit can produce a nullifier which effectively nullifies _an entire set_ of account notes. Note however, that account notes and the functionality of an account circuit in Aztec 3 can be created using a _public circuit_ (see [below](#examples)). Account notes aren't really even private states. + +### Preventing private state collisions + +Within a contract, private state collisions are prevented by including a `storageSlot` in the commitment's preimage. To prevent private state collisions between different contracts, we can do the following. + +Let's call the each of the commitments produced by a private circuit an `innerCommitment`. The private kernel circuit will 'attach' to the `innerCommitment` the contract address of the private contract to which the private circuit belongs, to create an `outerCommitment`. + +E.g. `outerCommitment = h(contractAddress, innerCommitment)` + +### Preventing nullifier collisions + + +Similarly, we must do the same with nullifiers: + +E.g. `outerNullifier = h(contractAddress, innerNullifier)`. + +Otherwise, a malicious app could front-run valid nullifier submissions of other contracts. + +## Public States + +Public states are stored in a giant 254-heigh merkle tree; the `publicDataTree`. Each leaf of the tree is a key:value mapping, where: + +- The key is `hash(contractAddress, storageSlot)` +- The value is the public state's `value`. + +> Note: including the `contractAddress` prevents collisions _between_ contracts. The `contractAddress` is injected by the Public Kernel Circuit (not by the app!), to prevent an app from maliciously writing to another contract's state. + +### Reserved storage slots + +For each contract, the following storage slots (in the public data tree) are reserved (and understood by the kernel snarks): + +- `0`: value is the leafIndex of the contractTree where this contract's vkTree is located. + - :question: There's a suggestion to remove the vk tree, and place functions directly as leaves of the contracts tree (which would be renamed to "function tree"). Functions could then be updated by nullifying the old one and deploying a new function to the next empty leaf in the function tree. The `0` storage slot would then be the length of a dynamic array, whose ith element sits at hash(0)+i (much like Solidity storage layouts). However, with such a suggestion, each time a contract calls a function, a 'read emulation' would be needed, where the function is nullified and re-added to the tree for every call, which is untidy. + - The suggestion also adds complexity, like: how do we manage function updates and protect users from having functions change without them realising? + + + + +## Examples + +For those familiar with Aztec Connect, we can categorise its various state variables into the Aztec 3 framework. Although in Aztec 2, we stored most notes in the 'data tree' (an analogue of this spec's `privateDataTree`), notice that not all of those notes will belong in the `privateDataTree` in Aztec 3. + +> See the related [examples](./function-types.md#examples) in the 'function types' section for Aztec3-categorisation of Aztec2's circuits. + +> See also the detailed walkthrough example of deploying an ERC20 shielding protocol (effectively zk-money) to Aztec 3 [here](../../examples/erc20/erc20-shielding.md). + +**Value Note** +A value note forms _part_ of a **private** state. A user's erc20 balances is _partitioned_ across a set of value notes. The total balances is the sum of all not-yet-nullified value notes owned by the user. + +**Account Note** +A **public** state. The contents of this note (`account_alias_id, account_public_key, spending_public_key`) are all public values, so don't necessarily need to be private. But more importantly, in Aztec 2, the 'nullifier' doesn't nullify an account note with 'zero-knowledge' - that is to say, the nullifier is just a hash of the `account_alias_id`, which anyone can dictionary attack to learn who's account was just migrated. In Aztec 3, a user's 'current' account keys, nonce, and alias, could all be stored in the `publicDataTree` and overwritten whenever the user wants to migrate; there's no need for commitments & nullifiers (unless wanting to edit state under zero knowledge). + +**Claim Note** +A **public** state. A claim note contains all public values, so it could be stored as a struct (e.g.) in the `publicDataTree`. The 'nullification' of a claim note that happens in Aztec 2 doesn't hide which claim note has been nullified; notes and nullifiers are just used because there's no public state tree that can be edited. + +**Defi Interaction Note** +A **public** state. Similar to a claim note, the contents of a defi interaction note are all public values, so it could be stored as a struct (e.g.) in the `publicDataTree`. The 'nullification' of a defi interaction note that happens in Aztec 2 doesn't hide which note has been nullified; notes and nullifiers are just used because there's no public state tree that can be edited. + +> So if Aztec 2 were migrated to Aztec 3, the only private state would be a user's balance; partitioned across a series of value notes. \ No newline at end of file diff --git a/circuits/specs/src/architecture/contracts/transactions.md b/circuits/specs/src/architecture/contracts/transactions.md new file mode 100644 index 00000000000..90c01b72c3f --- /dev/null +++ b/circuits/specs/src/architecture/contracts/transactions.md @@ -0,0 +1,148 @@ +# Transactions (Calls) + +A transaction begins as a call to a single function[^1]. A function can be uniquely identified (across all contracts) by its [`functionSignature`](#function-signature). A 'call' to a function is expressed through a [`callStackItem`](#call-stacks). During the execution of a transaction, the initial function might make calls to other functions, so callstacks are required. Call stack items are verified recursively. The final kernel snark that is produced by the recursion represents the entire transaction. + +Contracts can be deployed with a special type of call (a contractDeploymentCall). + +[^1]: Most transactions will likely begin with _two_ callstack items: one for the actual call, and one to pay the rollup provider a fee (by invoking some payment circuit). [Fee payments](../fees/fees.md) still need to be spec'd out. +## Function signature + +A private function call is uniquely defined by a 64-bit integer, which we'll call a `functionSignature`: + + +| Num Bits | Description | +| --- | --- | +| 0-31 (32-bits) | `contractAddress` | The contract address being called.
For calls which deploy a contract, this is `0` (context will be understood from the fact this will be popped of a contractDeploymentCallStack).
For calls to private constructors, this is not known when generating the private kernel proof which verifies the private constructor, so is `0` (in combination with `isConstructor`). | +| 32-60 (29-bits) | `vkIndex` - the position of the vk (i.e. its leaf index) in this contract's `vkTree` (this defines the function being called) | +| 61 (1-bit) | `isPrivate` - A bit describing if this function is public or private.

:question: Is this needed? Perhaps the differences in private/public ABIs is sufficient to cause a circuit to fail if passed the wrong proof type? Or, maybe the vk tree could be arranged in a way which clearly separates public/private vks. | +| 62 (1-bit) | `isConstructor` - If a function is a constructor, it's going to be called by the Contract Deployment Kernel circuit. This flag notifies the kernel circuit that this private circuit is being executed as a constructor for the deployment of a new contract, and so the following public inputs of this private circuit MUST be revealed to the public kernel circuit (so that the Contract Deployment kernel circuit may validate them):
  • `callStackItemHash` - so that the Contract Deployment kernel circuit (and interested parties) can be convinced that the constructor was run with the correct set of inputs (this might need to exposed all the way to L1)
  • `vkHash` - so that the Contract Deplyment constructor can validate that the correct function was executed. (Notice, we don't use a conventional `functionSignature` because we won't be adding constructor vkHashes to the vkTree). Notice, by design, this doesn't reveal any details to observers about the nature of the executed function. We might want to optionally allow the underlying vk to be broadcast (and hence we might need to expose this vkHash all the way to L1).
  • `emittedPublicInputs` - to pass particular inputs to L1.

Special note: this `isConstructor` flag is not part of the private circuit's ABI (as it potentially could have been), because the checks in the contract deployment kernel circuit are much cheaper if it's accessible here. | +| 63 (1-bit) | `isCallback` - Tells the kernel circuit that this function is being executed as a callback from an earlier L2 --> L1 call. | + + +_Note_: the `contractTree` is append-only, so individual verification keys can't be 'replaced' for bug-fixes etc.; the entire contract (a `vkTree`) would need to be re-deployed to the next available slot in the `contractTree`. Such re-deployments, of course, would change the contract address. + +--- + +## Call Stacks + +To fully define how Aztec 3 implements call semantics, we start by defining 4 call stack data structures. + +A call stack is a vector where each entry describes a transaction that is yet to be processed. + +There are 4 call stack types in the Aztec 3 architecture: public calls, private calls, L1 calls (see [earlier](./function-types.md) for details of those 3), and [contract deployment](./deployment.md) calls. + + +### Structure of a call stack item + +A call stack item contains the following witnesses: + +| Data | Description | +| -------- | -------- | +| `functionSignature` | The 'function signature' of the circuit being called. I.e. `concat(contractAddress, vkIndex, isPrivate)` (see earlier) | +| `publicInputsHash` | The public inputs of the call (represented as a pedersen hash. Preimage provided as auxiliary data. When a call stack item is processed, the preimage is unpacked).

Note: for the public circuit ABI, _not all_ public inputs are hashed to form this `publicInputsHash`, since variables read/written from/to the publicDataTree are not known at the time the call is made by the user (or by another circuit). See the Public Circuit ABI section. | +| `callContext: {` | 'Object' for distinguishing between `call` and `delegateCall` | +| ` - msgSender,` | - If doing a `call` or `staticCall`: Either the user address or the address of the contract that created the call. (Can be set to `0` for private -> public calls)
- If doing a `delegateCall`: the address of the calling contract's own `callContext.msgSender` (since delegate calls can be chained). | +| ` - storageContractAddress,` | - If doing a `call` or `staticCall`: the address of the contract being called.
- If doing a `delegateCall`: the address of the calling contract's own `callContext.storageContractAddress` (since delegate calls can be chained). | +| `}` | | +| `bool isDelegateCall` | Used by the kernel snark to validate that the `callContext` of newly-pushed `callStackItems` is consistent with the contract making the call. | +| `bool isStaticCall` | Informs the kernel snark that it MUST fail if the function being called modifies state.

A state modification includes: creating a new contract; emitting events; writing to trees; making a 'call' to another contract. :question: Not sure why 'delegatecall' is not included as a potentially state-modifying tx in ethereum specs?

Note: static calls to private circuits might not make sense. 'Reads' from the privateDataTree require a write of equal value, but the kernel snark cannot 'see' what has been written (it's a private tx), and so cannot validate that a state change didn't take place. So there would be no output commitments or nullifiers for a private static call. But a private call's only use is (I think :question:) to read/modify private state. So I'm thinking a staticCall to a private circuit doesn't make sense. | + +> Note: A `proof` is not included in the call stack item. For public calls, the proof is not known at the time the call is made, because public proofs are generated by the rollup provider. For private calls, the proof isn't needed for a call stack item to be unique; the input nullifiers and output commitments ensure uniqueness of calls. :question: Q: is a private call which doesn't read/modify state nonsensical (if so, that's good - we can reject such calls (they won't have any nullifiers or commitments), thereby ensuring uniqueness of private callStack items)? + +> Note: Certain public inputs are omitted when calculating the publicInputsHash for a public call stack item, because such inputs will depend on the 'current' state of trees, which won't be known by the caller; only by the party executing the call. + +> Note: Certain public inputs are omitted when calculating the publicInputsHash for a callback's call stack item, because such inputs will depend on the L1 Result. + +> Note: The `contractAddress` is sometimes set to `0` in the `functionSignature` if a function is calling another function of the same contract. (Functions cannot know their own contract address, since it is set after the function's circuit has been compiled). The kernel circuits are capable of interpreting this. Examples of a function calling another function of the same contract are: a private-to-public call; and a call to a callback function. + + +#### `callStackItemHash` +`callStackItemHash := hash(functionSignature, publicInputsHash, callContext, etc.)` +a.k.a. `callHash` - similar to Ethereum's notion of a txHash. + +We also use the term `callbackCallHash` to refer to the `callHash` of a callback function (which has certain public inputs omitted when calculating the call stack item). + +Having a single value for each item on the stack (a hash) makes thinking about the callstack easier. + +#### Contract Deployment call stack item + +An instruction to deploy a contract is also expressed through a call, but the call stack item's data is slightly abbreviated (no function signature): + +| Data | Description | +| -------- | -------- | +| `publicInputsHash` | The public inputs of the call (represented as a pedersen hash. Preimage provided as auxiliary data. When a call stack item is processed, the preimage is unpacked). | +| `callContext: {` | 'Object' for distinguishing between `call` and `delegateCall`. :question: Not sure if we need this for a contract deployment? | +| ` - msgSender,` | | +| ` - storageContractAddress,` | | +| `}` | | +| `bool isDelegateCall` | | +| `bool isStaticCall` | | + +### L1 callstack items + +An L1 callstack item is a call to L1. So it's the Ethereum-defined tuple (functionSelector, argument encoding). See [here](https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#function-selector-and-argument-encoding). + +Given that the argument encoding is of a variable size, we can't handle such a thing in our kernel snarks. The easiest thing to do is probably to hash the L1 call's `functionSelector, argumentEncoding` into a single value, and then unpack that value when we come to use it on-chain in the RollupProcessor.sol contract. We should probably use a **keccak256** hash for this, which is cheap on-chain (but unfortunately expensive within a snark). + +To ensure the `l1CallStackItem` is a call to the correct portal contract (that is associated with the contract making the call), the kernel circuit adds the `portalContractAddress` to the preimage of an `l1CallStackItem`. + +We disambiguate the two calls (with and without a portal contract address) with their name. + +So: +- In an app-specific circuit: + - `partialL1CallStackItem = keccak(functionSelector, argumentEncoding)` +- In the kernel circuit, it gets modified to include the portal contract address of the calling contract: + - `l1CallStackItem = keccak(portalContractAddress,l1FunctionCall)` + - We don't do this within the app-specific circuit to save on expensive keccak hashing (since the kernel has to do a portal contract address check, so needs to do this hashing already). + + +### Passing inputs between functions + +Brief explanation of passing inputs between functions: + +Suppose function F0 calls F1 and F2, passing parameter set P1 to F1 receiving response R1 (similar for F2). + +Firstly, note that R1 & R2 don't really exist (for private circuits, at least) - there's no return data, it's all input params P1 & P2, because it's a circuit. + +So to call F1, F0 adds a callstack item to its public inputs representing a call to F1: + +``` +callStackItem = { + functionSignature, + publicInputsHash, + callContext, + etc. +} +``` + +Notice the parameters P1 are squished into the `publicInputsHash`. It's up to the logic of function F0 to interpret the underlying public inputs of this callstack item as input params or return params of F1. + +Similarly, it's up to the logic of function F0 to interpret the underlying public inputs of the F2 callstack item as input params or return params of F2. + + + +## Function visibility + +TODO: maybe move this section? + +Aztec contracts will support `internal`, `public` and maybe also `external` function visibility. But this logic will happen at the Noir level. We don't need the core architecture (i.e. the kernel circuits) to perform checks on the visibility of functions, as explained below: + +Suppose a contract `A` is calling a contract `B`: + +- If `B` is `internal` it won’t exist as a distinct verification key (it'll just be part of A's circuit). +- If `B` is `public` it will exist as a distinct verification key but there is nothing stopping a compiler from rolling an implementation of `B` into other functions in the same contract that call `B` (in fact this is probably exactly what will happen). +- If `B` is `external` there is nothing the kernel snark can do to validate the compiler has chosen or not chosen to roll an implementation of an external function into a different function in the same contract. + +It's just language semantics. It’s important but not something that is part of the core architecture spec. + + + +## Aztec 3 transaction flow + +TODO: diagram in mdbook friendly way. + +(apologies for badly drawn diagram!) +Edit: see [here](https://drive.google.com/file/d/1gCFhE78QhfEboF0hq3scb4vAU1pE0emH/view?usp=sharing) for more diagrams (and a suggestion to recurse in a merkle tree shape instead of linearly). + +![](https://hackmd.io/_uploads/S1WCbhxHK.jpg =600x) + diff --git a/circuits/specs/src/architecture/contracts/trees.md b/circuits/specs/src/architecture/contracts/trees.md new file mode 100644 index 00000000000..f976aa54758 --- /dev/null +++ b/circuits/specs/src/architecture/contracts/trees.md @@ -0,0 +1,35 @@ +# Trees + +See the [sexy diagrams](https://drive.google.com/file/d/1gCFhE78QhfEboF0hq3scb4vAU1pE0emH/view?usp=sharing) also (open with -> diagrams.net). + +Eventually those diagrams will be included in this book, but it's a bit of faff, so we won't do it until things stabilise. I'd keep the tree diagrams handy in a tab of your browser as you read through this book. + +**Private state:** +* `privateDataTree`: stores encrypted UTXO objects (equiv. to current note tree) +* `nullifierTree`: nullifiers for the private data tree + +**Public state:** +* `publicDataTree`: each leaf is a public value, which may be updated.Each leaf is a key:value mapping that maps contract address + storage slot -> value. Note this tree's data can only be read/written by the rollup provider, since only the rollup provider can know the very-latest state of the tree when processing a tx. +* `l1ResultsTree`: stores callback function data and the results of L2 --> L1 calls. +* ~~`accountsTree`: stores Aztec 3 user accounts~~ <-- plan is to use Ethereum keypairs instead + +**Functions:** +* `contractTree`: each leaf contains an Aztec 3 contract's `vkTree`, the contract's address, and its associated portal contract address[^1]. +* `vkTree`: a clear name to give to an aztec contract's mini tree of verification keys (because the term 'contract tree' would always get confused with the `contractTree`) + +**Historic tree roots:** +* `privateDataTreeRootsTree`: for membership checks of old roots of the `privateDataTree` +* `contractTreeRootsTree`: for membership checks of old roots of the `contractTree` + +**Valid Kernel Snark VKs** +* `privateKernelVKTree`: a tree of VKs for various sizes of private kernel circuit (where 'size' refers to the number of public inputs; namely commitments and nullifiers). +* `publicKernelVKTree`: a tree of VKs for various sizes of public kernel circuit. + +**Validium** +We also have Validium versions of some trees (NOT YET SPEC'D) +* `vPrivateDataTree`: Validium version of data tree (data not stored on-chain. i.e. the cheap version for devs that don't want to pay for Ethereum's data availability guarantees) +* `vNullifierTree`: nullifiers for `vPrivateDataTree` +* `vPublicDataTree`: cheapo Validium version of `publicDataTree` + + +[^1]: Consult the diagram. The `portalContractAddress` is stored within a contract's leaf in the contractTree. This is because both private and public calls should be able to make calls to L1, and so both the private and public kernel snarks need to be able to access the correct `portalContractAddress` for a given contract's address. Similarly, the contract address also needs to be stored somewhere a private circuit can access (so not in the public data tree). \ No newline at end of file diff --git a/circuits/specs/src/architecture/fees/fees.md b/circuits/specs/src/architecture/fees/fees.md new file mode 100644 index 00000000000..735ca2437fa --- /dev/null +++ b/circuits/specs/src/architecture/fees/fees.md @@ -0,0 +1 @@ +WIP - still need to have some chats about fees. \ No newline at end of file diff --git a/circuits/specs/src/architecture/kernel-circuits/contract-deployment-kernel.md b/circuits/specs/src/architecture/kernel-circuits/contract-deployment-kernel.md new file mode 100644 index 00000000000..ff06e59ab0d --- /dev/null +++ b/circuits/specs/src/architecture/kernel-circuits/contract-deployment-kernel.md @@ -0,0 +1,284 @@ +# Contract Deployment Kernel Circuit + +Notice, that this is a _kernel_ circuit. That's because this circuit will itself verify a private &or public kernel snark representing the new contract's 'constructors'. Unlike the other two (private & public) kernel snarks though, Contract Deployment Kernel Circuits can be called by users and/or functions, meaning they have a callStack of their own which can be pushed-to. The Contract Deployment call stack will be processed at the very end of the kernel chain; after the private and public kernels have been executed. + +You'll notice that the private/public inputs for this kernel circuit are a superset of the inputs of both the private & public kernel circuits. That's because contract deployments are processed at the very end of a tx, so all other data needs to 'pass through' this circuit. + +### Private inputs ABI + +| Data Type | Description | +| -------- | -------- | +| `signature` | ECDSA signature signed by user (if no private/public kernel proof has been provided && `start.contractDeploymentCallCount == 0`, otherwise empty) | +| `start: {` | | +| `- aggregatedProof` | The current aggregated proof state (if any) | +| `- contractDeploymentCallCount` | How many _contract deployment_ calls have been recursively executed so far? | +| `- contractDeploymentCallStack` | Starting state of contract deployment call stack (max depth 4?) | +| `- l1CallStack` | Starting state of l1 call stack (max depth 64?) | +| `- callbackStack` | See breakdown in the public inputs ABI in the next table | +| `- optionallyRevealedData` | See breakdown in the public inputs ABI in the next table | +| `- deployedContractData` | A keccak hash of information about each deployed contract. | +| `- proverRecords` | | +| `- outputCommitments` | Starting state of commitments to be added to `privateDataTree`.
Notice that a contract deployment circuit is allowed to add commitments to the privateDataTree. | +| `- inputNullifiers` | Deployment of a new contract to an address produces a `contractAddressNullifier` which needs to be added to this list of nullifiers. | +| `- publicDataTreeRoot` | The publicDataTree's root _before_ we make any state transitions (as requested in the contractDeploymentCall being processed within this circuit). | +| `- contractTreeRoot` | The contractTree's root _before_ we deploy any new contract (as requested in the contractDeploymentCall being processed within this circuit). | +| `- nextAvailableContractTreeLeafIndex` | The index of the left-most nonempty leaf of the contract tree _after_ deploying a new contract within this circuit. | +| `}` | | +| `previousKernel: {` | | +| `- proof` | | +|
- publicInputs = {
  end: start, // copy within circuit.
  constants: {
    oldTreeRoots: {
      privateDataTree,
      contractTree,
      l1ResultsTree,
    },
    privateKernelVKTreeRoot,
    publicKernelVKTreeRoot,
    initialPublicDataTreeRoot,
    initialContractTreeRoot,
    initialNextAvailableContractTreeLeafIndex,
    isConstructorRecursion,
    isCallbackRecursion,
    executedCallback: {},
    globals: {,
      minTimestamp,
      block.timestamp,
      block.number,
      prevBlock.ethTimestamp,
      prevBlock.ethNumber,
    }
  }
  proverAddress,
  isPrivate,
  isPublic,
  isContractDeployment,
}
| | +| `- vk` | The VK that should be used to verify the `previousKernel.proof`. | +| `- vkIndex` | The leaf index of the `previousKernel.vk`, to accompany the `previousKernel.vkPath` in doing a membership check. | +| `- vkPath` | We can support multiple 'sizes' of kernel circuit (i.e. kernel circuits with varying numbers of public inputs) if we store all of the VKs of such circuits as vkHashes in a little Merkle tree. This path is the sibling path from the `previousKernel.vk`'s leaf to the root of such a tree. | +| `}` | | +| `privateConstructorKernel: {` | | +| `- proof` | | +| `- publicInputs` | The public inputs of a private _kernel_ snark (see the relevant section). | +| `- vk` | The VK that should be used to verify the `privateConstructorKernel.proof`. | +| `- vkIndex` | The leaf index of the `privateConstructorKernel.vk`, to accompany the `privateConstructorKernel.vkPath` in doing a membership check. | +| `- vkPath` | We can support multiple 'sizes' of kernel circuit (i.e. kernel circuits with varying numbers of public inputs) if we store all of the VKs of such circuits as vkHashes in a little Merkle tree. This path is the sibling path from the `privateConstructorKernel.vk`'s leaf to the root of such a tree. | +| `}` | | +| `publicConstructorKernel: {` | | +| `- proof` | | +| `- publicInputs` | The public inputs of a public _kernel_ snark (see the relevant section). | +| `- vk` | The VK that should be used to verify the `publicConstructorKernel.proof`. | +| `- vkIndex` | The leaf index of the `publicConstructorKernel.vk`, to accompany the `publicConstructorKernel.vkPath` in doing a membership check. | +| `- vkPath` | We can support multiple 'sizes' of kernel circuit (i.e. kernel circuits with varying numbers of public inputs) if we store all of the VKs of such circuits as vkHashes in a little Merkle tree. This path is the sibling path from the `publicConstructorKernel.vk`'s leaf to the root of such a tree. | +| `}` | | +| `contractDeploymentCall: {` | Data relating to the next contract deployment callstack item that we're going to pop off the callstack and verify within this snark. Recall we're representing items in the callstack as a `callStackItemHash`. We'll pass the unpacked data here, for validation within this kernel circuit. | +|
- publicInputs: {
  privateConstructorPublicInputsHash,
  publicConstructorPublicInputsHash,
  privateConstructorVKHash,
  publicConstructorVKHash,
  contractAddress,
  salt,
  vkRoot,
  circuitDataKeccakHash,
  portalContractAddress,
},
| Rather than pass in the `publicInputsHash`, we pass in its preimage here (we'll hash it within this kernel circuit). This is _all_ of the data listed in the Contract Deployment ABI's table of public inputs (see earlier section). | +| `- callContext: {...},` | | +| `- isDelegateCall,` | | +| `- isStaticCall = false,` | | +| `- newContractSiblingPath` | The sibling path (in the contract tree) that will allow the new contract to be inserted at the next available leaf. | +| `- newContractStorageSlotSiblingPath[254]` | We'll need to write data to the `0`th storage slot of the new contract. This sibling paths allow such updates to be made to leaves of the `publicDataTree`. | +| `}` | | + + +### Public inputs ABI + +| Data type | Description | +| --- | --- | +| `end: {` | | +| `- aggregatedProof` | Output aggregated proof | +| `- contractDeploymentCallCount` | How many calls have been recursively executed at end of circuit execution? (either `start.publicCallCount + 1` or `0` iff `end.publicCallStack` is empty | +| `- contractDeploymentCallStack` | Output state of contract deployment call stack (max depth 4?) | +| `- l1CallStack` | Output state of l1 call stack (max depth 64?) | +| `- callbackStack: [{` | Data to add to the `l1ResultsTree`. See [here](../contracts/l1-calls.md) | +| `- - callbackPublicKey` | | +| `- - successCallbackCallHash,` | of the callback function to execute upon success of the L1 call | +| `- - failureCallbackCallHash` | of the callback function to execute upon failure of the L1 call | +| `- - successResultArgMapAcc` | | +| `}],` | | +| `- optionallyRevealedData: [{` | Some values from a public call can be optionally revealed to the Contract Deployment kernel circuit / L1, depending on bools of the public circuit ABI. For some/every public call, each 'object' in this 'array' contains the following fields (some of which might be 0, depending on the bools) (note: there might be more efficient ways to encode this data - this is just for illustration): | +| `- - callStackItemHash,` | Serves as a 'lookup key' of sorts. | +| `- - functionSignature,` | | +| `- - emittedPublicInputs: [_, _, _, _],` | | +| `- - vkHash,` | | +| `- - portalContractAddress,` | | +| `- - ` | :question: Discussion needed. We might also need to reveal all the bools to the public kernel snark, so that it may filter out data that doesn't need to be revealed to L1. | +| `- }, ...]` | :question: Should a callStackItemHash contain a salt, to hide the nature of the call? | +| `- deployedContractData: [...]` | Each entry (one per newly deployed contract) is a keccak hash of information about that contract. The preimage of the hash will be submitted on-chain for reconciliation, so that users may validate the contract was deployed as purported. The preimage is simply the public inputs of a contractDeploymentCallStackItem. | +| `- proverRecords` | We need to record info about who generated public proofs and who generated public kernel snarks, so that they may be rewarded for their work. It's not as simple as there being one prover. Proving might be delegated to various people by the rollup processor, so we need to track an array (obvs of some bounded size) with an element for each prover. Each prover record entry in `proverRecords` will be of the form `[proverAddress, totalNumberOfGates]`, where we track the `totalNumberOfGates` this prover has generated proofs over, as an approximation of the work they've done. | +| `- outputCommitments` | Output state of commitments to be added to `privateDataTree`.

Notice that a public circuit is allowed to add commitments to the privateDataTree. Imagine, for example, a defi-bridge between private L2 and public L2. Then the rollup processor can complete partial commitments (partial commitments can be added to the _public_ data tree), and the completed commitments can be added straight to the private data tree. | +| `- inputNullifiers` | Deployment of a new contract to an address produces a `contractAddressNullifier` which needs to be added to this list of nullifiers. | +| `- publicDataTreeRoot` | The root of the public data tree _after_ performing the stateTransitions requested by the contractDeploymentCall being processed within this circuit. | +| `- contractTreeRoot` | The root of the contract tree _after_ deploying a new contract within this circuit. | +| `- nextAvailableContractTreeLeafIndex` | The index of the left-most nonempty leaf of the contract tree _after_ deploying a new contract within this circuit. | +| `}` | | +| `constants: {` | | +| `- oldTreeRoots: {` | | +| `- - privateDataTree` | must equal the value used in the final private kernel proof | +| `- - contractTree` | A recent root of the contract tree (for vk membership checks). Must also equal the value used in the final private kernel proof. | +| `- - l1ResultsTree,` | A recent root of the L1 results tree. | +| `- }` | | +| `- privateKernelVKTreeRoot` | must equal the value used in the final private kernel proof | +| `- publicKernelVKTreeRoot` | The root of a little Merkle tree whose leaves are hashes of the public kernel circuit VKs, allowing support for multuple 'sizes' of kernel circuit (i.e. with varying numbers of public inputs). | +| `- initialPublicDataTreeRoot` | The root of the public data tree before _any_ of the calls from the publicCallStack were executed. We need this to demonstrate that we started our recursion using the correct tree. This will be kept the same throughout the recursion. | +| `- initialContractTreeRoot` | The root of the contract tree before _any_ of the calls from the contractDeploymentCallStack were executed. We need this to demonstrate that we started our 'contract deployment' recursion using the correct tree. This will be kept the same throughout the recursion. | +| `- initialnextAvailableContractTreeLeafIndex` | The index of the left-most nonempty leaf of the contract tree before _any_ of the calls from the contractDeploymentCallStack were executed. We need this to demonstrate that we started our contract deployments from the correct leaf. | +| `- isConstructorRecursion`, | Flags whether this entire recursion began with a constructor function. | +| `- isCallbackRecursion`, | Flags whether this entire recursion began with a callback function. | +| `- executedCallback: {` | Only populated (if at all) by the first call in a tx, if that call is a callback AND if the callback's execution doesn't want to be 'hidden'. This gives details of the callback that's been executed, so the callback and result can be cross-checked against the l1ResultsTree eventually in the Base Rollup Circuit.
We assume the rollup provider will have a record of the contents of each leaf of the l1ResultsTree, so we don't need to provide the data here; the rollup provider can pass it as a private input to the Base Rollup snark. | +| `- - l1ResultHash`, | This will eventually be compared against a leaf of the L1 Callback Tree in the Base Rollup Circuit. | +| `- - l1ResultsTreeLeafIndex`, | Communicates to the rollup provider the correct leaf to prove membership against in the l1ResultsTree. This will eventually be used to lookup a leaf of the L1 Callback Tree in the Base Rollup Circuit. | +| `- },` | | +| `- globals: {` | | +| `- - minTimestamp` | must equal value used in private call proof | +| `- - block.timestamp` | aztec block timestamp | +| `- - block.number` | aztec block number | +| `- - prevBlock.ethTimestamp` | Ethereum timestamp of block that contained previous Aztec 3 block | +| `- - prevBlock.ethNumber` | block number of Ethereum block that contained previous Aztec 3 block | +| `- },` | | +| `}` | | +| `proverAddress` | Who is going to be generating the proof for this kernel circuit (any value can be injected here by the prover). | +| `isPrivate = false` | Bool. Tells the next kernel circuit that this is not a private kernel snark. | +| `isPublic = false` | Bool. Tells the next kernel circuit that this is not a public kernel snark. | +| `isContractDeployment = true` | Bool. Tells the next kernel circuit that this is a contract deployment kernel snark. | + + + +### Execution Logic + +:heavy_exclamation_mark: It would be ideal if the number of public inputs of the private kernel, public kernel, and contract deployment kernel circuits are the same, so that the below base case and recursion cases can use the same verification code paths (and also so that the Rollup Circuit can accept any of these kernel proofs, to avoid having to unnecessarily 'wrap' every tx in a contract deployment kernel proof). + +Note: the logic would be simplified if we only allowed 1 contract deployment per tx. TBC. + +Current rule: you can't deploy a contract directly as an L1 callback (because it's too complicated, and because there's no 'app-specific' contract deployment circuit that could handle an L1 response - only public and private circuits can have custom logic). You'd have to call a public/private function as a callback which would then deploy a contract for you. + +- `require(previousKernel.publicInputs.isPrivate == true NAND previousKernel.publicInputs.isPublic == true NAND previousKernel.publicInputs.isContractDeployment == true)` + +Base case (verifying a public or private kernel snark): +* If `start.contractDeploymentCallCount == 0`: + * validate that `start.contractDeploymentCallStack.length > 0` + * if `(previousKernelProof.proof && (previousKernelProof.isPublic || previousKernelProof.isPrivate)` + * Verify the `previousKernelProof` using the `previousKernelVK` + * Validate that the `previousKernelVK` is a valid public or private kernel VK with a membership check: + * Calculate `previousKernelVKHash := hash(previousKernelVK`; + * Compute `root` using the `previousKernelVKHash`, `previousKernelVKPath` and `previousKernelVKIndex`. + * Validate that `root == privateKernelTreeRoot` or `root == publicKernelTreeRoot`. + - else: + * Pop the only `contractDeploymentCallStackItemHash` off the `start.contractDeploymentCallStack`. + * Verify the ECDSA `signature`, with `message := contractDeploymentCallStackItemHash` and `signer := contractDeploymentCall.callContext.msgSender`. + * Validate consistency of 'start' and 'previous end' values: + - verify that the `start...` values match the `previousKernelProofPublicInputs.end...` equivalents. + * Validate consistency of values which must remain the same throughout the recursion (when passed from kernel circuit to kernel circuit): + * ensure this kernel circuit's 'constant' public inputs match the `previousKernelProof`'s public inputs. + * E.g. old tree roots. + - Also ensure that any 'append-only' stacks or arrays have the same entries as the previous kernel proof, before pushing more data onto them! + - Set `initialContractTreeRoot := start.contractTreeRoot`. + +Recursion (of contract deployment kernel snarks - if we choose to support more than one contract deployment per tx): +* If `start.contractDeploymentCallCount > 0`: + * Verify the `previousKernelProof` using the `previousKernelVK` + * Validate that the `previousKernelVK` is a valid _public_ kernel VK with a membership check: + * Calculate `previousKernelVKHash := hash(previousKernelVK)`; + * Compute `root` using the `previousKernelVKHash`, `previousKernelVKPath` and `previousKernelVKIndex`. + * Validate that `root == publicKernelVKTreeRoot`. + * Validate consistency of 'start' and 'previous end' values: + - verify that the `start...` values match the `previousKernelProofPublicInputs.end...` equivalents. + * Validate consistency of values which must remain the same throughout the recursion (when passed from kernel circuit to kernel circuit): + * ensure this kernel circuit's 'constant' public inputs match the `previousKernelProof`'s public inputs. + * E.g. old tree roots. + +Validate the next call on the contractDeploymentCallStack: +* Verify `start.contractDeploymentCallStack.length > 0` and (if not already done during the 'Base Case' logic above), pop 1 item off of `start.contractDeploymentCallStack` - call it `contractDeploymentCall`. +* Validate that this newly-popped `contractDeploymentCallStackItemHash` corresponds to the `contractDeploymentCall` data passed into this circuit: + * Calculate `contractDeploymentCallPublicInputsHash := hash(contractDeploymentCall.publicInputs);` + * Verify that `contractDeploymentCallStackItemHash == hash(contractDeploymentCall.functionSignature, contractDeploymentCallPublicInputsHash, contractDeploymentCall.callContext, etc...)` + +Deploy the contract: +- Let `deployerAddress := contractDeploymentCall.callContext.msgSender` +- Extract `{ privateConstructorPublicInputsHash, publicConstructorPublicInputsHash, privateConstructorVKHash, publicConstructorVKHash, contractAddress, salt } = contractDeploymentCall;` +- Let `constructorsHash := hash(privateConstructorPublicInputsHash, publicConstructorPublicInputsHash, privateConstructorVKHash, publicConstructorVKHash)` +- Let `newContractAddress := hash(deployerAddress, salt, vkRoot, constructorHash)` +- `assert(contractAddress == newContractAddress)` +- Let `newContractAddressNullifier := hash(newContractAddress)` - used to prevent someone else deploying to this same contract address. + - Remember to add this `newContractAddressNullifier` to the `inputNullifiers` array. +- Let `newPortalContractAddressNullifier := hash(portalContractAddress)` - used to prevent someone else linking to this same portal contract address. + - Remember to add this `newPortalContractAddressNullifier` to the `inputNullifiers` array. +- Let `newContractLeafIndex = start.nextAvailableContractTreeLeafIndex` +- Construct the leaf that will be inserted into the `contractTree` (consult the diagram): + - `leafValue = hash(newContractAddress, portalContractAddress, contractDeploymentCall.publicInputs.vkRoot)` +- Insert the vk tree into the `contractTree` using: `leafIndex = newContractLeafIndex, leafValue, siblingPath = contractDeploymentCall.newContractSiblingPath`. Get the `newContractTreeRoot` in return +- Write new 'meta' information about this contract into the first storage slots of this contract in the `publicDataTree`: + - Store a pointer to the `newContractLeafIndex` which can be queried using the `newContractAddress`: + - Let `publicDataTreeLeafIndex := hash(newContractAddress, 0)` (the 0th storage slot of each contract is reserved especially for this leaf index pointer). + - Insert the pointer into the `publicDataTree` using: `leafIndex = publicDataTreeLeafIndex, leafValue = newContractLeafIndex, siblingPath = contractDeploymentCall.newContractStorageSlotSiblingPath`. Get a `newPublicDataTreeRoot` in return. + - Note: we don't need to check whether we're overwriting an existing state in the tree here. The `newContractAddressNullifier`, together with the infeasibility of inter-contract state collisions, is enough to prevent a collision. + + +Verify the private constructor's kernel snark: +* Verify the (`privateConstructorKernel.proof`, `privateConstructorKernel.publicInputs`) using the `privateConstructorKernel.vk` + - Validate that the `privateConstructorKernel.vk` is a valid _private_ kernel VK with a membership check: + * Calculate `privateConstructorKernelVKHash := hash(privateConstructorKernel.vk)`; + * Compute `root` using the `privateConstructorKernelVKHash`, `privateConstructorKernel.vkPath` and `privateConstructorKernel.vkIndex`. + * Validate that `root == constants.privateKernelVKTreeRoot`. + * Validate consistency of values which must remain the same between the private constructor kernel's inputs and this kernel's inputs: + * ensure this kernel circuit's 'constant' public inputs match the `privateConstructorKernel`'s public inputs. + * E.g. old tree roots. + - We'll push public inputs from this constructor onto stacks shortly. + - Validate that the expected constructor function was indeed actually executed as the first call of the private kernel snark, with the expected inputs, by comparing call data: + - We need to reconcile the exposed callStackItemHash of the actually-executed constructor of the private kernel snark, with what we'd expect: + - Let `actualCallStackItemHash = privateConstructorKernel.publicInputs.end.optionallyRevealedData[0].callStackItemHash;` (the `0`-th value will be the constructor's callStack item, otherwise something has gone wrong). + - Let's try to reconcile that `actualCallStackItemHash` with the hash we'd expect: `expectedCallStackItemHash`: + - Let `expectedFunctionSignature := concat(newContractAddress, 0, false, true, false)`. Note: the `0` in the 2nd parameter might suggest we want to call the function whose vkIndex is at position `0` - but the `isConstructor = true` tells the kernel circuit that we're calling a constructor; not looking up a deployed function. Note: this line is justification for `isConstructor` being part of the functionSignature. If it were alternatively part of the `privateConstructorPublicInputsHash`, we'd have to do _much_ more hashing to extract its value here. + - Let `expectedPublicInputsHash := contractDeploymentCall.publicInputs.privateConstructorPublicInputsHash` + - Let `expectedCallContext := { msgSender: contractDeploymentCall.callContext.msgSender, storageContractAddress: newContractAddress }`. Notice: The calling of a constructor is as though called by the person/contract who called to deploy the contract in the first place. + - Let `expectedIsDelegateCall = false`, `expectedIsStaticCall = false`. + - Hash it all together: + - `expectedCallStackItemHash = hash(expectedFunctionSignature, expectedPublicInputsHash, expectedCallContext, false, false)` + - Assert `actualCallStackItemHash == expectedCallStackItemHash`. + - We need to reconcile the exposed `privateConstructorVKHash` of the actually-executed constructor of the private kernel snark, with what we'd expect: + - Let `actualPrivateConstructorVKHash = privateConstructorKernel.publicInputs.end.optionallyRevealedData[0].vkHash` (the `0`-th value will be the constructor's callStack item, otherwise something has gone wrong). + - Let `expectedPrivateConstructorVKHash = contractDeploymentCall.publicInputs.privateConstructorVKHash` + - Assert `expectedPrivateConstructorVKHash == actualPrivateConstructorVKHash` + + +Verify the public constructor's kernel snark: +* Verify the (`publicConstructorKernel.proof`, `publicConstructorKernel.publicInputs`) using the `publicConstructorKernel.vk` + - Validate that the `publicConstructorKernel.vk` is a valid _public_ kernel VK with a membership check: + * Calculate `publicConstructorKernelVKHash := hash(publicConstructorKernel.vk)`; + * Compute `root` using the `publicConstructorKernelVKHash`, `publicConstructorKernel.vkPath` and `publicConstructorKernel.vkIndex`. + * Validate that `root == constants.publicKernelVKTreeRoot`. + * Validate consistency of values which must remain the same between the public constructor kernel's inputs and this kernel's inputs: + * ensure this kernel circuit's 'constant' public inputs match the `publicConstructorKernel`'s public inputs. + * E.g. old tree roots. + - We'll push public inputs from this constructor onto stacks shortly. + - Validate that the expected constructor function was indeed executed as the first call of the public kernel snark, with the expected inputs, by comparing call data: + - We need to reconcile the exposed callStackItemHash of the actually-executed constructor of the public kernel snark, with what we'd expect: + - Let `actualCallStackItemHash = publicConstructorKernel.publicInputs.end.optionallyRevealedData[0].callStackItemHash;` (the `0`-th value will be the constructor's callStack item, otherwise something has gone wrong). + - Let's try to reconcile that `actualCallStackItemHash` with the hash we'd expect: `expectedCallStackItemHash`: + - Let `expectedFunctionSignature := concat(newContractAddress, 0, false, true, false)`. Note: the `0` in the 2nd parameter might suggest we want to call the function whose vkIndex is at position `0` - but the `isConstructor = true` tells the kernel circuit that we're calling a constructor; not looking up a deployed function. Note: this line is justification for `isConstructor` being part of the functionSignature. If it were alternatively part of the `publicConstructorPublicInputsHash`, we'd have to do _much_ more hashing to extract its value here. + - Let `expectedPublicInputsHash := contractDeploymentCall.publicInputs.publicConstructorPublicInputsHash` + - Let `expectedCallContext := { msgSender: contractDeploymentCall.callContext.msgSender, storageContractAddress: newContractAddress }`. Notice: The calling of a constructor is as though called by the person/contract who called to deploy the contract in the first place. + - Let `expectedIsDelegateCall = false`, `expectedIsStaticCall = false`. + - Hash it all together: + - `expectedCallStackItemHash = hash(expectedFunctionSignature, expectedPublicInputsHash, expectedCallContext, false, false)` + - Assert `actualCallStackItemHash == expectedCallStackItemHash`. + - We need to reconcile the exposed `publicConstructorVKHash` of the actually-executed constructor of the public kernel snark, with what we'd expect: + - Let `actualPublicConstructorVKHash = publicConstructorKernel.publicInputs.end.optionallyRevealedData[0].vkHash` (the `0`-th value will be the constructor's callStack item, otherwise something has gone wrong). + - Let `expectedPublicConstructorVKHash = contractDeploymentCall.publicInputs.publicConstructorVKHash` + - Assert `expectedPublicConstructorVKHash == actualPublicConstructorVKHash` + +Update the `end` values: +- Extract the following from the `privateConstructorKernel.publicInputs`, and push the data onto the relevant stack of _this_ circuit's public inputs: + - `l1CallStack`, `optionallyRevealedData`, `outputCommitments`, `inputNullifiers`, `proverRecords` + - Merge the stacks. (It'll probably require some expensive O(n^2) logic to merge these stacks). + - Ensure the `initial` tree roots exposed by the `privateConstructorKernel` match the latest tree roots that this circuit was aware of. Then update this circuit's understanding of the latest tree roots to be the `end` tree roots exposed by the `privateConstructorKernel`. +- Extract the following from the `publicConstructorKernel.publicInputs`, and push the data onto the relevant stack of _this_ circuit's public inputs: + - `l1CallStack`, `callbackStack`, `optionallyRevealedData`, `outputCommitments`, `inputNullifiers` + - Merge the stacks. (It'll probably require some expensive O(n^2) logic to merge these stacks). + - Ensure the `initial` tree roots exposed by the `publicConstructorKernel` match the latest tree roots that this circuit was aware of. Then update this circuit's understanding of the latest tree roots to be the `end` tree roots exposed by the `publicConstructorKernel`. +- Push a log of this contract deployment to the `deployedContractData`. + - Let `log := keccak256(contractDeploymentCall.publicInputs);` NOTE: this is expensive, since it's keccak, but I think this needs to be validated on-chain as well. We've already computed a hash of this data earlier in this circuit, but that was a cheaper pedersen hash (since the app needs to be able to efficiently produce that hash in order to create a contractDeploymentCallStackHash cheaply). + - Push `log` onto `deployedContractData`. +* Calculate new data to push to `proverRecords`: + - Extract `previousKernelProverAddress := previousKernel.publicInputs.proverAddress` + - Extract `previousKernelNumberOfGates := previousKernel.vk.n` + - Extract `privateConstructorKernelProverAddress := privateConstructorKernel.publicInputs.proverAddress` + - Extract `privateConstructorKernelNumberOfGates := privateConstructorKernel.vk.n` + - Extract `publicConstructorKernelProverAddress := publicConstructorKernel.publicInputs.proverAddress` + - Extract `publicConstructorKernelNumberOfGates := publicConstructorKernel.vk.n` + - Below is expensive looping and dynamic pushing within a circuit (O(n^2) stuff). Consider alternatives. + - Find in the `proverRecords` array an entry matching `previousKernelProverAddress`. + - If found: increment their `totalNumberOfGates += previousKernelNumberOfGates`. + - If not found: push a new record `[previousKernelProverAddress, previousKernelNumberOfGates]` onto `proverRecords`. + - Find in the `proverRecords` array an entry matching `privateConstructorKernelProverAddress`. + - If found: increment their `totalNumberOfGates += privateConstructorKernelNumberOfGates`. + - If not found: push a new record `[privateConstructorKernelProverAddress, privateConstructorKernelNumberOfGates]` onto `proverRecords`. + - Find in the `proverRecords` array an entry matching `publicConstructorKernelProverAddress`. + - If found: increment their `totalNumberOfGates += publicConstructorKernelNumberOfGates`. + - If not found: push a new record `[publicConstructorKernelProverAddress, publicConstructorKernelNumberOfGates]` onto `proverRecords`. +* Extract the contract deployment call's `contractDeploymentCallStack` and `l1CallStack`. + - Validate the call contexts of these calls: + - For each `newCallStackItem` in `contractDeploymentCallStack`: + - If `newCallStackItem.isDelegateCall == true`: + - Assert `newCallStackItem.callContext == contractDeploymentCall.callContext` + - Else: + - Assert `newCallStackItem.callContext.msgSender == contractDeploymentCall.functionSignature.contractAddress` + - Assert `newCallStackItem.callContext.storageContractAddress == newCallStackItem.functionSignature.contractAddress` + - Push the contents of these call stacks onto the kernel circuit's `end.contractDeploymentCallStack` and `end.l1CallStack`. + - It would be nice if these 'pushes' could result in tightly-packed stacks. + +* If `end.contractDeploymentCallStack.length == 0`, set `end.contractDeploymentCallCount = 0`, else `end.contractDeploymentCallCount = start.contractDeploymentCallCount + 1` diff --git a/circuits/specs/src/architecture/kernel-circuits/kernel-circuits.md b/circuits/specs/src/architecture/kernel-circuits/kernel-circuits.md new file mode 100644 index 00000000000..124ef179cdb --- /dev/null +++ b/circuits/specs/src/architecture/kernel-circuits/kernel-circuits.md @@ -0,0 +1,33 @@ +# Kernel Circuits + +Kernel circuits are used to validate the correctness of a private or public transaction, manage call stacks and implement traditional call semantics. + +There are 3 Kernel circuits: +- private kernel circuit +- public kernel circuit +- contract deployment kernel circuit + +Private kernel circuit proofs are generated by the client (transaction sender). Public & Contract Deployment kernel circuit proofs are generated by the rollup provider. + +The Kernel circuits act recursively upon their respective callstack. The private kernel circuit will pop 1 item off the private callstack, verify a proof of correctness, extract additional calls to be made from the verified proof and insert them into their respective call stacks. In addition the previous kernel circuit proof (if present) is aggregated with the private transaction proof. + +This process is repeated recursively until the private callstack is empty. This final proof is then fed into a public kernel circuit, which performs the same action on the public callstack. + +If any of the private / public circuits _deploy_ a contract as part of their execution, then the contract deployment callstack will be nonempty, and so the final public kernel snark will be fed into the contract deployment kernel circuit, which will recurse through its callstack. + +A transaction is ready to be [rolled up](../rollup-circuits/rollup-circuits.md)) at the point that a public kernel circuit proof is generated whose private and public call stacks are empty. + + +## Achieving arbitrary recursion + +A circuit cannot verify a proof of itself if the verification key is required as part of the circuit's structure. + +We can solve this by having the kernel circuit verify a prior kernel proof using a *user-input* verification key. i.e. the Private Kernel Snark verification key is *also* a public input into the circuit (or at least a hash of it). + +The kernel circuit must then perform a consistency check; that the key present in the previous kernel proof's public inputs is equal to the key present in the current public inputs. + +Finally, the circuit in the next phase of the transaction process (the public kernel circuit) must verify that the key from the private kernel proof's public inputs is equal to the canonical private kernel circuit verification key. + +Repeat this for the public kernel circuit, (and again for the contract deployment circuit, if applicable), where this time the rollup circuit will check the correctness of the used key. + +The current spec also allows for multiple 'sizes' of kernel circuit - i.e. kernel circuits with various numbers of public inputs, to save on proof generation times. \ No newline at end of file diff --git a/circuits/specs/src/architecture/kernel-circuits/private-kernel.md b/circuits/specs/src/architecture/kernel-circuits/private-kernel.md new file mode 100644 index 00000000000..7a7d3cb2eba --- /dev/null +++ b/circuits/specs/src/architecture/kernel-circuits/private-kernel.md @@ -0,0 +1,292 @@ +# Private Kernel Circuit + +## Private inputs ABI + +| Data Type | Description | +| -------- | -------- | +| `signature` | ECDSA signature (where `message = publicInputsHash`) signed by the user (if `start.privateCallCount == 0`, otherwise empty) | +| `start: {` | | +| `- aggregatedProof` | The current aggregated proof state (if any) | +| `- privateCallCount` | How many calls have been recursively executed so far? | +| `- privateCallStack` | Starting state of private call stack (max depth 64) | +| `- publicCallStack` | Starting state of public call stack (max depth 64) | +| `- contractDeploymentCallStack` | Output state of contract deployment call stack (max depth 4?) | +| `- l1CallStack` | Starting state of L1 call stack (max depth 64?) | +| `- callbackStack` | See breakdown in the public inputs ABI in the next table | +| `- optionallyRevealedData` | See breakdown in the public inputs ABI in the next table | +| `- outputCommitments` | Starting state of commitments to be added to `privateDataTree` | +| `- inputNullifiers` | Starting state of nullifiers to be added to `nullifierTree` (up to 64) | +| `},` | | +| `previousKernel: {` | | +| `- proof` | Previous Kernel snark proof (if any). | +|
- publicInputs = {
  end: start, // copy within circuit.
  constants: {
    oldTreeRoots: {
      privateDataTree,
      contractTree,
    },
    privateKernelVKTreeRoot,
    isConstructorRecursion,
    isCallbackRecursion,
    executedCallback: {
      l1ResultHash,
      l1ResultsTreeLeafIndex,
    },
    globals: {
      minTimestamp,
    },
  }
  isPrivate,
  isPublic,
  isContractDeployment,
}
| The first Kernel Circuit execution can have `previousKernel.proof = 0` (or equivalent). | +| `- vk` | The VK that should be used to verify the `previousKernel.proof`. | +| `- vkIndex` | The leaf index to accompany the `previousKernel.vkPath`. | +| `- vkPath` | We can support multiple 'sizes' of kernel circuit (i.e. kernel circuits with varying numbers of public inputs) if we store all of the VKs of such circuits as vkHashes in a little Merkle tree. This path is the sibling path from the `previousKernel.vk`'s leaf to the root of such a tree. | +| `}` | | +| `privateCall: {` | Data relating to the next private callstack item that we're going to pop off the callstack and verify within this snark. Recall we're representing items in the callstack as a `callStackItemHash`. We'll pass the unpacked data here, for validation within this kernel circuit. | +| `- functionSignature,` | 64-bits (see earlier section) | +| `- publicInputs: {...},` | Rather than pass in the `publicInputsHash`, we pass in its preimage here (we'll hash it within this kernel circuit). This is _all_ of the data listed in the Private Circuit ABI's table of public inputs (see earlier section). | +| `- callContext: {...},` | | +| `- isDelegateCall` | | +| `- isStaticCall` | | +| `- proof` | The proof for this item of the callstack. We'll be verifying this within this kernel circuit. | +| `- vk` | The full verification key of the private call proof that will be verified within this circuit. (I.e. the proof `start.privateCallStack.pop().proof`) | +| `- vkPath` | The sibling path of the `vk`'s `vkHash` within the aztec contract's 'mini merkle tree'. Note, the `vkIndex` to use when proving membership can be grabbed from the `privateCall` being executed (which itself is popped off the callstack). | +| `- portalContractAddress` | The portal contract address that corresponds to the contract of the function being called (`privateCall`). | +| `- contractLeafIndex` | The leaf index of the contracts tree where this contract's vkTree is stored | +| `- contractPath` | The sibling path from this contract's root (a leaf of the contract tree) to the `oldContractTreeRoot` | +| `- privatelyExecutedCallback: {` | Only populated (if at all) by the first call in a tx, if that call is a callback. This gives details of the callback that's been executed, so the callback and result can be cross-checked against the l1ResultsTree within this private kernel circuit. It's checked within the private kernel circuit so that the fact that this callback has even been executed can be hidden. | +| `- - l1SuccessResultValues`, | The results of an L1 interaction. These underlying result values will be reconciled against this `privateCall.publicInputs.executedCallback.l1ResultHash` | +| `- - l1SuccessResultArgPositions`, | An array which details how the L1 Results array gets mapped to the argument positions of the callback function. This will be checked within this circuit whether these values 'accumulate' to give the `successResultArgMapAcc`. The format can be cumbersome, if it saves on constraints, since this is a private input. | +| `- - l1ResultsTreeSiblingPath`, | The leafIndex is a public input of the privateCall itself. | +|
-  - callbackStackItem: {
callbackPublicKey,
successCallbackHash,
failureCallbackHash,
successResultArgMapAcc
- - } | | +| `- - callbackPrivateKey`, | | +| `- },` | | +| `}` | | + +## Public inputs ABI + +| Data type | Description | +| --- | --- | +| `end: {` | | +| `- aggregatedProof,` | Output aggregated proof | +| `- privateCallCount,` | How many calls have been recursively executed at end of circuit execution? (either `start.privateCallCount + 1` or `0` iff `endPrivateCallStack` is empty | +| `- privateCallStack,` | Output state of private call stack (max depth 64) | +| `- publicCallStack,` | Output state of public call stack (max depth 64) | +| `- contractDeploymentCallStack` | Output state of contract deployment call stack (max depth 4?) | +| `- l1CallStack,` | Output state of l1 call stack (max depth 64?) | +| `- callbackStack: [{` | Data to add to the `l1ResultsTree`. See [here](../contracts/l1-calls.md) | +| `- - callbackPublicKey` | | +| `- - successCallbackCallHash,` | of the callback function to execute upon success of the L1 call. | +| `- - failureCallbackCallHash` | of the callback function to execute upon failure of the L1 call. | +| `- - successResultArgMapAcc` | See [here](../contracts/l1-calls.md#successresultargmapacc). | +| `}],` | | +| `- optionallyRevealedData: [{` | Some values from a private call can be optionally revealed to the 'public world', depending on bools of the private circuit ABI. For some/every private call each 'object' in this 'array' contains the following fields (some of which might be 0, depending on the bools) (note: there might be more efficient ways to encode this data - this is just for illustration): | +| `- - callStackItemHash,` | Serves as a 'lookup key' of sorts. | +| `- - functionSignature,` | | +| `- - emittedPublicInputs: [_, _, _, _],` | | +| `- - vkHash,` | | +| `- - portalContractAddress,` | | +| `- - ` | :question: Discussion needed. We might also need to reveal all the bools to the public kernel snark, so that it may filter out data that doesn't need to be revealed to L1. | +| `- }, ...]` | | +| `- outputCommitments,` | Output state of commitments to be added to `privateDataTree` (up to 64) | +| `- inputNullifiers,` | Output state of nullifiers to be added to `nullifierTree` (up to 64) | +| `},` | | +| `constants: {` | | +| `- oldTreeRoots: {` | | +| `- - privateDataTree,` | must equal value used in private call proof | +| `- - contractTree,` | A recent root of the contract tree (for vk membership checks) | +| `- - l1ResultsTree,` | A recent root of the L1 results tree. This MUST always be populated (even though it's only used when `privatelyExecutedCallback` is nonempty) to hide whether or not this is a callback. To enforce this, the correctness of this value (even if it's unused within thie circui) will be checked by the base rollup circuit. | +| `- },` | | +| `- privateKernelVKTreeRoot` | The root of a little Merkle tree whose leaves are hashes of the private kernel circuit VKs, allowing support for multuple 'sizes' of kernel circuit (i.e. with varying numbers of public inputs) | +| `- isConstructorRecursion`, | Flags whether this entire recursion began with a constructor function. | +| `- isCallbackRecursion`, | Flags whether this entire recursion began with a callback function. | +| `- executedCallback: {` | Only populated (if at all) by the first call in a tx, if that call is a callback AND if the callback's execution doesn't want to be 'hidden' :question: WHY WOULD WE EVER WANT THIS CASE?. This gives details of the callback that's been executed, so the callback and result can be cross-checked against the l1ResultsTree eventually in the Base Rollup Circuit.
We assume the rollup provider will have a record of the contents of each leaf of the l1ResultsTree, so we don't need to provide the data here; the rollup provider can pass it as a private input to the Base Rollup snark. | +| `- - l1ResultHash`, | This will eventually be compared against a leaf of the L1 Callback Tree in the Base Rollup Circuit. | +| `- - l1ResultsTreeLeafIndex`, | Communicates to the rollup provider the correct leaf to prove membership against in the l1ResultsTree. This will eventually be used to lookup a leaf of the L1 Callback Tree in the Base Rollup Circuit. | +| `- },` | | +| `- globals: {` | | +| `- - minTimestamp` | must equal value used in private call proof | +| `- }` | | +| `}` | | +| `isPrivate = true` | Bool. Tells the next kernel circuit that this is a private kernel snark. | +| `isPublic = false` | Bool. Tells the next kernel circuit that this is not a public kernel snark. | +| `isContractDeployment = false` | Bool. Tells the next kernel circuit that this is not a contract deployment kernel snark. | + +## Execution Logic + +- `require(previousKernel.publicInputs.isPublic == false && previousKernel.publicInputs.isContractDeployment == false)` + + +TODO: less nesting! (Or, in practice, we'll modularise this all into neat functions). + +Base case: +* if `start.privateCallCount == 0`: + * Require previous kernel data to be empty. + * Validate that `start.privateCallStack.length == 1 && start.publicCallStack.length == 0 && start.contractDeploymentCallStack.length == 0 && start.l1CallStack.length == 0` + - TBD: to allow the option of a fee payment, we might require `start.privateCallStack.length` to be "1" or "2, where one tx has an `isFeePayment` indicator". We could even allow any number of initial private calls on the stack, but that's a pretty big deviation from the ethereum tx model. + * Pop the only (TBD) `privateCallStackItemHash` off the `start.privateCallStack`. + - If `privateCall.functionSignature.isConstructor == true`: + - then we don't need a signature from the user, since this entire 'callstack' has been instantiated by a Contract Deployment kernel snark (which itself will have been signed by the user). + - Set `constants.isConstructorRecursion := true` - This public input will percolate to, and be checked by. the Contract Deployment Kernel Circuit which calls this constructor. This check is required to prevent a person from circumventing the ECDSA signature check by simply setting `isConstructor = true` when making a private call. If this aggregated kernel snark reaches the rollup circuit without this flag being reset to `false` by the Contract Deployment Kernel Circuit (to say "yes, this kernel was indeed a constructor for a Contract Deployment Kernel Circuit"), then the entire tx will be rejected by the rollup circuit. + - Else: + - Set `constants.isConstructorRecursion := false` + - Verify the ECDSA `signature`, with `message := privateCallStackItemHash` and `signer := privateCall.callContext.msgSender`. + - Validate the `callContext`. Usually the correctness of a callContext is checked between the `privateCall` and all the new calls it makes (see later in this logic). That means for this 'Base case', those checks haven't been done for this `privateCall` (since there was no prior iteration of this kernel circuit to make those checks). + - If `privateCall.isDelegateCall == true || privateCall.isStaticCall == true`: + - Revert - a user cannot make a delegateCall or staticCall. + - Else: + - Assert `privateCall.callContext.storageContractAddress == privateCall.functionSignature.contractAddress` + - If `privateCall.functionSignature.isCallback == true`: + - Set `constants.isCallbackRecursion = true;` - this can only be set in the _first_ call of a recursion. + - We can infer whether the user wants to keep this callback's execution private, or if they want to expose it, from the `privatelyExecutedCallback` private inputs: + - If `privatelyExecutedCallback` is zeroes, then the user doesn't want to execute this callback privately (maybe it interacts with some public state tree data). + - Let `exposeCallback := true;` + - Copy over the `privateCall.publicInputs.executedCallback` data to this snark's output: `constants.executedCallback`. + - Else: + - Let `exposeCallback := false;` + - In which case we'll check the validity of this callback here: + - Extract `{ l1ResultsTreeSiblingPath, callbackStackItem: { callbackPublicKey, successCallback, failureCallback }, callbackPrivateKey } = privateCall.privatelyExecutedCallback;` + - Extract `{ l1ResultHash, l1ResultsTreeLeafIndex } = privateCall.publicInputs.executedCallback;` + - If `l1ResultHash != 0` (success): + - Check the successCallback's `functionSignature` matches the `privateCall`'s: + - `require(successCallback.functionSignature == privateCall.functionSignature)` + - In fact, check the entire callbackCallHash reconciles. + - Also check the `successResultArgMapAcc` reconciles. + - Extract array `positionData = privateCall.privatelyExecutedCallback.l1SuccessResultArgPositions;` + - Extract the underlying results `l1SuccessResultValues = privateCall.privatelyExecutedCallback.l1SuccessResultValues;` + - Reconcile the `privateCall.privatelyExecutedCallback.callbackStackItem.successResultArgMapAcc` against `positionData` (messy computation if using turboplonk). + - `positionData` is probably binary decompositions, so range checks aren't needed. Multiply all the stuff together with the primes (details omitted, since this solution is a stop-gap). No need to prevent duplicate positions here: the app circuit must do that when it makes the initial call. + - Compare the resulting value against `successResultArgMapAcc`. + - Then, for turbo: sum each of the `positionData` 'columns' to get the `position` as a value. For each `position` loop through the `privateCall.publicInputs.customPublicInputs` until reaching the index `i` of the `position`, and then `require(customPublicInputs[i] == l1SuccessResultValue[i]`. What a pain - Bring on ultraplonk! + - Else: + - Check the failureCallback's `functionSignature` matches the `privateCall`'s: + - `require(failureCallback.functionSignature == privateCall.functionSignature)` + - In fact, check the entire callbackCallHash reconciles. + - Let `callbackStackItemHash = hash(callbackStackItem)` + - Let `leafValue = hash(l1ResultHash, callbackStackItemHash)` + - Check membership of the `leafValue` in the `l1ResultsTree` using: + - `l1ResultsTreeLeafIndex` + - `l1ResultsTreeSiblingPath` + - `constants.oldTreeRoots.l1ResultsTree` + - Validate the `callbackPrivateKey`: + - `require(callbackPrivateKey * G = callbackPublicKey)` (for some fixed point `G`). + - Set `callbackNullifier := hash(callbackDatumHash, callbackPrivateKey)` to prevent this callback from being executed again. + - Set `isCallbackRecursion = false;` to hide that this is a callback, and to prevent callback logic being triggered later in the Base Rollup circuit. + - Ensure `constants.executedCallback` is zeroes. + - We don't include the whole `leafValue` in the preimage of the nullifier, to prevent a user maliciously calling the callback twice: once for 'success' and once for 'fail' (although that shouldn't be possible if the 'L1 results copier' circuit works correctly). + - Else: + - Set `isCallbackRecursion = false;` + - Assert `l1ResultHash == 0` + +Recursion: +* If `previousKernel.publicInputs.isPrivate && start.privateCallCount > 0`: + - If `privateCall.functionSignature.isConstructor == true || privateCall.functionSignature.isCallback == true`: + - Revert - only the first call in the kernel recursion can be a constructor or a callback. + * Verify the `previousKernelProof` using the `previousKernelVK` + * Validate that the `previousKernelVK` is a valid private kernel VK with a membership check: + * Calculate `previousKernelVKHash := hash(previousKernelVK);` + * Compute `root` using the `previousKernelVKHash`, `previousKernelVKPath` and `previousKernelVKIndex`. + * Validate that `root == privateKernelVKTreeRoot`. + * Validate consistency of 'starting' and 'previous end' values: + - verify that the `start...` values match the `previousKernelProofPublicInputs.end...` equivalents. (As mentioned in the table above, we might be able to just pass one set of inputs to avoid this cross-checking) + * Validate consistency of values which must remain the same throughout the recursion (when passed from kernel circuit to kernel circuit): + * ensure this kernel circuit's 'constant' public inputs match the `previousKernelProof`'s public inputs. + * E.g. old tree roots. + - Also ensure that any 'append-only' stacks or arrays have the same entries as the previous kernel proof, before pushing more data onto them! + +Verify the next call on the callstack: +* Verify `start.privateCallStack.length > 0` and (if not already done during the 'Base Case' logic above), pop 1 item off of `start.privateCallStack`. +* Validate that `privateCall.functionSignature.isPrivate == true` (otherwise this is the wrong type of kernel circuit to be using). +* Validate that this newly-popped `privateCallStackItemHash` corresponds to the `privateCall` data passed into this circuit: + * Calculate `privateCallPublicInputsHash := hash(privateCall.publicInputs);` + * Verify that `privateCallStackItemHash == hash(privateCall.functionSignature, privateCallPublicInputsHash, privateCall.callContext, etc...)` + * Recall, the structure of a callstack item: + * ```js + privateCall = { + functionSignature: { + contractAddress, + vkIndex, + isPrivate, + isConstructor, + isCallback, + }, + publicInputsHash, + callContext, + isDelegateCall, + isStaticCall, + } + ``` +* Verify the correctness of `(proof, privateCallPublicInputsHash)` using the `vk`. +* Validate the `vk` actually represents the function that is purportedly being executed: + * Extract the `contractAddress` and `vkIndex` from `privateCall.functionSignature`. + * Compute `vkHash := hash(vk)` + * Compute the `vkRoot` of this function's contract using the `vkIndex`, `vkPath`, and `vkHash`. + * Compute the contract's leaf in the `contractTree`: + * Let `leafValue := hash(contractAddress, portalContractAddress, vkRoot)` + * Compute `contractTreeRoot` using the `contractLeafIndex`, `contractPath` and `leafValue`. + * Validate that `contractTreeRoot == constants.oldTreeRoots.contractTree`. +* Validate consistency of the `privateCall`'s `constant` data with that of the kernel circuit's public inputs (and those of the previousKernelProof). I.e.: + * same old tree roots + * same timestamp values, etc. + +Update the `end` values: +* Extract the private call's `outputCommitments` and `inputNullifiers`. + - If `privateCall.isStaticCall == true`: + - Assert that the `outputCommitments` and `inputNullifiers` are empty, since no state changes are allowed for static calls. + - NOTE: although it's technically possible to emulate pure reads from the privateDataTree by creating an output commitment with value equal to the input commitment being nullified (i.e. being 'read') - there's no way for the kernel circuit to 'trust' that the logic of the private circuit actually did a pure read and didn't change state (since everything is private). + - Else, 'silo' the `outputCommitments` and `inputNullifiers` with the contract address of the callContext: `storageContractAddress := privateCall.callContext.storageContractAddress`: + - For each `outputCommitment` in `outputCommitments`: + - `siloedOutputCommitment := hash(storageContractAddress, outputCommitment);` + - For each `inputNullifier` in `inputNullifiers`: + - `siloedInputNullifier := hash(storageContractAddress, inputNullifier);` + - Push those values (`siloedOutputCommitments` and `siloedInputNullifiers`) onto `end.outputCommitments`, `end.inputNullifiers` + - Also push `callbackNullifier` onto `end.inputNullifiers`, if it exists. + * It would be great if these new commitments & nullifiers could be pushed onto the first nonzero element of the `end` lists, so that these `end` lists remain tightly-packed, allowing many more rounds of recursion. Within a circuit, searching for this first nonzero element's index and then pushing to that position will use approx `(3 * 16 + 1) * 256 = 12544` constraints - so `2 * 12544 = 25088` constraints to push both the nullifier and commitment lists. + * n = 256 + * m = 16 + * `n` checks for the first nonzero entry in the `end` list. + * For each of the m nullifiers, loop through the `end` list and conditionally add the nullifier to that position of the `end` list if it's the next nonzero index available. Assuming 3 constraints per iteraction, that's `3mn` constraints. + * So `(3m + 1)n` altogether. (Of course it'll end up being way more in practice). +* Extract the private call's `privateCallStack`, `publicCallStack`, `contractDeploymentCallStack`. + - Validate the call contexts of these calls: + - For each `newCallStackItem` in `privateCallStack`, `publicCallStack`, `contractDeploymentCallStack` and `partialL1CallStack`. + - If `newCallStackItem.functionSignature.contractAddress == 0`: + - Then this `0` is understood to be a call to `address(this)`, which cannot be populated by the app's circuit itself. + - We must mutate the contract address to be that of the `privateCall`. + - Mutation: Set `newCallStackItem.functionSignature.contractAddress = privateCall.functionSignature.contractAddress` + - If `newCallStackItem.isDelegateCall == true`: + - Assert `newCallStackItem.callContext == publicCall.callContext` + - Else: + - Assert `newCallStackItem.callContext.msgSender == publicCall.functionSignature.contractAddress` + - Assert `newCallStackItem.callContext.storageContractAddress == newCallStackItem.functionSignature.contractAddress` + - Validate `partialL1CallStack` and `callbackStack` lengths: + - `require(partialL1CallStack.length == callbackStack.length)` - every L1 call must have a callback entry (even if the callbacks are zeroes). + - For each `partialL1CallStackItem` in the `partialL1CallStack` (index `i`): + - Ensure that the call is being sent to the associated portal contract address, by adding the `portalContractAddress` here: + - Let `l1CallStackItem := keccak(portalContractAddress, partialL1CallStackItem)` + - Validate `publicCall.callbackStack[i]`: + - Let `successCallback = publicCall.callbackStack[i].successCallback` + - Let `failureCallback = publicCall.callbackStack[i].failureCallback` + - Ensure the contract address of each of the two callbacks matches that of the public call: + - TODO: we might actually want to _mutate_ the contractAddress from `0` to the correct address here. `0` initially, because a contract doesn't know its own address, so `0` can mean an instruction to this kernel snark to insert `address(this)` + - `require(successCallback.functionSignature.contractAddress == publicCall.functionSignature.contractAddress)`; + - `require(failureCallback.functionSignature.contractAddress == publicCall.functionSignature.contractAddress)`; + - Calculate the callbackHashes: + - Let `successCallbackHash = hash(successCallback.functionSignature, etc...)` + - Let `failureCallbackHash = hash(failureCallback.functionSignature, etc...)` + - Push the contents of these call stacks onto the kernel circuit's `end.privateCallStack`, `end.publicCallStack`, `end.contractDeploymentCallStack` and `end.l1CallStack`. + - Also push the each `{callbackPublicKey, successCallbackHash, failureCallbackHash}` onto `end.callbackStack`. + - As per the commitments/nullifiers bullet immediately above, it would be nice if these 'pushes' could result in tightly-packed stacks. +- Determine whether any values need to be optionally revealed to the 'public world', by referring to the `publicCall`'s booleans: + - Let `optionallyRevealedData = {};` + - If `privateCall.functionSignature.isConstructor`, set: + - `optionallyRevealedData.callStackItemHash = privateCallStackItemHash;` + - `optionallyRevealedData.vkHash = vkHash;` + - `optionallyRevealedData.emittedPublicInputs = privateCall.publicInputs.emittedPublicInputs;` + - If `privateCall.functionSignature.isCallback && exposeCallback`, set: + - `optionallyRevealedData.functionSignature = privateCall.functionSignature;` + - `optionallyRevealedData.emittedPublicInputs = privateCall.publicInputs.emittedPublicInputs;` + - TODO: consider whether we can get rid of the emittedPublicInputs being emitted by a callback. More [here](../contracts/l1-calls.md#more-details). + - If `isFeePayment`, set: + - `optionallyRevealedData.callStackItemHash = privateCallStackItemHash;` + - `optionallyRevealedData.functionSignature = privateCall.functionSignature;` + - `optionallyRevealedData.emittedPublicInputs = privateCall.publicInputs.emittedPublicInputs;` + - If `payFeeFromL1`, set: + - `optionallyRevealedData.callStackItemHash = privateCallStackItemHash;` + - If `calledFromL1`, set: + - `optionallyRevealedData.callStackItemHash = privateCallStackItemHash;` + - `optionallyRevealedData.functionSignature = privateCall.functionSignature;` + - `optionallyRevealedData.emittedPublicInputs = privateCall.publicInputs.emittedPublicInputs;` + - `optionallyRevealedData.portalContractAddress = portalContractAddress;` // TODO: we need to check this portal contract address is the correct one within this kernel circuit (with a membership check). We need to decide where in L2 this should be stored: either in the contract tree or in the public data tree (e.g. at storage slot 0 for each contract). Argh, it cannot be in the public data tree, because the private kernel circuit cannot access that :heavy_exclamation_mark: + - Push the `optionallyRevealedData` onto the `optionallyRevealedData`. +- Throw an error if any of the stacks is out of room! +* If `end.privateCallStack.length == 0`, set `end.privateCallCount = 0`, else `end.privateCallCount = start.privateCallCount + 1` +* Set `isPrivate := true;` (and the others are false) +* Ensure all unused public inputs (which are _not_ shown in the table above, but will be included in practice so that all kernel snarks have the same public input ABI) are `0`. + + +A private transaction is executed by creating a private Kernel Snark proof over a circuit that contains 1 entry in either `start.privateCallStack` or `start.publicCallStack` or `start.contractDeploymentCallStack` and a valid ECDSA signature. + +Execution finishes when `end.privateCallStack.length == 0`. If this condition is not met, the kernel snark proof is recursively fed into the kernel snark circuit and a new proof is made. \ No newline at end of file diff --git a/circuits/specs/src/architecture/kernel-circuits/public-kernel.md b/circuits/specs/src/architecture/kernel-circuits/public-kernel.md new file mode 100644 index 00000000000..71b040bc25f --- /dev/null +++ b/circuits/specs/src/architecture/kernel-circuits/public-kernel.md @@ -0,0 +1,301 @@ +# Public Kernel Circuit + +The public kernel circuit has a very similar structure to that of the private kernel circuit. + +The public circuit tracks its own call depth. If `start.publicCallCount == 0` , one of two conditions must be met: + +* A valid ECDSA signature is provided by a user (where the message is the callStackItemHash). In this case `msg.sender = user`. +* A valid private kernel proof is provided where `end.privateCallStack.length == 0`. + +Public kernel proofs are generated recursively until `end.publicCallStack.length == 0`. At this point the proof can be included within a rollup circuit. + +## Private inputs ABI + +| Data Type | Description | +| -------- | -------- | +| `signature` | ECDSA signature signed by user (if no private kernel proof has been provided && `start.publicCallCount == 0`, otherwise empty) | +| `start: {` | | +| `- aggregatedProof` | The current aggregated proof state (if any) | +| `- publicCallCount` | How many _public_ calls have been recursively executed so far? | +| `- publicCallStack` | Starting state of public call stack (max depth 64) | +| `- contractDeploymentCallStack` | Starting state of contract deployment call stack (max depth 4?) | +| `- l1CallStack` | Starting state of l1 call stack (max depth 64?) | +| `- callbackStack` | See breakdown in the public inputs ABI in the next table | +| `- optionallyRevealedData` | See breakdown in the public inputs ABI in the next table | +| `- proverRecords` | | +| `- outputCommitments` | Starting state of commitments to be added to `privateDataTree`.
Notice that a public circuit is allowed to add commitments to the privateDataTree. Imagine, for example, a defi-bridge between private L2 and public L2. Then the rollup processor can complete partial commitments (partial commitments can be added to the _public_ data tree), and the completed commitments can be added straight to the private data tree. | +| `- inputNullifiers` | Values being passed-through from the private circuit executions (must be kept constant). Although this MUST be kept constant in the public kernel recursion, shouldn't go in the `constants` object of this ABI, because a more important requirement is for _all_ kernel snarks to have the same public inputs layout, so this needs to live here in `start`/`end` instead. There's a check in each kernel snark to ensure arrays are append-only (and hence unchanged at earlier indices), so constant-ness is ensured. | +| `- publicDataTreeRoot` | The publicDataTree's root _before_ we make any state transitions (as requested in the publicCall being verified within this circuit). | +| `}` | | +| `previousKernel: {` | | +| `- proof` | | +|
- publicInputs = {
  end: start, // copy within circuit.
  constants: {
    oldTreeRoots: {
      privateDataTree,
      contractTree,
    },
    privateKernelVKTreeRoot,
    publicKernelVKTreeRoot,
    initialPublicDataTreeRoot,
    isConstructorRecursion,
    isCallbackRecursion,
    executedCallback: {
      l1ResultHash,
      l1ResultsTreeLeafIndex,
    },
    globals: {
      minTimestamp,
      block.timestamp,
      block.number,
      prevBlock.ethTimestamp,
      prevBlock.ethNumber,
    },
  }
  proverAddress,
  isPrivate,
  isPublic,
  isContractDeployment,
}
| | +| `- vk` | The VK that should be used to verify the `previousKernel.proof`. | +| `- vkIndex` | The leaf index of the `previousKernel.vk`, to accompany the `previousKernel.vkPath` in doing a membership check. | +| `- vkPath` | We can support multiple 'sizes' of kernel circuit (i.e. kernel circuits with varying numbers of public inputs) if we store all of the VKs of such circuits as vkHashes in a little Merkle tree. This path is the sibling path from the `previousKernel.vk`'s leaf to the root of such a tree. | +| `}` | | +| `publicCall: {` | Data relating to the next public callstack item that we're going to pop off the callstack and verify within this snark. Recall we're representing items in the callstack as a `callStackItemHash`. We'll pass the unpacked data here, for validation within this kernel circuit. | +| `- functionSignature,` | 64-bits (see earlier section) | +| `- publicInputs: {...},` | Rather than pass in the `publicInputsHash`, we pass in its preimage here (we'll hash it within this kernel circuit). This is _all_ of the data listed in the Public Circuit ABI's table of public inputs (see earlier section). | +| `- callContext: {...},` | | +| `- isDelegateCall,` | | +| `- isStaticCall,` | | +| `- proof` | The proof for this item of the callstack. We'll be verifying this within this kernel circuit. | +| `- vk` | The full verification key of the public call proof that will be verified within this circuit. (I.e. the proof `start.publicCallStack.pop().proof`) | +| `- vkPath` | The sibling path of the `vk`'s `vkHash` within the aztec contract's 'mini merkle tree'. | +| `- portalContractAddress` | Needed to reconstruct the contract's leaf of the `contractTree`. | +| `- contractLeafIndex` | The leaf index of the contracts tree where this contract's vkTree is stored | +| `- contractPath` | The sibling path from the contract's root (a leaf of the contract tree) to the `oldContractTreeRoot` | +| `- stateReadPaths: [` | :question: Discussion needed. We might also need to reveal all the bools to the public kernel snark, so that it may filter out data that doesn't need to be revealed to L1. | +| `- }, ...]` | :question: Should a callStackItemHash contain a salt, to hide the nature of the call? | +| `- proverRecords` | We need to record info about who generated public proofs and who generated public kernel snarks, so that they may be rewarded for their work. It's not as simple as there being one prover. Proving might be delegated to various people by the rollup processor, so we need to track an array (obvs of some bounded size) with an element for each prover. Each prover record entry in `proverRecords` will be of the form `[proverAddress, totalNumberOfGates]`, where we track the `totalNumberOfGates` this prover has generated proofs over, as an approximation of the work they've done. | +| `- outputCommitments` | Output state of commitments to be added to `privateDataTree`.

Notice that a public circuit is allowed to add commitments to the privateDataTree. Imagine, for example, a defi-bridge between private L2 and public L2. Then the rollup processor can complete partial commitments (partial commitments can be added to the _public_ data tree), and the completed commitments can be added straight to the private data tree. | +| `- inputNullifiers` | Values being passed-through from the private circuit executions (must be kept constant). Although this MUST be kept constant in the public kernel recursion, shouldn't go in the `constants` object of this ABI, because a more important requirement is for _all_ kernel snarks to have the same public inputs layout, so this needs to live here in `start`/`end` instead. There's a check in each kernel snark to ensure arrays are append-only (and hence unchanged at earlier indices), so constant-ness is ensured. | +| `- publicDataTreeRoot` | The root of the public data tree _after_ performing the stateTransitions requested by the publicCall being verified within this circuit. | +| `}` | | +| `constants: {` | | +| `- oldTreeRoots: {` | | +| `- - privateDataTree` | must equal the value used in the final private kernel proof | +| `- - contractTree` | A recent root of the contract tree (for vk membership checks). Must also equal the value used in the final private kernel proof. | +| `- - l1ResultsTree,` | A recent root of the L1 results tree. | +| `- }` | | +| `- privateKernelVKTreeRoot` | must equal the value used in the final private kernel proof | +| `- publicKernelVKTreeRoot` | The root of a little Merkle tree whose leaves are hashes of the public kernel circuit VKs, allowing support for multuple 'sizes' of kernel circuit (i.e. with varying numbers of public inputs). | +| `- initialPublicDataTreeRoot` | The root of the public data tree before _any_ of the calls from the publicCallStack were executed. We need this to demonstrate that we started our recursion using the correct tree. This will be kept the same throughout the recursion. | +| `- isConstructorRecursion`, | Flags whether this entire recursion began with a constructor function. | +| `- isCallbackRecursion`, | Flags whether this entire recursion began with a callback function. | +| `- executedCallback: {` | Only populated (if at all) by the first call in a tx, if that call is a callback AND if the callback's execution doesn't want to be 'hidden'. This gives details of the callback that's been executed, so the callback and result can be cross-checked against the l1ResultsTree eventually in the Base Rollup Circuit.
We assume the rollup provider will have a record of the contents of each leaf of the l1ResultsTree, so we don't need to provide the data here; the rollup provider can pass it as a private input to the Base Rollup snark. | +| `- - l1ResultHash`, | This will eventually be compared against a leaf of the L1 Callback Tree in the Base Rollup Circuit. | +| `- - l1ResultsTreeLeafIndex`, | Communicates to the rollup provider the correct leaf to prove membership against in the l1ResultsTree. This will eventually be used to lookup a leaf of the L1 Callback Tree in the Base Rollup Circuit. | +| `- },` | | +| `- globals: {` | | +| `- - minTimestamp` | must equal value used in private call proof | +| `- - block.timestamp` | aztec block timestamp | +| `- - block.number` | aztec block number | +| `- - prevBlock.ethTimestamp` | Ethereum timestamp of block that contained previous Aztec 3 block | +| `- - prevBlock.ethNumber` | block number of Ethereum block that contained previous Aztec 3 block | +| `- }` | | +| `}` | | +| `proverAddress` | Who is going to be generating the proof for this kernel circuit (any value can be injected here by the prover). This is used to apportion gas rewards. Note: not needed for the private kernel snarks, because they'll always be generated by the fee payer. | +| `isPrivate = false` | Bool. Tells the next kernel circuit that this is not a private kernel snark. | +| `isPublic = true` | Bool. Tells the next kernel circuit that this is a public kernel snark. | +| `isContractDeployment = false` | Bool. Tells the next kernel circuit that this is not a contract deployment kernel snark. | + +## Execution Logic + +:heavy_exclamation_mark: It would be ideal if the number of public inputs of a private kernel and public kernel circuit are the same, so that the below base case and recursion case can use the same verification code path. + +- `require(previousKernel.publicInputs.isPrivate == true NAND previousKernel.publicInputs.isPublic == true)` +- `require(previousKernel.publicInputs.isContractDeployment == false` +- `require(start.publicCallCount == 0)` +* `require(start.publicCallStack.length > 0)` +Base case (verifying a private kernel snark): +* if `(previousKernel.proof && previousKernel.publicInputs.isPrivate)` + - `require(privateCall.functionSignature.isConstructor == false && privateCall.functionSignature.isCallback == false)`: + - only the first call in the kernel recursion can be a constructor or a callback. + * Verify the (`previousKernel.proof`, `previousKernel.publicInputs`) using the `previousKernel.vk`. + * Validate that the `previousKernel.vk` is a valid _private_ kernel VK with a membership check: + * Calculate `previousKernelVKHash := hash(previousKernel.vk)`; + * Compute `root` using the `previousKernelVKHash`, `previousKernel.vkPath` and `previousKernel.vkIndex`. + * Validate that `root == privateKernelTreeRoot`. + * Validate consistency of 'start' and 'previous end' values: + - verify that the `start...` values match the `previousKernel.publicInputs.end...` equivalents. + * Validate consistency of values which must remain the same throughout the recursion (when passed from kernel circuit to kernel circuit): + * ensure this kernel circuit's `constant` public inputs match the `previousKernelProof`'s public inputs. + * E.g. old tree roots. + - Also ensure that any 'append-only' stacks or arrays have the same entries as the previous kernel proof, before pushing more data onto them! +- else: + - This is the first call of the tx. + * Require previous kernel data to be empty. + * Validate that `start.publicCallStack.length == 1 && start.contractDeploymentCallStack.length == 0 && start.l1CallStack.length == 0` + - TBD: to allow the option of a fee payment, we might require `start.publicCallStack.length` to be "1" or "2, where one tx has an `isFeePayment` indicator". We could even allow any number of initial private calls on the stack, but that's a pretty big deviation from the ethereum tx model. + * Pop the only (TBD) `publicCallStackItemHash` off the `start.publicCallStack`. + - If `publicCall.functionSignature.isConstructor == true`: + - then we don't need a signature from the user, since this entire 'callstack' has been instantiated by a Contract Deployment kernel snark (which itself will have been signed by the user). + - Set `isConstructorRecursion := true` - This public input will percolate to, and be checked by. the Contract Deployment Kernel Circuit which calls this constructor. This check is required to prevent a person from circumventing the ECDSA signature check by simply setting `isConstructor = true` when making a private call. If this aggregated kernel snark reaches the rollup circuit without this flag being reset to `false` by the Contract Deployment Kernel Circuit (to say "yes, this kernel was indeed a constructor for a Contract Deployment Kernel Circuit"), then the entire tx will be rejected by the rollup circuit. + - Else: + - Set `isConstructorRecursion := false` + * Verify the ECDSA `signature`, with `message := publicCallStackItemHash` and `signer := publicCall.callContext.msgSender`. + - Validate the `callContext`. Usually the correctness of a callContext is checked between the `publicCall` and all the new calls it makes (see later in this logic). That means for this 'Base case', those checks haven't been done for this `publicCall` (since there was no prior iteration of this kernel circuit to make those checks). + - If `publicCall.isDelegateCall == true || publicCall.isStaticCall == true`: + - Revert - a user cannot make a delegateCall or staticCall. + - Else: + - Assert `publicCall.callContext.storageContractAddress == publicCall.functionSignature.contractAddress` + - If `publicCall.functionSignature.isCallback == true`: + - Set `isCallbackRecursion = true;` - this can only be set in the _first_ call of a recursion. + - Assert `l1ResultHash != 0` + - Copy over the `publicCall.publicInputs.executedCallback` data to this snark's output: `constants.executedCallback`. + - Else: + - Set `isCallbackRecursion = false;` + - Assert `l1ResultHash == 0` +- Set `initialPublicDataTreeRoot := start.publicDataTreeRoot`. + + +Recursion (of public kernel snarks): +* If `previousKernel.publicInputs.isPublic && start.publicCallCount > 0`: + - `require(privateCall.functionSignature.isConstructor == false && privateCall.functionSignature.isCallback == false)`: + - only the first call in the kernel recursion can be a constructor or a callback. + * Verify the `previousKernel.proof` using the `previousKernel.vk` + * Validate that the `previousKernel.vk` is a valid _public_ kernel VK with a membership check: + * Calculate `previousKernelVKHash := hash(previousKernel.vk)`; + * Compute `root` using the `previousKernelVKHash`, `previousKernel.vkPath` and `previousKernel.vkIndex`. + * Validate that `root == publicKernelVKTreeRoot`. + * Validate consistency of 'start' and 'previous end' values: + - verify that the `start...` values match the `previousKernel.publicInputs.end...` equivalents. + * Validate consistency of values which must remain the same throughout the recursion (when passed from kernel circuit to kernel circuit): + * ensure this kernel circuit's 'constant' public inputs match the `previousKernel`'s public inputs. + * E.g. old tree roots. + +Verify the next call on the callstack: +* Verify `start.publicCallStack.length > 0` and (if not already done during the 'Base Case' logic above), pop 1 item off of `start.publicCallStack`. +* Validate that `publicCall.functionSignature.isPrivate == false` (otherwise this is the wrong type of kernel circuit to be using). +* Validate that this newly-popped `publiceCallStackItemHash` corresponds to the `publicCall` data passed into this circuit: + - Calculate the `publicInputsHashPreimage`, given the complexity that 'current' public data wasn't known to the caller at the time they made the call: + - Include all data from `publicCall.publicInputs`, except for the data documented earlier in the Public Circuit ABI section. + * Calculate `publicCallPublicInputsHash := hash(publicInputsHashPreimage);` + * Verify that `publicCallStackItemHash == hash(publicCall.functionSignature, publicCallPublicInputsHash, publicCall.callContext, etc...)` + * Recall, the structure of a callstack item: + * ```js + publicCall = { + functionSignature: { + contractAddress, + vkIndex, + isPrivate, + isConstructor, + isCallback, + }, + publicInputsHash, + callContext, + isDelegateCall, + isStaticCall, + } + ``` +* Verify the correctness of `(proof, publicCallPublicInputsHash)` using the `vk`. +* Validate the `vk` actually represents the function that is purportedly being executed: + * Extract the `contractAddress` and `vkIndex` from `publicCall.functionSignature`. + * Compute `vkHash := hash(vk)` + * Compute the `vkRoot` of this function's contract using the `vkIndex`, `vkPath`, and `vkHash`. + * Compute the contract's leaf in the `contractTree`: + * Let `leafValue := hash(contractAddress, portalContractAddress, vkRoot)` + * Compute `contractTreeRoot` using the `contractLeafIndex`, `contractPath` and `leafValue`. + * Validate that `contractTreeRoot == constants.oldTreeRoots.contractTree`. +* Validate consistency of the `publicCall`'s `constant` data with that of the kernel circuit's public inputs (and those of the previousKernelProof). I.e.: + * same old tree roots + * etc. + + +Update the `end` values: +- Extract the public call's `stateReads`, which will have been populated with current values by the rollup provider (i.e. each transition will be of the form `[storageSlot, current_value`]). + - Extract the contract address of the contract being read from, based on the callContext: `storageContractAddress := publicCall.callContext.storageContractAddress`. + - For each `stateRead` in `stateReads` (loop index `i`): + - Calculate the `stateLeafIndex = hash(storageContractAddress, stateRead.storageSlot)` (this can be thought of as a 'key' in a key:value mapping. The `stateRead.current_value` is the 'value'). + - Check the `current_value` is correct: + - do a membership check with: `leafValue = current_value, leafIndex = stateLeafIndex, siblingPath = stateReadPaths[i]` + - Assert that the calculated root equals `start.publicDataTreeRoot`. +- Extract the public call's `stateTransitions`, which will have been populated with old and new values by the rollup provider (i.e. each transition will be of the form `[storageSlot, old_value, new_value`]). + - Extract the contract address to be used for storage, based on the callContext: `storageContractAddress := publicCall.callContext.storageContractAddress`. + - Let `tempPublicDataTreeRoot := start.publicDataTreeRoot` + - For each `stateTransition` in `stateTransitions` (loop index `i`): + - Calculate the `stateLeafIndex = hash(storageContractAddress, stateTransition.storageSlot)` (this can be thought of as a 'key' in a key:value mapping. The `stateTransition.old_value` is the 'value'). + - Check the old_value is correct: + - do a membership check with: `leafValue = old_value, leafIndex = stateLeafIndex, siblingPath = stateTransitionPaths[i]` + - Assert that the calculated root equals `tempPublicDataTreeRoot`. + - Update the tree with the new_value: + - Hash up the tree using `leafValue = old_value, leafIndex = stateLeafIndex, siblingPath = stateTransitionPaths[i]`. + - Set `tempPublicDataTreeRoot = the newly computed root`. + - Set `end.publicDataTreeRoot = tempPublicDataTreeRoot` +* Extract the public call's `outputCommitments` (recall: a public circuit can indeed output new commitments, much like the claim circuit). + - If `publicCall.isStaticCall == true`: + - Assert that `outputCommitments` is empty, since no state changes are allowed for static calls. + - Else, 'silo' the `outputCommitments` with the contract address of the callContext: `storageContractAddress := publicCall.callContext.storageContractAddress`: + - For each `outputCommitment` in `outputCommitments`: + - `siloedOutputCommitment := hash(storageContractAddress, outputCommitment);` + - Push those values (`siloedOutputCommitments`) onto `end.outputCommitments`. + * See earlier note on how we can push these values onto the end arrays without gaps (i.e. dynamically) +* Calculate new data to push to `proverRecords`: + - Extract `publicCallProverAddress := publicCall.publicInputs.proverAddress`. + - Extract `publicCallNumberOfGates := vk.n` + - Extract `previousKernelProverAddress := previousKernel.publicInputs.proverAddress` + - Extract `previousKernelNumberOfGates := previousKernel.vk.n` + - Below is expensive looping and dynamic pushing within a circuit (O(n^2) stuff). Consider alternatives. + - Find in the `proverRecords` array an entry matching `publicCallProverAddress`. + - If found: increment their `totalNumberOfGates += publicCallNumberOfGates`. + - If not found: push a new record `[publicCallProverAddress, publicCallNumberOfGates]` onto `proverRecords`. + - Find in the `proverRecords` array an entry matching `previousKernelProverAddress`. + - If found: increment their `totalNumberOfGates += previousKernelNumberOfGates`. + - If not found: push a new record `[previousKernelProverAddress, previousKernelNumberOfGates]` onto `proverRecords`. +* Extract the public call's `publicCallStack`, `contractDeploymentCallStack` and `partialL1CallStack`. + - Validate the call contexts of these calls: + - For each `newCallStackItem` in `publicCallStack`, `contractDeploymentCallStack`: + - If `newCallStackItem.isDelegateCall == true`: + - Assert `newCallStackItem.callContext == publicCall.callContext` + - Else: + - Assert `newCallStackItem.callContext.msgSender == publicCall.functionSignature.contractAddress` + - Assert `newCallStackItem.callContext.storageContractAddress == newCallStackItem.functionSignature.contractAddress` + - Validate `partialL1CallStack` and `callbackStack` lengths: + - `require(partialL1CallStack.length == callbackStack.length)` - every L1 call must have a callback entry (even if the callbacks are zeroes). + - For each `partialL1CallStackItem` in the `partialL1CallStack` (index `i`): + - Ensure that the call is being sent to the associated portal contract address, by adding the `portalContractAddress` here: + - Let `l1CallStackItem := keccak(portalContractAddress, partialL1CallStackItem)` + - Validate `publicCall.callbackStack[i]`: + - Let `successCallback = publicCall.callbackStack[i].successCallback` + - Let `failureCallback = publicCall.callbackStack[i].failureCallback` + - Ensure the contract address of each of the two callbacks matches that of the public call: + - `require(successCallback.functionSignature.contractAddress == publicCall.functionSignature.contractAddress)`; + - `require(failureCallback.functionSignature.contractAddress == publicCall.functionSignature.contractAddress)`; + - Calculate the callbackHashes: + - Let `successCallbackHash = hash(successCallback.functionSignature, etc...)` + - Let `failureCallbackHash = hash(failureCallback.functionSignature, etc...)` + - Push the contents of these call stacks onto the kernel circuit's `end.publicCallStack`, `end.contractDeploymentCallStack` and `end.l1CallStack`. + - Also push the each `{callbackPublicKey, successCallbackHash, failureCallbackHash}` onto `end.callbackStack`. + - As per the commitments/nullifiers bullet above, it would be nice if these 'pushes' could result in tightly-packed stacks. +- Determine whether any values need to be optionally revealed to the Contract Deployment kernel circuit, or to L1, by referring to the `publicCall`'s booleans: + - Let `optionallyRevealedData = {};` + - If `publicCall.functionSignature.isConstructor`, set: + - `optionallyRevealedData.callStackItemHash = publicCallStackItemHash;` + - `optionallyRevealedData.vkHash = vkHash;` + - `optionallyRevealedData.emittedPublicInputs = publicCall.publicInputs.emittedPublicInputs;` + - If `publicCall.functionSignature.isCallback`, set: + - `optionallyRevealedData.functionSignature = publicCall.functionSignature;` + - `optionallyRevealedData.emittedPublicInputs = publicCall.publicInputs.emittedPublicInputs;` + - TODO: consider whether we can get rid of the emittedPublicInputs being emitted by a callback. More [here](../contracts/l1-calls.md#more-details). + - If `isFeePayment`, set: + - `optionallyRevealedData.callStackItemHash = publicCallStackItemHash;` + - `optionallyRevealedData.functionSignature = publicCall.functionSignature;` + - `optionallyRevealedData.emittedPublicInputs = publicCall.publicInputs.emittedPublicInputs;` + - If `payFeeFromL1`, set: + - `optionallyRevealedData.callStackItemHash = publicCallStackItemHash;` + - If `calledFromL1`, set: + - `optionallyRevealedData.callStackItemHash = publicCallStackItemHash;` + - `optionallyRevealedData.functionSignature = publicCall.functionSignature;` + - `optionallyRevealedData.emittedPublicInputs = publicCall.publicInputs.emittedPublicInputs;` + - Push the `optionallyRevealedData` onto the `optionallyRevealedData`. +* If `end.publicCallStack.length == 0`, set `end.publicCallCount = 0`, else `end.publicCallCount = start.publicCallCount + 1` +* Set `isPublic := true;` (and the others are false) +* Ensure all unused public inputs (which are _not_ shown in the table above, but will be included in practice so that all kernel snarks have the same public input ABI) are `0`. \ No newline at end of file diff --git a/circuits/specs/src/architecture/rollup-circuits/base-rollup.md b/circuits/specs/src/architecture/rollup-circuits/base-rollup.md new file mode 100644 index 00000000000..246067c1e46 --- /dev/null +++ b/circuits/specs/src/architecture/rollup-circuits/base-rollup.md @@ -0,0 +1,428 @@ + + +# Base rollup circuit + +## Private inputs ABI + +```js +// two input kernel snarks +kernelSnarks: [ + { + proof, + publicInputs: { + end: { + aggregatedProof, + callCount: 0, + privateCallStack: [], // empty + publicCallStack: [], // empty + contractDeploymentCallStack: [], // empty + l1CallStack: [...], + callbackStack: [...], + optionallyRevealedData: [...], + deployedContractData: [...], + proverRecords: [...], + outputCommitments: [...], + inputNullifiers: [...], + publicDataTreeRoot, + contractTreeRoot, + nextAvailableContractTreeLeafIndex, + }, + constants: { + oldTreeRoots: { + privateDataTree, + contractTree, + l1ResultsTree, + }, + privateKernelVKTreeRoot, + publicKernelVKTreeRoot, + initialPublicDataTreeRoot, + initialContractTreeRoot, + initialNextAvailableContractTreeLeafIndex, + isConstructorRecursion, + isCallbackRecursion, + executedCallback: { + l1ResultHash, + l1ResultsTreeLeafIndex, + } + globals: { + minTimestamp, + block.timestamp, + block.number, + prevBlock.ethTimestamp, + prevBlock.ethNumber, + }, + }, + proverAddress, + isPrivate, + isPublic, + isContractDeployment, + }, + kernelType, // enum: private/public/contractDeployment + vk, // must be a kernel snark vk + vkIndex, // in the kernel vk tree + vkPath, // for proving membership of the kernel vk in the kernel vk tree + }, + // and again for the 2nd kernel snark being passed into this base rollup circuit. +], +membershipWitnesses: { + lowNullifiers: [{ + // the leaf data of nullifiers which are 'one smaller' than the + // new nullifiers we'll be inserting. + leafIndex, + leafValue: { + thisValue, + nextValue, + nextIndex, + }, + siblingPath + }, ...], + inputNullifiersBatch: { + // leafValues provided in 'inputNullifiers' input + // leafIndex provided in 'start.nullifierTree.nextAvailableLeafIndex' + siblingPath, // The 'frontier'. The sibling path of the next available leaf + // index. + }, + outputCommitmentsBatch: { + // leafValues provided in 'inputCommitments' input + // leafIndex provided in 'start.privateDataTree.nextAvailableLeafIndex' + siblingPath, // The 'frontier'. The sibling path of the next available leaf + // index. + }, + callbackStackBatch: { + // We'll insert any new callbacks for any new L1 calls. + // leafValues provided in the 'callbackStack' input + // leafIndex provided in 'start.l1ResultsTree.nextAvailableLeafIndex' + siblingPath, // The 'frontier'. The sibling path of the next available leaf + // index. + }, + executedCallbacks: [ + // A witness for each kernel snark. + // If a kernel snark `isCallbackRecursion`, then it'll be referencing some + // L1 Result. This witness allows that purported result to be validated. + { + siblingPath, + callbackStackItem: { + // We need to provide this preimage of a callbackStackItemHash, + // because if a nonzero callbackPublicKey is included, + // then this callback must be validated only by the private + // kernel circuit (not by this circuit). + // Also, we need to validate the function signature of the callback. + callbackPublicKey, + successCallback, + failureCallback, + }, + // The leafIndex is already provided in the kernel snark's public inputs, + // to help the rollup provider to find the correct leaf (and to force the + // correct leaf to be used). + }, + { + siblingPath, + callbackStackItem: {...}, + } + ], + oldPrivateDataTreeRoots: [ + // Two old private data tree roots were given: one for each kernel snark: + { + leafIndex, // of the oldPrivateDataTreeRoot in the privateDataTreeRootsTree + siblingPath, + }, + { + leafIndex, + siblingPath, + }, + ], + oldContractTreeRoots: [ + // Two old contract tree roots were given: one for each kernel snark: + { + leafIndex, // of the oldContractTreeRoot in the contractTreeRootsTree + siblingPath, + }, + { + leafIndex, + siblingPath, + }, + ], + oldL1ResultsTreeRoots: [ + // Two old l1 results tree roots were given: one for each kernel snark: + { + leafIndex, // of the oldL1ResultsTreeRoot in the l1ResultsTreeRootsTree + siblingPath, + }, + { + leafIndex, + siblingPath, + }, + ], + endPrivateDataTreeRoot: { + siblingPath, + }, + endContractTreeRoot: { + siblingPath, + }, +}, +``` + +## Public inputs ABI + +```js +start: { + nullifierTree: { + root, + nextAvailableLeafIndex, + }, + privateDataTree: { + root, + nextAvailableLeafIndex, + }, + privateDataTreeRootsTree: { + root, + nextAvailableLeafIndex, + }, + publicDataTree: { + root, + }, + contractTree: { + root, + nextAvailableLeafIndex, + }, + contractTreeRootsTree: { + root, + nextAvailableLeafIndex, + }, + l1ResultsTree: { + root, + nextAvailableLeafIndex, + }, + l1ResultsTreeRootsTree: { + root, + nextAvailableLeafIndex, + }, +}, +end: { + nullifierTree: { + root, + nextAvailableLeafIndex, + }, + privateDataTree: { + root, + nextAvailableLeafIndex, + }, + privateDataTreeRootsTree: { + root, + nextAvailableLeafIndex, + }, + publicDataTree: { + root, + }, + contractTree: { + root, + nextAvailableLeafIndex, + }, + contractTreeRootsTree: { + root, + nextAvailableLeafIndex, + }, + l1ResultsTree: { + root, + nextAvailableLeafIndex, + }, + l1ResultsTreeRootsTree: { + root, + nextAvailableLeafIndex, + }, +}, +constants: { + privateKernelVKTreeRoot, + publicKernelVKTreeRoot, + baseRollupVKHash, + mergeRollupVKHash, +}, +l1CallStack: [...], // combined from both input kernel snarks' public inputs +optionallyRevealedData: [{ + callStackItemHash, + functionSignature, + emittedPublicInputs: [_, _, _, _], + vkHash, + portalContractAddress, + , +},...], // combined from both input kernel snarks' public inputs +proverRecords: [{ + proverAddress, + totalNumberOfGates, +},...], // combined from both input kernel snarks' public inputs +proverAddress, +minMinTimestamp, // the min of the minTimestamps passed to this circuit +maxMinTimestamp, // the max of the minTimestamps passed to this circuit +``` + + +## Execution Logic + +We'll do a few things in the circuit: +- Verify the two kernel snarks +- Merge some arrays from both inputs +- Check some tree stuff +- Check the public inputs of both kernel snarks based on the ordering: + - `kernelSnarks[0]` happened first + - `kernelSnarks[1]` happened second + +So: +- the base rollup circuit's `start` tree data must line up with the `initial...` tree data of `kernelSnarks[0]`. +- the `end` tree data of `kernelSnarks[0]` must line up with the `initial...` tree data of `kernelSnarks[1]`. +- the `end` tree data of `kernelSnarks[1]` must line up with the base rollup circuit's `end` tree data. + +Here we go... + +- For `i in [0, 1]`: + - If `kernelSnarks[i].publicInputs.constants.isConstructorRecursion == true`: + - Revert. A constructor kernel can only be verified by the contractDeployment kernel snark. + - Verify `(kernelSnarks[i].proof, kernelSnarks[i].publicInputs)` against the vk `kernelSnarks[i].vk`. + - Validate that the `kernelSnarks[i].vk` is a valid kernel snark of the correct `kernelSnarks[i].kernelType` with a membership check of the relevent kernel snark vk tree: + - Calculate `kernelVKHash := hash(kernelSnarks[i].vk)`; + - Compute `root` using the `kernelVKHash`, `kernelSnarks[i].vkPath` and `kernelSnarks[i].vkIndex`. + - Validate that `root == constants.KernelVKTreeRoot`. + +Validate that the callStacks of both kernel snarks were all completed (are all empty): +- For `i in [0, 1]`: + - `require(callCount == 0);` + - Require all values of `privateCallStack`, `publicCallStack`, `contractDeploymentCallStack` to be `0`. + +Check the old tree roots (that were referred-to by the users' circuits) have actually existed (at some point in history) as the root of their tree: +- For `i in [0, 1]`: + - Check the old private data tree root once existed: + - Calculate `root` using: `leafValue: kernelSnarks[i].publicInputs.constants.oldTreeRoots.privateDataTree, leafIndex: membershipWitnesses.oldPrivateDataTreeRoots[i].leafIndex, siblingPath: membershipWitnesses.oldPrivateDataTreeRoots[i].siblingPath`. + - `assert(root == start.privateDataTreeRootsTree.root` + - Check the old contract tree root once existed: + - Calculate `root` using: `leafValue: kernelSnarks[i].publicInputs.constants.oldTreeRoots.contractTree, leafIndex: membershipWitnesses.oldContractTreeRoots[i].leafIndex, siblingPath: membershipWitnesses.oldContractTreeRoots[i].siblingPath`. + - `assert(root == start.contractTreeRootsTree.root` + - Check the old L1 results tree root once existed: + - Calculate `root` using: `leafValue: kernelSnarks[i].publicInputs.constants.oldTreeRoots.l1ResultsTree, leafIndex: membershipWitnesses.oldL1ResultsTreeRoots[i].leafIndex, siblingPath: membershipWitnesses.oldL1ResultsTreeRoots[i].siblingPath`. + - `assert(root == start.contractTreeRootsTree.root` + +Check the alignment of the start and end states of the two trees which were updated _within the kernel snarks_ (the publicDataTree and the contractTree). This ensures the kernel snarks didn't make any unexpected changes to those trees: + +- `start -> kernelSnarks[0]`: + - `require(start.publicDataTree.root == kernelSnarks[0].publicInputs.constants.initialPublicDataTreeRoot);` + - `require(start.contractTree.root == kernelSnarks[0].publicInputs.constants.initialContractTreeRoot);` + - `require(start.contractTree.nextAvailableLeafIndex == kernelSnarks[0].publicInputs.constants.initialNextAvailableContractTreeLeafIndex);` +- `kernelSnarks[0] -> kernelSnarks[1]`: + - `require(kernelSnarks[0].publicInputs.end.publicDataTreeRoot == kernelSnarks[1].publicInputs.constants.initialPublicDataTreeRoot);` + - `require(kernelSnarks[0].publicInputs.end.contractTreeRoot == kernelSnarks[1].publicInputs.constants.initialContractTreeRoot);` + - `require(kernelSnarks[0].publicInputs.end.nextAvailableContractTreeLeafIndex == kernelSnarks[1].publicInputs.constants.initialNextAvailableContractTreeLeafIndex);` +- `kernelSnarks[1] -> end`: + - `require(kernelSnarks[1].publicInputs.end.publicDataTreeRoot == end.publicDataTree.root);` + - `require(kernelSnarks[1].publicInputs.end.contractTreeRoot == end.contractTree.root);` + - `require(kernelSnarks[1].publicInputs.end.nextAvailableContractTreeLeafIndex == end.contractTree.nextAvailableLeafIndex);` + +Merge input stacks/arrays to create single output stacks/arrays: +- `assert(l1CallStack == [...kernelSnarks[0].publicInputs.end.l1CallStack, ...kernelSnarks[1].publicInputs..end.l1CallStack]);` +- `assert(optionallyRevealedData == [...kernelSnarks[0].publicInputs..end.optionallyRevealedData, ...kernelSnarks[1].publicInputs.end.optionallyRevealedData]);` +- `assert(deployedContractData == [...kernelSnarks[0].publicInputs..end.deployedContractData, ...kernelSnarks[1].publicInputs.end.deployedContractData]);` + + +If either of the kernel snarks was a callback execution, check that their purported L1 Result is correct (i.e. that it exists in the L1 results tree). +We do this here, in the base rollup circuit rather than the public kernel circuit, because this only needs to be done at most once per tx, so it'd be wasteful to repeat this calc in every kernel recursion. Having said that, the _private_ kernel circuit does also offer this functionality, so that a user may hide which callback they're calling (and even the fact they're executing a callback at all). +This logic MUST come before the 'nullifier insertion' logic, because we add a new nullifier to the set here. +- Let `callbackNullifiers = []` +- For `i in [0, 1]`: + - If `kernelSnarks[i].publicInputs.constants.isCallbackRecursion` + - `require(l1ResultHash != 0)` to prevent a user executing a callback which refers to a _pending_ result. + - Extract `{ l1ResultHash, l1ResultsTreeLeafIndex } = kernelSnarks[i].publicInputs.constants.executedCallback;` + - Extract `{ callbackStackItem: { callbackPublicKey, successCallback, failureCallbac } } = membershipWitnesses.executedCallbacks[i];` + - Extract the function signature of the callback which was called (this will always be at the 0th position of the optionallyRevealedData): + - Let `executedCallbackFunctionSignature = kernelSnarks[i].publicInputs.end.optionallyRevealedData[0].functionSelector`. + - `require(executedCallbackFunctionSignature != 0)` + - Let `executedCallbackEmittedPublicInputs = kernelSnarks[i].publicInputs.end.optionallyRevealedData[0].emittedPublicInputs`. + - If `l1ResultHash != 0` (success): + - Check the successCallback's `functionSignature` matches the kernel snark's: + - `require(successCallbackHash.functionSignature == executedCallbackFunctionSignature)` + - In fact, check the entire successCallbackCallHash + - Else: + - Check the failureCallbackHash's `functionSignature` matches the kernel snark's: + - `require(failureCallbackHash.functionSignature == executedCallbackFunctionSignature)` + - In fact, check the entire successCallbackCallHash + - `require(callbackPublicKey == 0)`, otherwise this callback should have been processed in the private kernel snark. + - Let `callbackStackItemHash := hash(callbackPublicKey, callbackStackItem.successCallbackHash, callbackStackItem.failureCallbackHash)` + - Let `leafValue = hash(l1ResultHash, callbackStackItemHash);` + - Check membership of the `leafValue` in the `l1ResultsTree` using: + - `l1ResultsTreeLeafIndex` + - `membershipWitnesses.executedCallbacks[i].siblingPath` + - `kernelSnarks[i].publicInputs.constants.oldTreeRoots.l1ResultsTree` + - Set `callbackNullifiers[i] := hash(callbackStackItemHash, callbackPrivateKey = 0)` to prevent this callback from being executed again. + - We don't include the whole `leafValue` in the preimage of the nullifier, to prevent a user maliciously calling the callback twice: once for 'success' and once for 'fail' (although that shouldn't be possible if the 'L1 results copier' circuit works correctly). + - The `callbackPrivateKey` only gets used if the callback is executed privately (in which case all of the checks of this section are done in the private kernel circuit. The private kernel circuit would then toggle the `isCallbackRecursion` to `false`, to hide the fact that it's a callback, and so that this section is skipped within this circuit). + +Add new pending callbacks to the l1ResultsTree: +- Let `pendingResultLeafValues = [];` +- For `i in [0, 1]` + - For each `callbackStackItem in kernelSnarks[i].publicInputs.end.callbackStack`. + - Set `pendingResultLeafValues.push( callbackStackItemHash )` ("pendingResult", because "finalisation" of the leaf happens once the L1 results are added in the next rollup). +- Batch-insert the `pendingResultLeafValues`, using: + - `start.l1ResultsTree.nextAvailableLeafIndex` + - `start.l1ResultsTree.root` (to reconcile the starting root before adding more leaves) + - `end.l1ResultsTree.nextAvailableLeafIndex` + - `end.l1ResultsTree.root` + - `membershipWitnesses.callbackStackBatch` + + + +Add the inputNullifiers and outputCommitments to their trees: +- Merge the arrays from the two input kernel snarks: + - Let `inputNullifiers := [...kernelSnarks[0].publicInputs.end.inputNullifiers, ...kernelSnarks[1].publicInputs.end.inputNullifiers]`; + - Let `outputCommitments := [...kernelSnarks[0].publicInputs.end.outputCommitments, ...kernelSnarks[1].publicInputs.end.outputCommitments]`; + +Nullifiers: +- Let `inputNullifierLeafIndex := start.nullifierTree.nextAvailableLeafIndex` +- Let `rootBeforeInsertion := start.nullifierTree.root` +- For each `inputNullifier` in `inputNullifiers` (index `i`): + - Do a non-membership check, using: + - `membershipWitnesses.lowNullifiers[i]` (to validate `rootBeforeInsertion`) + - `inputNullifiers[i]` to validate non-membership. + - See the hackmd for the new nullifier tree info. + - Update all of the `lowNullifiers[i].leafValue.nextValue` and `lowNullifiers[i].leafValue.nextIndex` values, using: + - `membershipWitnesses.lowNullifiers[i]` + - `inputNullifiers[i]` to update the 'next' values. + - Batch-insert the new `inputNullifiers`, using: + - `start.nullifierTree.nextAvailableLeafIndex` + - `start.nullifierTree.root` (to reconcile the starting root before adding more leaves) + - `end.nullifierTree.nextAvailableLeafIndex` + - `end.nullifierTree.root` + - `membershipWitnesses.inputNullifiersBatch` + +Commitments: +- Batch-insert `outputCommitments` (and validate start and end tree states) using: + - `start.privateDataTree.nextAvailableLeafIndex` + - `start.privateDataTree.root` (to reconcile the starting root before adding more leaves) + - `end.privateDataTree.nextAvailableLeafIndex` + - `end.privateDataTree.root` + - `membershipWitnesses.outputCommitmentsBatch` + + +Update the (difficultly-named) trees whose leaves are the roots of historic trees. I.e. add the newly-calculated roots as the 'latest' roots of the historic trees (`privateDataTreeRootsTree`, `contractTreeRootsTree`, `l1ResultsTreeRootsTree`). + +- Insert the newly-calculated `end.privateDataTree.root` as a new leaf in the `privateDataTreeRootsTree` using: + - `membershipWitnesses.endPrivateDataTreeRoot.siblingPath` + - `start.privateDataTreeRootsTree.nextAvailableLeafIndex` + - `start.privateDataTreeRootsTree.root` + - `end.privateDataTreeRootsTree.nextAvailableLeafIndex` + - `end.privateDataTreeRootsTree.root` + +- Insert the newly-calculated `end.contractTree.root` as a new leaf in the `contractTreeRootsTree` using: + - `membershipWitnesses.endContractTreeRoot.siblingPath` + - `start.contractTreeRootsTree.nextAvailableLeafIndex` + - `start.contractTreeRootsTree.root` + - `end.contractTreeRootsTree.nextAvailableLeafIndex` + - `end.contractTreeRootsTree.root` + +- Insert the newly-calculated `end.l1ResultsTree.root` as a new leaf in the `l1ResultsTreeRootsTree` using: + - `membershipWitnesses.endl1ResultsTreeRoot.siblingPath` + - `start.l1ResultsTreeRootsTree.nextAvailableLeafIndex` + - `start.l1ResultsTreeRootsTree.root` + - `end.l1ResultsTreeRootsTree.nextAvailableLeafIndex` + - `end.l1ResultsTreeRootsTree.root` + +* Calculate new data to push to `proverRecords`: + - Calculate new prover record data from both input kernelSnarks, using the `proverAddress` and `vk` of the kernel snarks' `publicInputs` (see detailed logic in the kernel snarks' 'execution logic' sections). + - Push that data onto the `proverRecords` array. \ No newline at end of file diff --git a/circuits/specs/src/architecture/rollup-circuits/l1-results-copier.md b/circuits/specs/src/architecture/rollup-circuits/l1-results-copier.md new file mode 100644 index 00000000000..69223c168be --- /dev/null +++ b/circuits/specs/src/architecture/rollup-circuits/l1-results-copier.md @@ -0,0 +1,55 @@ +# L1 Results Copier Circuit + +See the [L2 --> L1 calls](../contracts/l1-calls.md#l2----l1-calls) section for motivation. + +This circuit copies results of L1 calls (which were executed by the _previous_ rollup) to the `l1ResultsTree` on L2. It will effectively be updated _before_ any other state changes of this next rollup, so that the results are available for txs (callbacks) in this rollup to use. + +This is a generalisation of how the root rollup circuit adds defi interaction notes to the defi tree. + +> TODO: consider whether we can safely make execution of this circuit _optional_, so that several sequential rollups can be computed in parallel (meaning much faster rollup throughput). I.e. if we don't force the very next rollup to copy over results data, then the very next rollup (and the one after that, and so on) can start to be computed before the L1 txs are finalised, for mega fast throughput. Every now and then, a rollup provider could include an 'L1 results copy proof'... we just need to incentivise it so that copying actually happens, whenever possible. + +> Note: I've separated this circuit for ease of reading, and because (as the above note suggests) we might not need to do this copying for _every_ rollup. + + +## Private Inputs ABI + +```js +subtreeMembershipWitness: { + siblingPath, +}, +pendingResultLeafValues: [...], +l1Results: [...], +``` + +## Public Inputs ABI + +```js +start: { + l1ResultsTree: { + root, + firstPendingResultLeafIndex, + }, +}, +end: { + l1ResultsTree: { + root, + firstPendingResultLeafIndex, + }, +}, +l1ResultsHash, +``` + + +## Execution Logic + +- `assert(l1Results.length == pendingResultLeafValues.length)`. +- Calculate the 'subroot' of the batch of 'pending' leaves (using `pendingResultLeafValues`) before updating them. +- Recalculate the `start.l1ResultsTree.root` using the calculated subroot and the membership witness `subtreeMembershipWitness.siblingPath` and `start.l1ResultsTree.firstPendingResultLeafIndex`, and assert that the calculated root matches `start.l1ResultsTree.root`. + - This step confirms that the pending leaf hashes (`pendingResultLeafValues`) are correct. +- 'Finalise' each pending leaf: + - Let `updatedLeaves[i] := hash(l1Results[i].l1ResultHash, pendingResultLeafValues[i])` + - Note: `l1ResultHash = 0` for any failed L1 calls. +- Update the tree with the batch of completed leaves using the `subtreeMembershipWitness.siblingPath` and `start.l1ResultsTree.firstPendingResultLeafIndex`. +- Let `end.l1ResultsTree.firstPendingResultLeafIndex = start.l1ResultsTree.firstPendingResultLeafIndex + l1Results.length` +- Hash all of the results (using the expensive sha256 hash) so that it may be checked on-chain: + - `l1ResultsHash = sha256(...l1Results.map(r => r.l1ResultHash));` diff --git a/circuits/specs/src/architecture/rollup-circuits/merge-rollup.md b/circuits/specs/src/architecture/rollup-circuits/merge-rollup.md new file mode 100644 index 00000000000..b70b5b3a44a --- /dev/null +++ b/circuits/specs/src/architecture/rollup-circuits/merge-rollup.md @@ -0,0 +1,155 @@ +# Merge rollup circuit + +## Private inputs ABI + +```js +// two input rollup snarks (can be EITHER a BASE or a MERGE snark). +rollupSnarks: [ + { + proof, + publicInputs: { + // public inputs of a ROLLUP snark (BASE or MERGE - they have the same layout) + }, + rollupType, // enum: base/merge + vk, // must be a rollup snark vk + }, + // and again for the 2nd rollup snark being passed into this base rollup circuit. +], +``` + +## Public inputs ABI + +Exactly the same as the BASE rollup snark. +```js +start: { + nullifierTree: { + root, + nextAvailableLeafIndex, + }, + privateDataTree: { + root, + nextAvailableLeafIndex, + }, + privateDataTreeRootsTree: { + root, + nextAvailableLeafIndex, + }, + publicDataTree: { + root, + }, + contractTree: { + root, + nextAvailableLeafIndex, + }, + contractTreeRootsTree: { + root, + nextAvailableLeafIndex, + }, + l1ResultsTree: { + root, + nextAvailableLeafIndex, + }, + l1ResultsTreeRootsTree: { + root, + nextAvailableLeafIndex, + }, +}, +end: { + nullifierTree: { + root, + nextAvailableLeafIndex, + }, + privateDataTree: { + root, + nextAvailableLeafIndex, + }, + privateDataTreeRootsTree: { + root, + nextAvailableLeafIndex, + }, + publicDataTree: { + root, + }, + contractTree: { + root, + nextAvailableLeafIndex, + }, + contractTreeRootsTree: { + root, + nextAvailableLeafIndex, + }, + l1ResultsTree: { + root, + nextAvailableLeafIndex, + }, + l1ResultsTreeRootsTree: { + root, + nextAvailableLeafIndex, + }, +}, +constants: { + privateKernelVKTreeRoot, + publicKernelVKTreeRoot, + baseRollupVKHash, + mergeRollupVKHash, +}, +l1CallStack: [...], // combined from both input kernel snarks' public inputs +optionallyRevealedData: [{ + callStackItemHash, + functionSignature, + emittedPublicInputs: [_, _, _, _], + vkHash, + portalContractAddress, + , +},...], // combined from both input kernel snarks' public inputs +proverRecords: [{ + proverAddress, + totalNumberOfGates, +},...], // combined from both input kernel snarks' public inputs +proverAddress, +minMinTimestamp, // the min of the minTimestamps passed to this circuit +maxMinTimestamp, // the max of the minTimestamps passed to this circuit +``` + + +## Execution Logic + +We'll do a few things in the circuit: +- Verify the two input ROLLUP snarks +- Merge some arrays from both inputs +- Check the public inputs of both rollup snarks based on the ordering: + - `rollupSnarks[0]` happened first + - `rollupSnarks[1]` happened second + - I.e. the `end` data of `rollupSnarks[0]` must line up with the `start` data of `rollupSnarks[1]` + +Here we go... + +- Validate that either both inputs are a BASE snark or both inputs are a MERGE snark. You can't mix the two. + - `assert((rollupSnarks[0].rollupType == 'base' && rollupSnarks[1].rollupType == 'base') ^ (rollupSnarks[0].rollupType == 'merge' && rollupSnarks[1].rollupType == 'merge')`: +- For `i in [0, 1]`: + - Verify `(rollupSnarks[i].proof, rollupSnarks[i].publicInputs)` against the vk `rollupSnarks[i].vk`. + - Validate that the `rollupSnarks[i].vk` is a valid base/merge snark: + - Let `vkHash := hash(rollupSnarks[i].vk)` + - If `rollupSnarks[i].rollupType == 'base'`: + - `assert(vkHash == constants.baseRollupVKHash)` + - Else (`rollupSnarks[i].rollupType == 'merge'`): + - `assert(vkHash == constants.mergeRollupVKHash)` + +Ensure constants are kept constant. +- Assert that all items in `constant` are the same between the two input rollup snarks: + - `assert(rollupSnarks[0].publicInputs.constants == rollupSnarks[1].publicInputs.constants)` +- Assert that the input `constant` are the same as the output `constant` + - `assert(rollupSnarks[0].publicInputs.constants == constants)` + +Check that the `end` data of `rollupSnarks[0]` lines up with the `start` data of `rollupSnarks[1]` +- `assert(rollupSnarks[0].end == rollupSnarks[1].start)` + + +Merge input stacks/arrays to create single output stacks/arrays: +- `assert(l1CallStack == [...rollupSnarks[0].publicInputs.l1CallStack, ...rollupSnarks[1].publicInputs.l1CallStack]);` +- `assert(optionallyRevealedData == [...rollupSnarks[0].publicInputs.optionallyRevealedData, ...rollupSnarks[1].publicInputs.optionallyRevealedData]);` +- `assert(deployedContractData == [...rollupSnarks[0].publicInputs.deployedContractData, ...rollupSnarks[1].publicInputs.deployedContractData]);` + +* Calculate new data to push to `proverRecords`: + - Calculate new prover record data from both input rollupSnarks, using the `proverAddress` and `vk` of the rollup snarks' `publicInputs` (see detailed logic in the kernel snarks' 'execution logic' sections). + - Push that data onto the `proverRecords` array. \ No newline at end of file diff --git a/circuits/specs/src/architecture/rollup-circuits/rollup-circuits.md b/circuits/specs/src/architecture/rollup-circuits/rollup-circuits.md new file mode 100644 index 00000000000..ff4b216734d --- /dev/null +++ b/circuits/specs/src/architecture/rollup-circuits/rollup-circuits.md @@ -0,0 +1,7 @@ +# Rollup circuit + +Takes two snarks, checks they're correct, and does a 'subtree' of state updating for the various trees. Eventually, 2^k kernel snarks will have been verified in a 'rollup tree' of height k, where the root of the rollup tree is a single rollup snark representing 2^k transactions. + +There are two kinds of rollup circuit: +- 'Base' rollup circuit: Verify two kernel snarks. +- 'Merge' rollup circuit: Verify two rollup snarks (can be either two 'base' snarks or two 'merge' snarks), 'merging' them into 1 rollup snark. \ No newline at end of file diff --git a/circuits/specs/src/architecture/rollup-circuits/standard-plonk-converter.md b/circuits/specs/src/architecture/rollup-circuits/standard-plonk-converter.md new file mode 100644 index 00000000000..1810e4aa536 --- /dev/null +++ b/circuits/specs/src/architecture/rollup-circuits/standard-plonk-converter.md @@ -0,0 +1,4 @@ +# Standard Plonk Converter Circuit + +Converts the final Merge Rollup Snark from HONK! format into Standard Plonk format (for cheaper on-chain verification). +This will be similar to the 'root verifier' circuit of Aztec Connect. It's just renamed for clarity. \ No newline at end of file diff --git a/circuits/specs/src/examples/erc20/appendix/appendix.md b/circuits/specs/src/examples/erc20/appendix/appendix.md new file mode 100644 index 00000000000..bf16fad24a2 --- /dev/null +++ b/circuits/specs/src/examples/erc20/appendix/appendix.md @@ -0,0 +1,3 @@ +# Appendix + +Extra reference materials to support the explanations in this section. diff --git a/circuits/specs/src/examples/erc20/appendix/portal-contract.md b/circuits/specs/src/examples/erc20/appendix/portal-contract.md new file mode 100644 index 00000000000..4096e19c9af --- /dev/null +++ b/circuits/specs/src/examples/erc20/appendix/portal-contract.md @@ -0,0 +1,198 @@ +## Example Portal Contract + +Here's an example (in pseudocode) of what the Portal Contract for our ERC20 shielding application might look like: + + + + + + +```js +import IERC20 from '...'; +import IRollupProcessor from '...'; + +contract ERC20Shield { + + IRollupProcessor rollupProcessor; + uint32 public immutable l2ContractAddress; + bytes public immutable l2DepositFunctionSignature; + + struct PendingDepositDatum { + address depositorAddress; + address depositCurrency; + uint256 amount; + } + + // l2CallHash => PendingDepositDatum[] (dynamic to allow for duplicate calls) + mapping(uint256 => PendingDepositDatum[]) public pendingDepositData; + + modifier onlyRollupProcessor { + require( + msg.sender == address(rollupProcessor), + "Only the rollup processor can call this function." + ); + _; + } + + constructor ( + address _rollupProcessorAddress, + uint32 _l2ContractAddress, + bytes _l2DepositFunctionSignature + ) { + rollupProcessor = IRollupProcessor(rollupProcessorAddress); + l2ContractAddress = _l2ContractAddress; + l2DepositFunctionSignature = _l2DepositFunctionSignature; + } + + + /******************************************************************************** + * DEPOSIT FUNCTIONS + *******************************************************************************/ + + /** + * ERC20 token example only (not ETH). + * The user MUST have called `approve` in the ERC20 contract of the token they + * wish to deposit (and the fee contract), so that funds may be transferred by + * this function. + * Q: can the user pass a signed 'approve' tx blob as calldata instead? + */ + function deposit( + uint256 amount, // amount to deposit + address depositCurrency, // currency of the deposit + + uint256 l2Fee, + address l2FeeCurrency, // currency of the fee + uint256 l2CallHash, // a callStackItemHash + ) external { + IERC20 depositContract = IERC20(depositCurrency); + IERC20 feeContract = IERC20(l2FeeCurrency); + + depositContract.transferFrom(msg.sender, address(this), amount); + + // At the moment two fee transfers happen: + // - From the user to the portal contract + // - From the portal contract to the RollupProcessor contract. + // The idea being, maybe we can avoid the user ever interacting with (and + // giving 'approvals' to) the rollup contract directly. BUT, that's expensive + // and perhaps wasteful. + feeContract.transferFrom(msg.sender, address(this), l2Fee); + feeContract.increaseAllowance(address(rollupProcessor), l2Fee); + + // Record the data about the deposit (indexed by the l2CallHash), for when + // the callBack is executed later. + PendingDepositDatum memory pendingDeposit = PendingDepositDatum({ + depositorAddress: msg.sender, + depositCurrency, + amount, + }); + pendingDepositData[l2CallHash].push(pendingDeposit); + + // Will be hardcoded function selectors. + bytes24 callback = // concat(address(this), functionSelector); + bytes24 callbackOnCancel = // concat(address(this), functionSelector); + + // Call the RollupProcessor contract: + rollupProcessor.callL2AndPayFee( + l2CallHash, + callback, + callbackOnCancel, + l2Fee, + l2FeeCurrency, + ); + } + + /** + * Finalise a deposit tx in response to the L2 tx being processed. + * @notice these @params are _rigidly_ dictated by the RollupProcessor's + * interface, since it's _always_ the RollupProcessor which calls this. + */ + function depositCallback( + uint256 l2CallHash, + uint256 callIndex, + bytes functionSignature, + uint256[4] emittedPublicInputs, + ) external onlyRollupProcessor { + // First check that the function which was executed on L2 was _actually_ + // the 'deposit' circuit of the L2 contract which is actually associated with + // this portal contract: + require( + functionSignature == l2DepositFunctionSignature, + "The wrong function was executed on L2!" + ); + + // Retrieve the pending deposit data: + PendingDepositDatum memory pendingDeposit = + pendingDepositData[l2CallHash][callIndex]; + + // The portal contract will receive all emittedPublicInputs (that were + // emitted by the circuit). It's up to the portal contract to interpret + // these numbers in an app-specific way. + uint256 amount = emittedPublicInputs[0]; // for example + // This example ignores the other emittedPublicInputs. + + require( + amount == pendingDeposit.amount, + "The amount deposited on L2 does not match the amount deposited on L1!" + ); + + // Delete the pending deposit (as it's now finalised): + delete pendingDepositData[l2CallHash][callIndex]; + } + + /** + * Called if the L2 tx is cancelled in the RollupProcessor. + * @notice these @params are _rigidly_ dictated by the RollupProcessor's + * interface, since it's _always_ the RollupProcessor which calls this. + */ + // TODO: NOT SURE IF AN L1 -> L2 CALL SHOULD BE CANCELLABLE! (The rollup might + // already be in-flight before the cancellation). + function depositCancellationCallback( + uint256 l2CallHash, + uint256 callIndex, + ) external onlyRollupProcessor { + + // Retrieve the pending deposit data: + PendingDepositDatum memory pendingDeposit = + pendingDepositData[l2CallHash][callIndex]; + + // Return the deposit back to the user: + IERC20 erc20 = IERC20(pendingDeposit.depositCurrency); + erc20.transfer(pendingDeposit.depositorAddress, pendingDeposit.amount); + + // Delete the pending deposit (as it's now been cancelled): + delete pendingDepositData[l2CallHash][callIndex]; + } + + /******************************************************************************** + * No need for a transfer function. Private transfers don't interact with L1 state. + *******************************************************************************/ + + /******************************************************************************** + * WITHDRAWAL FUNCTIONS + *******************************************************************************/ + + // NOTE: the RollupProcessor MUST NOT call functions of portal contracts unless + // the corresponding snark was verified as true. + function withdraw( + address msgSender, // not to be confused with msg.sender. + // This is the original user's address. + calldata userWithdrawalSignature, + address erc20Address, + address to, + uint256 amount + ) external onlyRollupProcessor returns (bool success) { + // Check withdrawal signature (that this user _actually_ wants to perform this action). + // The rollup processor has already checked the circuit logic; that this user has sufficient funds. + IERC20 erc20 = IERC20(erc20Address); + require(erc20.balanceOf(address(this)) >= amount, "Insufficient funds"); // this should _never_ be possible, given the circuit logic. + // Call the erc20's transfer function, transferring `amount` from this portal contract's address to the `to` address + return success; // this will have been updated depending on the above steps. + } + +} +``` \ No newline at end of file diff --git a/circuits/specs/src/examples/erc20/appendix/rollup-processor.md b/circuits/specs/src/examples/erc20/appendix/rollup-processor.md new file mode 100644 index 00000000000..81bbe7f2e84 --- /dev/null +++ b/circuits/specs/src/examples/erc20/appendix/rollup-processor.md @@ -0,0 +1,213 @@ + +```js +contract RollupProcessor is IRollupProcessor { + + // Needs reordering to save space. + struct PendingL2TxDatum { + address feePayer; + uint256 fee; + address feeCurrency; + bytes24 callback; + uint256 callbackGasLimit; // TODO: maybe this can be more-cheaply communicated + // through the L2 call (rollup calldata)? + bytes24 callbackOnCancel; + uint256 callbackOnCancelGasLimit; // TODO: as above. + } + + // portalContractAddress => l2ContractAddress lookup. + // mapping(address => uint32) l2ContractAddresses; + // l2ContractAddress => portalContractAddress lookup. + // mapping(uint32 => address) portalContractAddresses; + + // l2CallHash => PendingL2TxData[] (dynamic array to allow for duplicate calls) + mapping(uint256 => PendingL2TxDatum[]) l2TxPool; + + event NewDeployment(...); + + // Events to inform the rollup provider of potential fees they can earn from L1. + event NewPendingL2Tx( + uint256 l2CallHash, + uint256 callIndex, + uint256 fee, + address feeCurrency + ); + event ProcessedPendingL2Tx( + uint256 l2CallHash, + uint256 callIndex + ); + event CancelledPendingL2Tx( + uint256 l2CallHash, + uint256 callIndex + ); + + + /** + * This probably doesn't need to be in the RollupProcessor contract; + * it can be separate. + */ + function deployPortalContract(bytes memory bytecode, uint salt) + external pure returns (address portalContractAddress) { + // Do a CREATE2 call to deploy the portal contract + assembly { + portalContractAddress := create2( + callvalue(), // wei sent with current call + // Actual code starts after skipping the first 32 bytes + add(bytecode, 0x20), + mload(bytecode), // Load the size of code from the first 32 bytes + salt + ) + if iszero(extcodesize(portalContractAddress)) { + revert(0, 0) + } + } + } + + + /** + * @param callback - contract address & function selector of an L1 callback + * function which will be executed once the L2 tx is processed by this contract. + * + * I think the `callback` will have to have a rigid functionSelector with params: + * - l2CallHash (as a 'lookup' key which the portal contract can use) + * - emittedPublicInputs + */ + function callL2AndPayFee( + uint256 l2CallHash, + bytes24 callback, + uint32 callbackGasLimit, // TODO: maybe this can more-cheaply be communicated + // through the L2 call (rollup calldata)? + bytes24 callbackOnCancel, + uint32 callbackOnCancelGasLimit, // TODO (as above) + uint256 fee, // pays for both the L2 call and the L1 callback gas + address feeCurrency, + ) external { + // Note: an l2CallHash contains a callContext, which contains a msgSender, + // so it is unique (unless the user calls twice). If the user calls twice, + // the pool is a dynamic array, so we'll push the call again. Portal + // Contracts will need to allow for duplicate l2CallHashes. + + PendingTxDatum memory tx = PendingL2TxDatum({ + feePayer: msg.sender, + fee, + feeCurrency, + callback, + callbackGasLimit, + callbackOnCancel, + callbackOnCancelGasLimit, + }); + + uint256 callIndex = l2TxPool[l2CallHash].push(tx); + + IERC20 erc20 = IERC20(feeCurrency); + erc20.transferFrom(msg.sender, address(this), fee); + + emit NewPendingL2Tx(l2CallHash, callIndex, fee, feeCurrency); + } + + + // TODO: Should cancellation even be allowed? A user's L2 tx could be processed + // by the rollup provider, but then get cancelled before the rollup provider + // publishes their rollup; thereby missing out on being paid. + // On the other hand, cancellation does seem important. + // Maybe the fee repayment could be delayed for a week? Seems nasty. + cancelL2Call(l2CallHash, callIndex) external { + + PendingTxDatum memory tx = l2TxPool[l2CallHash][callIndex]; + + // For now, let's say the feePayer is the person permitted to cancel: + require(msg.sender == tx.feePayer, "Permission to cancel denied!"); + + // Return the fee + if (tx.fee > 0) { + IERC20 erc20 = IERC20(tx.feeCurrency); + erc20.transfer(tx.feePayer, tx.fee); + } + + // This is pseudocode: + tx.callbackOnCancel(l2CallHash, callIndex, { tx.callbackOnCancelGasLimit }); + + // Delete the tx from the pool: + delete l2TxPool[l2CallHash][callIndex]; + + emit CancelledPendingL2Tx(l2CallHash, callIndex); + } + + + /** + * Upon submission of a rollup, this contract will identify any L2 txs which were + * invoked via 'this.callL2AndPayFee()'. It will then pass params to this + * function. + * @param rollupProvider - the person who submitted the rollup + */ + function executeCallbackAndPayFee( + uint256 l2CallHash, + uint256 callIndex, + bytes functionSignature, + uint256[4] emittedPublicInputs, + address rollupProvider, + ) private { + PendingTxDatum memory tx = l2TxPool[l2CallHash][callIndex]; + + // Make a call to the callback function, passing the emittedPublicInputs as + // params, and passing the callbackGasLimit. Handle the call so that even if + // it fails or runs out of gas, the rollup provider still gets paid (and to + // prevent griefing). + // This is pseudocode!!! + tx.callback( + l2CallHash, + callIndex, + functionSignature, + emittedPublicInputs, + { tx.callbackGasLimit } + ); + + // Pay the rollup provider + if (tx.fee > 0) { + IERC20 erc20 = IERC20(tx.feeCurrency); + erc20.transfer(rollupProvider, tx.fee); + } + + // delete the pending tx from the pool: + delete l2TxPool[l2CallHash][callIndex]; + + emit ProcessedPendingL2Tx(l2CallHash, callIndex); + } + + + function processRollup(...) { + + // Verify the proof + + // Decode the calldata + + // Loop through all txs in the rollup. + // Identify the following tx scenarios from the calldata: + // (see the Public Input ABIs section for more details of these bools) + // - payFeeFromL1 -> call payFee(l2CallHash, callIndex, rollupProvider); + // using l2CallHash, callIndex from the calldata. + // The rollup processor must be designed so this fee + // payment CANNOT fail. Otherwise we'd have L2 state + // changes for free. Hold the fee in escrow. The rollup + // provider shouldn't process the l2 tx unless he sees the + // fee exists on-chain. (And don't allow the fee to be + // withdrawn by the payer? (i.e. disallow cancellation?)) + // - calledFromL1 -> call executeCallBackAndPayFee(...) + // using data from the calldata. + // - isContractDeployment -> call something... TODO + // + // Loop through the l1CallStack of each tx in the rollup. + // - For each l1CallStackItem (which will be a keccak hash of data): + // - The unpacked data of the call (functionSelector, argumentEncoding) + // will need to have been provided as calldata when submitting the + // rollup. + // - Reconcile the l1CallStackItem: + // - require(l1CallStackItem == keccak256(unpackedData)); + // - Call the L1 function with args described by the unpacked data. + // - Note: if any L2 tx in a callstack makes an L1 call, NONE of the L2 + // state changes may be finalised until all the L1 calls have been + // successful. The next rollup block must 'complete' commitments or + // update the l1ResultsTree. + + } +} +``` \ No newline at end of file diff --git a/circuits/specs/src/examples/erc20/deployment.md b/circuits/specs/src/examples/erc20/deployment.md new file mode 100644 index 00000000000..2e1a54dcb23 --- /dev/null +++ b/circuits/specs/src/examples/erc20/deployment.md @@ -0,0 +1,189 @@ +# Deployment + +Let's suppose our aztec contract will have 3 circuits (plus constructor circuits): deposit, transfer, withdraw. + +> In reality these can be a single circuit, much like our join-split circuit, but we'll split it into 3 to show off more machinery of aztec 3.0. Suppose the proving keys and verification keys of these circuits have been generated and we're ready to deploy our aztec contract to Aztec 3.0. + +## Private Constructor + +See [here](../../architecture/contracts/deployment.md#private-constructor) for background. + +In this example, we don't need to initialise any private states, so won't be using the private constructor. + +## Public constructor + +Let's have a think about Aztec 2.0 and what public states are initialised and tracked for the 'zk.money ERC20' functionality: +- `userPendingDeposits[] (mapping)` +- `depositProofApprovals[] (mapping)` +- `supportedAssets[]` +- `DEFAULT_ERC20_GAS_LIMIT = 75000;` +- `assetGasLimit[] (mapping)` + +Since Aztec 3.0 will be agnostic to applications, we won't be able to store these states in the RollupProcessor contract anymore. So these app-specific states will need to either be stored in the aztec contract's portal contract, or in the L2 contract (in the publicDataTree). Both options are possible. + +The `userPendingDeposits, depositProofApprovals` will both start out as empty mappings, so don't need to be initialised in the public constructor. We'll probably also store these on-chain in the L1 portal contract - another reason we won't be initialising them in this constructor. + +The `supportedAssets, DEFAULT_ERC20_GAS_LIMIT, assetGasLimit` array _could_ be prepopulated with some values in the constructor, if we wish for these values to be stored in the aztec L2 publicDataTree, instead of in the L1 portal contract. + +To show off as much machinery as possible, let's store `supportedAssets` in the publicDataTree and initialise it in the constructor. The other two gas-related values I'll ignore for now, since 'gas limit' stuff still needs some thinking. + +:question: TODO: understanding gas limits for portal contract interactions is a complicated thing to spend time thinking about. The rollup provider really needs to know these limits before they process the rollup, in order to gauge their expected profits. + +This example public constructor will simply be a Public Circuit (which follows the Public Circuit ABI) which sets the value of `supportedAssets`. Before we can set this value, we need to know its `storageSlot` in our new contract. + +[Storage slots in Solidity](https://docs.soliditylang.org/en/v0.8.9/internals/layout_in_storage.html) are assigned based on the order variables are declared (with a few caveats for complex types). Aztec 3 is a bit more complicated, because storage is split across 3 places: +- On chain storage in the Portal Contract +- Public L2 storage in the publicDataTree (account-based storage model). +- Private L2 storage in the privateDataTree (UTXO storage model). + +In this example, things will be stored as follows: + +- Portal contract: + - `userPendingDeposits[] (mapping)` + - `depositProofApprovals[] (mapping)` + - ~~`DEFAULT_ERC20_GAS_LIMIT = 75000;`~~ For simplicity, we'll ignore this here. + - ~~`assetGasLimit[]`~~ - Fees & gas limits are tricky. I'll ignore for now. +- publicDataTree + - `supportedAssets[]` - publicDataTree (for example's sake) +- privateDataTree + - Join-split value notes are a representation of a user's `balance` (in ERC20 terms). + - The ERC20 notion of a `balances[]` mapping can be converted into a UTXO-friendly notion for the privateDataTree. Each user's balance is 'partitioned' across set of commitments. The sum of a user's (not-yet-nullified) commitments' values is understood to represent `balances[userAddress]`. + + +We're only considering writes to the publicDataTree in the public constructor. So what storage slots will be used in the tree? + +The 0th storage slot of every contract are reserved (in the current spec) for: +0. The leafIndex of a contract's vkRoot in the contractTree. + +So, `supportedAssets` can start at `storageSlot = 1`. It's a dynamic array, so we can perhaps copy Ethereum's method for deriving storage slots: + +- The length of the array can be stored at `storageSlot = 1`. +- The `i`th index of the array can be stored at `storageSlot = hash(1) + i`. + +Suppose we wish to support 3 assets at the beginning: ETH, DAI, WBTC with asset_id values `0, 1, 2` resp. + +Then there are **two** `stateTransitions` for the publicDataTree which the public constructor circuit will expose (via the ABI): +- `[storgeSlot, oldValue, newValue]`: + - `[hash(1) + 1, 0, 1]` for (`supportedAssets[1] = 1;`) + - `[hash(1) + 2, 0, 2]` for (`supportedAssets[2] = 2;`) + +Notice: we don't need to expose a state transition for ETH's asset_id, because it's intended value is `0`. + +Here's the public constructor's nonzero public inputs (refer to the Public Circuit ABI for the rest): + +```js +customPublicInputs, +customPublicOutputs, +stateTransitions: [ + [hash(1) + 1, 0, 1], + [hash(1) + 2, 0, 2], +], +``` + +(The other public inputs aren't shown, because they're either 0, or global stuff like block timestamps). + +> Note: although we can specify a recommended storage layout (which Noir will use), there's nothing technically stopping an app from deciding upon its own storage layout rules. Contracts' storage slots are siloed by hashing with the contract address (see the spec). + + +The `publicConstructorCallstackItem` looks like: + +```js +publicConstructorCallstackItem: { + functionSignature: concat( + contractAddress, + vkIndex = 0, // Constructor vks won't be added to the contract's vkTree. + // This `0` is treated as 'null' when `isConstructor = true`. + isPrivate = false, + isConstructor = true, + isCallback = false, + ), + publicInputsHash, // hash of public constructor’s public inputs (see earlier section) + callContext, + isDelegateCall, + isStaticCall, +} +``` + +## L2 contract address + +Much like Ethereum's create2, L2 contract addresses are specified deterministically: + +`newContractAddress := hash(deployerAddress, salt, vkRoot)` + +`deployerAddress` can be a user or another contract. + + + +## L1 Portal Contract + +Refer to the [appendix](./appendix/portal-contract.md) for example pseudocode. +### Motivation + +We need a way of depositing erc20 tokens into a shield contract (an L1 contract which holds the erc20 tokens in escrow whilst they're transferred privately via L2). With Aztec 1.0 & 2.0, the RollupProcessor contract served as the escrow contract, since there was only one application (zk-money). But for Aztec 3.0, we need to _silo_ the funds held in escrow on behalf of each L2 aztec contract. Why? + +Imagine two similar erc20-shielding aztec contracts get deployed (by different developers) to Aztec 3.0. The contracts are both composed of deposit, transfer and withdraw circuits. Suppose one of the developers is malicious, and put a backdoor into their withdraw circuit to allow them to withdraw 'infinite' L1 tokens that are held in escrow. Then if all of the L1 funds of both L2 contracts were held in a single pool, the malicious dev could withdraw them all. So we definitely need L1 funds to be siloed for each L2 contract. + +Why don't we track the siloed funds of the different L2 contracts in the RollupProcessor, still? Because Aztec 3.0 won't just support erc20 shielding. It'll support unlimited use cases, where different L2 contracts will want to manage different L1 states (not necessarily token balances). Therefore we'll put the onus of developing the logic of managing L1 states in the hands of the aztec contract developers. We'll allow devs to deploy an L1 'portal contract' which interacts with other L1 Ethereum contracts and manages L1 state for a particular L2 aztec contract. "Portal" because it links L2 & L1. + +Note: portal contracts will be able to make calls to _any_ L2 function. But an L2 function will only be able to make calls to its portal contract; an L2 function cannot call other L1 contracts directly, because it doesn't have an L1 address. That's a nice way of thinking about Portal contracts actually - they provide an L1 address through which calls to other L1 contracts can be made. + +### Portal Contract Deployment + +See [here](../../architecture/contracts/deployment.md#l1-portal-contract-address) first. + +Let's assume option 2 is available to us for this example. The deployer (the dev who's deploying this L2 contract) writes an L1 Portal Contract to handle calls to/from L2. The developer compiles this portal contract (along with constructor arguments) into bytecode. The address of the portal contract can be determined in advance using CREATE2. + +```js +portalContractAddress = keccak256(0xff, deployingAddress, salt, keccak256(bytecode))[12:] +``` + +> Notice there's a constructor argument in the [portal contract example](./appendix/portal-contract.md), just to show off as much machinery as possible. We didn't really need this, because the Rollup Processor's address can be accessed via `msg.sender`. 'Bytecode' is understood to include the contructor arguments of a function. I.e. let bytecode be `abi.encodePacked(bytecode, abi.encode(args))`. + +_Somehow_ (TODO) the deployer deploys the Portal Contract, and maybe registers it with the RollupProcessor. We need to prevent front-running of the Portal Contract address, whereby an attacker links the wrong L2 contract with the intended Portal Contract (TODO). + + +## Putting it all together and deploying the contract + +The dev will: +- Write circuits in Noir +- Write Portal Contract +- Write loads of code (TypeScript probably) to build their app. +- Send a tx to deploy a contract to the rollup provider. + - ```js + call = { + publicInputs: { + // Constructor functions + privateConstructorPublicInputsHash, + publicConstructorPublicInputsHash, + privateConstructorVKHash, + publicConstructorVKHash, + + // L2 contract address (create2-like) + contractAddress, + vkRoot, + + // Distributing L2 contract data + circuitDataKeccakHash, + + // Deploying an L1 Portal Contract + portalContractAddress, + }, + callContext, // not needed? + } + ``` + (the preimages of all these hashes will also need to be sent, so they may be fed in as private inputs to the contract deployment kernel snark). +- If there's a private constructor, the dev will need to execute that constructor circuit in their client and 'wrap' it in a private kernel snark proof. Then send that kernel proof to the rollup provider too (probably in the same send as above). +- The rollup provider will need to execute any public calls and public kernel snark recursions if that private call made any public calls. +- If there's a public constructor, the rollup provider will need to execute that and 'wrap' it in a public kernel snark. +- The rollup provider will then execute the Contract Deployment Kernel Circuit and generate a proof. + - This circuit validates both constructor kernel snarks; + - Then adds the contract data to the tree. +- Then that proof will be fed into the Base Rollup Circuit... +- ... which will then be fed into the Merge Rollup Circuit... +- ... which will eventually be sent to the RollupProcessor contract. +- The RollupProcessor might store a mapping between the Portal Contract's address and the Contract's address. + + + + + diff --git a/circuits/specs/src/examples/erc20/deposit.md b/circuits/specs/src/examples/erc20/deposit.md new file mode 100644 index 00000000000..208c0572eee --- /dev/null +++ b/circuits/specs/src/examples/erc20/deposit.md @@ -0,0 +1,42 @@ +# Deposit + + +Refer to the [example portal contract](./appendix/portal-contract.md) and [example rollup contract](../erc20/appendix/rollup-processor.md) when reading this section. + + +A 'deposit' is an example of an [L1 function making a call to an L2 function](../../architecture/contracts/l1-calls.md#l1----l2-calls). A user might not have any money on L2 yet, so we allow for L2 fees to be paid via L1. + +## High-level flow: + +- User generates inputs for an L2 contract's `deposit` function. +- User calls `PortalContract.deposit` + - Portal Contract stores some stuff. +- Portal Contract calls Rollup Processor. + - Rollup Processor stores more stuff. +- User generates a proof of the L2 `deposit` function. +- The `deposit` function emits an event via the `emittedPublicInputs` field. +- The proof gets added to a rollup. +- The Rollup Processor receives the rollup and is able to identify and extract info from functions which were 'called by L1 functions'. +- The Rollup Processor checks the `emittedPublicInputs` against the previously-stored on-chain stuff. +- A callback function calls the Portal Contract. +- The Portal Contract changes 'pending' states to finalised (or deletes them). +- Done. + +## Slightly less high-level flow + +- User calls `deposit` in the Portal Contract. +- Money is transferred-to and held by the Portal Contract, in escrow. +- An L2 circuit must also be executed as an off-chain counterpart to this on-chain deposit, in order to create a private note. +- The Portal Contract makes a call to the RollupProcessor's `callL2AndPayFee` function. +- An [`l2CallHash`](../../architecture/contracts/transactions.md#callstackitemhash) representing a call to the L2 circuit is send to the RollupProcessor to store temporarily, until the L2 function is executed. +- A `callback` function will also be given to the RollupProcessor, for it to call once the L2 circuit has been executed. This callback will call a function of any other L1 contract. + - In our example, the callback will call the Portal Contract's `depositCallback` function. +- Once the L2 circuit is executed, it will be added to a rollup, and the rollup will be submitted by the rollup provider to `RollupProcessor.processRollup`. +- The RollupProcessor will be able to identify from the rollup calldata any 'event data' emitted by functions which were 'called' by L1. + - In this example, the RollupProcessor will be able to extract the `l2CallHash`, `functionSignature`, and `emittedPublicInputs` of the L2 'deposit' circuit. +- The `l2CallHash`, `functionSignature`, and `emittedPublicInputs` will all be validated against what was previously stored when the L1 `deposit` function was called. + - In particular, the `emittedPublicInputs` of this example's 'deposit' circuit will contain the `amount` deposited, as a way of reconciling the L1 call with the L2 call. It might also contain the `msg.sender`. +- If all of the checks reconcile, then the rollup provider will be paid a fee (if one was provided as part of the initial L1 call). + + + diff --git a/circuits/specs/src/examples/erc20/erc20-shielding.md b/circuits/specs/src/examples/erc20/erc20-shielding.md new file mode 100644 index 00000000000..6f91259211c --- /dev/null +++ b/circuits/specs/src/examples/erc20/erc20-shielding.md @@ -0,0 +1,5 @@ +# Example - ERC20 shield + +Let's walk through the steps of deploying a contract to Aztec's L2, which shields ERC20-tokens from L1. + +See the [appendix](appendix/appendix.md) for example (pseudocode) smart contracts. diff --git a/circuits/specs/src/examples/erc20/transfer.md b/circuits/specs/src/examples/erc20/transfer.md new file mode 100644 index 00000000000..8dfcc0bf6ca --- /dev/null +++ b/circuits/specs/src/examples/erc20/transfer.md @@ -0,0 +1,12 @@ +# Transfer + +A transfer is an entirely private function. + +- A user's client generates a proof over the 'transfer' circuit, with a particular set of public/private inputs. +- The user's client then passes the proof to the Private Kernel Circuit and generates a proof. + - This proof hides the function which has been executed. + - A padding proof could then be generated to add more commitments/nullifiers to the kernel snark's public inputs, as a way of further obfuscating which tx was executed. Then that would all be passed into a second Private Kernel Circuit and a second such proof generated. +- The 'transfer' function doesn't make any public calls or contract deployment calls. +- The user sends their final kernel snark to the rollup provider +- The rollup provider adds the user's tx to a rollup (by passing the snark as input to a Base Rollup circuit, and then into a Merge Rollup circuit). +- Eventually the Rollup Processor contract receives the rollup and verifies the final rollup proof. \ No newline at end of file diff --git a/circuits/specs/src/examples/erc20/withdraw.md b/circuits/specs/src/examples/erc20/withdraw.md new file mode 100644 index 00000000000..0aafb8f751e --- /dev/null +++ b/circuits/specs/src/examples/erc20/withdraw.md @@ -0,0 +1,26 @@ +# Withdraw + +Withdrawal is an example of a [L2 --> L1 call](../../architecture/contracts/l1-calls.md#l2----l1-calls). A user wants to nullify a private note on L2, and then be transferred ERC20 tokens on L1. + +- The user generates a 'withdraw' proof. `withdraw` is a private circuit, because it must nullify a private state. +- The `withdraw` function nullifies an `amount` owned by the caller. +- Since it's an L2-->L1 call, the `withdraw` function _does_ reveal select information. + - It adds an `l1CallStackItem` to its `l1CallStack`. + - This `l1CallStackItem` includes the function selector of the L1 function, as well as an encoding of the arguments to be passed to the function. In particular, two arguments for this example will be an `amount` and a `recipient`. + - It can add callbacks, which may be executed depending on the outcome of the L1 function. + - In this example, the outcome will either be: + - success: the money is transferred; or + - fail: the L1 tx failed. + - We don't need a 'success' callback in this example. If the money is successfully transferred, nothing else needs to happen on L2 after the L1 call succeeds (the money has already been nullified on L2). + - We add a 'failure' callback to reinstate the private value note containing the `amount`, if the L1 tx fails. + - This failure callback can either be a public function or private, depending on the developer's preferences. It can be public, since the 'amount' and 'recipient' are already public knowledge by this point. But it could also be private, which would then allow the user to hide that the callback has even been executed. + - In particular, in this example, the `customPublicInputs` will need to contain the `amount` and maybe also the `recipient`, as a way of forcing the callback to only reinstate the correct amount to the correct user. +- Recall that the initial call to L1 must go via the Portal Contract + - ...So the Portal Contract will receive a call from RollupProcessor.sol + - If successful, it will return some result data (of variable size), and the RollupProcessor will sha256 hash this data (the amount of data to hash might need to be bounded to prevent griefing attacks). + - The sha256 hash will be emitted as an L1 result (along with all other L1 results). + - If the call fails and it doesn't return data, the RollupProcessor will register an 'L1 Result Hash' of `0`. +- The RollupProcessor with sha256 all result hashes to get a single L1ResultsHash (plural name). +- In the next rollup, the rollup provider will be _forced_ to add each L1ResultsHash to the l1ResultsTree. ('Forced', because the RollupProcessor will check the L1ResultsHash when the next rollup is submitted). +- The previously-stored callback functions can then be executed - either the success or failure callback, depending on the result. + - Each callback function exposes the `callbackCallHash` and an `l1ResultHash`. Both of these get checked against the previously-stored data to ensure the callback is responding in a valid way to the result. diff --git a/circuits/specs/src/intro.md b/circuits/specs/src/intro.md new file mode 100644 index 00000000000..ff1a15c49f3 --- /dev/null +++ b/circuits/specs/src/intro.md @@ -0,0 +1,19 @@ +# About + +- This spec is very much a work in progress. It will change many times between now and deployment. +- Much of this document is to aid development and hence is _very_ detailed, so that things which have been thought about aren't forgotten. The detail might make some sections unreadable (e.g. execution logic bullet points). +- It's such a big document, that there will be mistakes - please ask & we can correct any you see :) +- All constants in this spec are somewhat arbitrarily chosen, as the architecture must be implemented and performance measured to determine optimal values. +- Stuff relating to fees and attributing 'work done' by provers in the form of 'proverRecords' is only half thought-out. It needs more work, so skim read it for now. +# Goals of Aztec 3 + +- Private L2 + - General-purpose, private smart contracts. +- Public L2 + - Cheaper public state transactions than interacting with L1. +- Interacting with Ethereum's L1 still supported (and required for many use cases). + +> Whenever we refer to 'contract' in this document, we'll be referring to an Aztec 3 L2 contract (which may comprise both public and private functions). If we're talking about an Ethereum contract, we'll explicitly say something like 'Ethereum contract' or 'L1 contracct' or 'Portal contract'. + + +Here are the beginnings of some [sexy diagrams](https://drive.google.com/file/d/1gCFhE78QhfEboF0hq3scb4vAU1pE0emH/view?usp=sharing) (open with -> diagrams.net) diff --git a/circuits/specs/src/noir-stuff/extremes/call-l1.md b/circuits/specs/src/noir-stuff/extremes/call-l1.md new file mode 100644 index 00000000000..b8d4ca2eaaf --- /dev/null +++ b/circuits/specs/src/noir-stuff/extremes/call-l1.md @@ -0,0 +1,479 @@ +In these examples, we omit any 'other logic' and focus on making an L1 call. Therefore the code shown might not make much sense as a useful contract, since it won't do anything except call another function. + +This is a simplified example of a defi bridge swap, via L1. The simplification is that the L2 contract only tracks a single person's balance (and is therefore useless for privacy, but still useful as a demonstration) - I didn't want to dive into mappings and `msg.sender` syntax yet. + + +# High-level + +```js +/******************************************************************************** + * ON-CHAIN SOLIDITY: + *******************************************************************************/ + +// THIS FUNCTION IS SOLIDITY, IMPORTED SOMEHOW... +// Suppose this is deployed at L1 Portal Contract address 0xabc123. +contract L1_Portal_Contract { + function l1_swap_a_for_b(uint amount_a) { + // do an on-chain swap of amount_a for some amount_b + return amount_b; // This result is added to a results tree through Aztec 3's + // architecture. + } +} + +/******************************************************************************** + * CIRCUITS: + *******************************************************************************/ + +// Suppose this is deployed at contract address 0xdef456. +contract My_Contract_1 { + secret uint token_balance_a; + secret uint token_balance_b; + + function swap_a_for_b(uint amount_a) { + // Compute some stuff to make it realistic (ish), + token_balance_a -= amount_a; + + // An L2 function can _only_ make L1 calls to its own L1 Portal Contract + // (and not to any other L1 contract). + // Here's some pseudocode for a special 'L1Promise' type. + // Kind of like Rust's. Kind of like handling a JS Promise. + // Please make the syntax better! :) + // An L1 call (from L2) always must return an L1Promise. + L1Promise promise = L1_Portal_Contract.l1_swap_a_for_b(amount_a); + + promise.then( + result => hide_amount_b(result[0]), // On success, the result will + // effectively be an array of values. + // Note: a result value must not be + // passed to a 'secret' arg's position. + hide_amount_a(amount_a), // On failure, nothing is returned + // (not even an error message), so the failure + // callback is executed with existing args. + ); + } + + function hide_amount_b(uint amount_b) { + token_balance_b += amount_b; + } + + function hide_amount_a(uint amount_a) { + token_balance_a += amount_a; + } +} +``` +See the other extreme [below](#mycontract1). + +# Low level + +## `my_contract_1` + +### `swap_a_for_b()` + +```rust +// The PUBLIC_INPUTS adhere to the Aztec 3 ABI for a private circuit. +fn swap_a_for_b( + PRIVATE_INPUTS: { + + unpacked_callback_stack: [ + { + success_callback_call: { + function_signature, + public_inputs, + call_context, + is_delegate_call, + is_static_call, + }, + failure_callback_call: { + function_signature, + public_inputs, + call_context, + is_delegate_call, + is_static_call, + }, + } + ] + + token_balance_a_owner_private_key, + + token_balance_a_old_value, + token_balance_a_old_salt, + token_balance_a_old_input_nullifier, + token_balance_a_old_leaf_index, + token_balance_a_old_sibling_path, + + token_balance_a_new_salt, + }, + PUBLIC_INPUTS: { + custom_public_inputs: [ + amount_a, + ], + emitted_public_inputs: {}, + executed_callback: {}, + + output_commitments: { + token_balance_a_new_commitment, + }, + input_nullifiers: { + token_balance_a_old_nullifier, + }, + + private_call_stack: [], + public_call_stack: [], + contract_deployment_call_stack: [], + partial_l1_call_stack: [ + swap_a_for_b_l1_call_stack_item_hash, + ], + callback_stack: [ + { + callback_public_key, // this just passes through, if in use. + success_callback_call_hash, + failure_callback_call_hash, + success_result_arg_map_acc, + } + ], + + old_private_data_tree_root, + + is_fee_payment: false, + pay_fee_from_l1: false, + pay_fee_from_public_l2: false, + called_from_l1: false, + } +) { + + // Params: + let amount_a = PUBLIC_INPUTS.custom_public_inputs.amount_a + + /******************************************************************************** + * MAKE THE L1 CALL + *******************************************************************************/ + + // Check the correct parameters are being passed to the function. + // Assume we have some library that can do Solidity abi encoding. + let arg_encoding = Solidity.abi.encode(amount_a); + + // Compress the encoding (which can very in size from app to app) to be a fixed + // size for the kernel snark. + // We use keccak hashing because this will need to be unpacked on-chain in order + // to call the L1 function. + // Notice: the function selector can be hard-coded (0xdeadbeef here). + assert(l1_function_l1_call_stack_item_hash == keccak(0xdeadbeef, arg_encoding)); + + // Validate the callbacks: + let { + success_callback_call_hash, + failure_callback_call_hash, + success_result_arg_map_acc, + } = PUBLIC_INPUTS.callback_stack[0]; + + let { + success_callback_call, + failure_callback_call, + } = PRIVATE_INPUTS.unpacked_callback_stack[0]; + + + require( + success_callback_call == { + function_signature: { + contract_address: 0, // Special meaning: address(this) + vk_index: 1, // hide_amount_b() + is_private: true, + is_contract_deployment: false, + is_callback: true, // <-- callback! + }, + public_inputs: { + // Some public inputs are omitted from this object when calculating a + // _callback's_ call hash, because they depend on the (as of yet) + // unknown L1 result. + custom_public_inputs: [ + 0, // Inputs which will be 'result' values are set as 0. + ], + emitted_public_inputs: {}, + // executed_callback: {...}, // Object is omitted, + // since it's not known yet. + // TODO: maybe we ONLY need the custom_public_inputs??? + // TODO: model the claim circuit, so I understand what's needed for + // that context. + output_commitments: { + 0, // depends upon the result, so set to 0. + }, + input_nullifiers: { + // DANGER - race condition. This private state could be nullified + // by some other call from this user, before _this_ callback + // gets executed. We'll need the User Client to be aware of this. + // QUESTION: maybe this isn't needed to be specified at this time + // - that would prevent the race. + token_balance_b_old_nullifier, + }, + // All these are omitted from a callback's call hash, because these + // future calls might depend upon the result (which isn't known yet): + // private_call_stack: [], + // public_call_stack: [], + // contract_deployment_call_stack: [], + // partial_l1_call_stack: [], + // callback_stack: [], + + // old_private_data_tree_root, // Omitted, so that the very-latest + // root can be used when it's executed, + // for maximum privacy. + + is_fee_payment: false, + pay_fee_from_l1: false, + pay_fee_from_public_l2: false, + called_from_l1: false, + }, + call_context: { + msg_sender, // I _think_ we can keep this here. On some occasions, + // for public circuits, the rollup provider might + // execute the callback, but I think it can still be + // signed in advance by the actual user? + storage_contract_address: 0, // for `this` contract, we put `0`. + } + }, + failure_callback_call == { + function_signature: { + contract_address: 0, // Special meaning: address(this) + vk_index: 2, // hide_amount_a() + is_private: true, + is_contract_deployment: false, + is_callback: true, // <-- callback! + }, + public_inputs: { + custom_public_inputs: [ + amount_a, // All args are known for a failure callback. (There's + // no result being fed in). + ], + emitted_public_inputs: {}, + // executed_callback: {...}, // Object is omitted, + // since it's not known yet. + output_commitments: { + token_balance_a_new_commitment, + }, + input_nullifiers: { + // DANGER - race condition. This private state could be nullified + // by some other call from this user, before _this_ callback + // gets executed. We'll need the User Client to be aware of this. + // QUESTION: maybe this isn't needed to be specified at this time + // - that would prevent the race. + token_balance_a_old_nullifier, + }, + // All these are omitted from a callback's call hash. Whilst we + // technically _could_ include them for the failure callback, + // for consistency with the success callback, we omit them. + // private_call_stack: [], + // public_call_stack: [], + // contract_deployment_call_stack: [], + // partial_l1_call_stack: [], + // callback_stack: [], + + // old_private_data_tree_root, // Omitted, so that the very-latest + // root can be used when it's executed, + // for maximum privacy. + + is_fee_payment: false, + pay_fee_from_l1: false, + pay_fee_from_public_l2: false, + called_from_l1: false, + }, + call_context: { + msg_sender, // I _think_ we can keep this here. On some occasions, + // for public circuits, the rollup provider might + // execute the callback, but I think it can still be + // signed in advance by the actual user? + storage_contract_address: 0, // for `this` contract, we put `0`. + } + } + ) + + let failure_callback = PUBLIC_INPUTS.callback_stack.failure_callback; + assert( + failure_callback.function_signature == { + contract_address: 0, // special meaning: address(this) + vk_index: 2, // hide_amount_a() + is_private: true, + is_contract_deployment: false, + is_callback: true, // <-- callback! + } + ); + // TODO: assert public inputs, call context, etc. too. + + + + +// Everything below is as per the ./decr-private-owned.md contract_1 example. +// I.e. it's simply the decrementing of a 'whole' private state variable. + + /******************************************************************************** + * NULLIFY OLD STATE + *******************************************************************************/ + + // Calculate a proof of knowledge of secret key to permit editing of this state: + token_balance_a_owner_public_key = derive_public_key( + token_balance_a_owner_private_key + ); + + // Calculate commitment of the old value: + let token_balance_a_old_commitment = ped::hash( + 1, // assume `token_balance_a` occupies storage slot 1. + token_balance_a_old_value, // value + token_balance_a_owner_public_key, // owner + token_balance_a_old_salt, // salt + token_balance_a_old_input_nullifier // input_nullifier of some prev tx + // (to ensure uniqueness) + ); + + // Check token_balance_a_old_commitment exists in the old tree: + merkle_check( + old_private_data_tree_root, + token_balance_a_old_commitment, + token_balance_a_old_leaf_index, + token_balance_a_old_sibling_path, + ); + + // Nullify token_balance_a_old_value: + let token_balance_a_old_nullifier_check = ped::hash( + token_balance_a_old_commitment, + token_balance_a_owner_private_key + ) + assert(token_balance_a_old_nullifier_check == token_balance_a_old_nullifier); + + /******************************************************************************** + * MUTATE THE STATE + *******************************************************************************/ + + let token_balance_a_new_value = token_balance_a_old_value - amount_a; + + /******************************************************************************** + * PUSH NEW STATE + *******************************************************************************/ + + // Calculate commitments of the final value: + let token_balance_a_new_commitment_check = ped::hash( + 1, // assume `token_balance_a` occupies storage slot 1. + token_balance_a_new_value, // value + token_balance_a_owner_public_key, // owner + token_balance_a_new_salt // salt + token_balance_a_old_nullifier // input_nullifier + ); + assert(token_balance_a_new_commitment_check == token_balance_a_new_commitment); + +} +``` + +### `hide_amount_b()` + +Designed in such a way that the function doesn't have to _know_ that it's being used as a callback. + +```rust +// The PUBLIC_INPUTS adhere to the Aztec 3 ABI for a private circuit. +fn hide_amount_b( + PRIVATE_INPUTS: { + + token_balance_b_owner_private_key, + + token_balance_b_old_value, + token_balance_b_old_salt, + token_balance_b_old_input_nullifier, + token_balance_b_old_leaf_index, + token_balance_b_old_sibling_path, + + token_balance_b_new_salt, + }, + PUBLIC_INPUTS: { + custom_public_inputs: { + amount_b, + }, + emitted_public_inputs: {}, // lots of unused stuff denoted by {} or []. + executed_callback: { + // Nonzero values only if it's actually being executed as a callback. + // These values will be passed straight through this circuit; no checks + // needed here - the kernel circuit will deal with l1 result resolution. + // With this approach, the function doesn't need to 'know' that it's + // being used as a callback. A function can therefore be executed + // as a regular tx, or as a callback. That's nice. + l1_result_hash, + l1_results_tree_leaf_index, + }, + + output_commitments: { + token_balance_b_new_commitment, + }, + input_nullifiers: { + token_balance_b_old_nullifier, + }, + + private_call_stack: [], + public_call_stack: [], + contract_deployment_call_stack: [], + partial_l1_call_stack: [], + callback_stack: [], + + old_private_data_tree_root, + + is_fee_payment: false, + pay_fee_from_l1: false, + pay_fee_from_public_l2: false, + called_from_l1: false, + } +) { + + /******************************************************************************** + * NULLIFY OLD STATE + *******************************************************************************/ + + // Calculate a proof of knowledge of secret key to permit editing of this state: + token_balance_b_owner_public_key = derive_public_key( + token_balance_b_owner_private_key + ); + + // Calculate commitment of the old value: + let token_balance_b_old_commitment = ped::hash( + 1, // assume `x` occupies storage slot 1. + token_balance_b_old_value, // value + token_balance_b_owner_public_key, // owner + token_balance_b_old_salt, // salt + token_balance_b_old_input_nullifier // input_nullifier of some prev tx + // (to ensure uniqueness) + ); + + // Check token_balance_b_old_commitment exists in the old tree: + merkle_check( + old_private_data_tree_root, + token_balance_b_old_commitment, + token_balance_b_old_leaf_index, + token_balance_b_old_sibling_path, + ); + + // Nullify token_balance_b_old_value: + let token_balance_b_old_nullifier_check = ped::hash( + token_balance_b_old_commitment, + token_balance_b_owner_private_key + ) + assert(token_balance_b_old_nullifier_check == token_balance_b_old_nullifier); + + /******************************************************************************** + * MUTATE THE STATE + *******************************************************************************/ + + let token_balance_b_new_value = token_balance_b_old_value + amount; + + /******************************************************************************** + * PUSH NEW STATE + *******************************************************************************/ + + // Calculate commitments of the final value: + let token_balance_b_new_commitment_check = ped::hash( + 1, // assume `x` occupies storage slot 1. + token_balance_b_new_value, // value + token_balance_b_owner_public_key, // owner + token_balance_b_new_salt // salt + token_balance_b_old_nullifier // input_nullifier + ); + assert(token_balance_b_new_commitment_check == token_balance_b_new_commitment); + +} +``` + + + + diff --git a/circuits/specs/src/noir-stuff/extremes/call-private.md b/circuits/specs/src/noir-stuff/extremes/call-private.md new file mode 100644 index 00000000000..549f5090f7f --- /dev/null +++ b/circuits/specs/src/noir-stuff/extremes/call-private.md @@ -0,0 +1,150 @@ +In these examples, we omit any 'other logic' and focus on making a private call. Therefore the code shown might not make much sense as a useful contract, since it won't do anything except call another function. + +# High-level + +```js +// Suppose this is deployed at contract address 0xabc123. +contract Other_Contract { + // vkIndex = 0 in this example. + function other_private_function(uint a, uint b, uint c) { + // do a thing + } +} + +// Suppose this is deployed at contract address 0xdef456. +contract My_Contract_1 { + + function my_private_function(uint a, uint b) { + uint c = a + b; + + Other_Contract other_contract = Other_Contract(0xabc123); // hard-coded + // external address + // in this e.g. + other_contract.other_private_function(a, b, c); + } +} +``` +See the other extreme [below](#mycontract1). + + +# Low-level + +## `my_contract_1` + +```rust +// The PUBLIC_INPUTS adhere to the Aztec 3 ABI for a private circuit. +fn my_private_function( + PRIVATE_INPUTS: { + unpacked_private_call_stack: [ + { + // Here's the call stack item for the call to `other_private_function` + function_signature: { + contract_address: 0xabc123, + vk_index: 0, + is_private: true, + is_contract_deployment: false, + is_callback: false, + }, + public_inputs: { + // All of the public inputs of a private function call + custom_public_inputs: [ + a, + b, + c, + ], + emitted_public_inputs: {}, + executed_callback: {}, + + output_commitments: { + // none shown in example + }, + input_nullifiers: { + // none shown in example + }, + + private_call_stack: [], + public_call_stack: [], + contract_deployment_call_stack: [], + partial_l1_call_stack: [], + callback_stack: [], + + old_private_data_tree_root, + + is_fee_payment: false, + pay_fee_from_l1: false, + pay_fee_from_public_l2: false, + called_from_l1: false, + } + call_context: { + msg_sender: 0xdef456, + storage_contract_address: 0xabc123, + }, + is_delegate_call: false, + is_static_call: false, + }, + ] + }, + PUBLIC_INPUTS: { + custom_public_inputs: [ + a, + b, + ], + emitted_public_inputs: {}, + executed_callback: {}, + + output_commitments: { + // none shown in example + }, + input_nullifiers: { + // none shown in example + }, + + private_call_stack: [ + other_contract_other_private_function_call_stack_item_hash, + ], + public_call_stack: [], + contract_deployment_call_stack: [], + partial_l1_call_stack: [], + callback_stack: [], + + old_private_data_tree_root, + + is_fee_payment: false, + pay_fee_from_l1: false, + pay_fee_from_public_l2: false, + called_from_l1: false, + } +) { + let a = PUBLIC_INPUTS.custom_public_inputs.a; + let b = PUBLIC_INPUTS.custom_public_inputs.b; + + let c = a + b; + +// Make the call: + let call_stack_item = PRIVATE_INPUTS.unpacked_private_call_stack[0]; + + // Check the correct contract address is being called. + assert(call_stack_item.function_signature.contract_address == 0x123abc); + + // Check the vkIndex (which can be inferred from the ordering of functions in + // the Other_Contract): + assert(call_stack_item.function_signature.vk_index == 0); + + // Check the correct parameters are being passed to the function: + assert(call_stack_item.public_inputs.custom_public_inputs[0] == a); + assert(call_stack_item.public_inputs.custom_public_inputs[1] == b); + assert(call_stack_item.public_inputs.custom_public_inputs[2] == c); + + // The call context will be checked in the kernel snark, so we don't need + // to check it here. + + // Calculate the callStackItemHash of the call to the other_private_function: + assert( + PUBLIC_INPUTS.private_call_stack. + other_contract_other_private_function_call_stack_item_hash + == ped::hash(call_stack_item) // Note: this is a massive hash. + // We'll eventually optimise the structures to + // to be more efficient. + ); +} +``` \ No newline at end of file diff --git a/circuits/specs/src/noir-stuff/extremes/call-public-same.md b/circuits/specs/src/noir-stuff/extremes/call-public-same.md new file mode 100644 index 00000000000..ce405e64c03 --- /dev/null +++ b/circuits/specs/src/noir-stuff/extremes/call-public-same.md @@ -0,0 +1,147 @@ +In these examples, we omit any 'other logic' and focus on making a public call. Therefore the code shown might not make much sense as a useful contract, since it won't do anything except call another function. + +# High-level + +```js +// Suppose this is deployed at contract address 0xdef456. +contract My_Contract_1 { + // vkIndex = 0 + function my_public_function(uint a, uint b, uint c) { + // do a thing + } + + // vkIndex = 1 + function my_private_function(uint a, uint b) { + uint c = a + b; + + this.my_public_function(a, b, c); + } +} +``` +See the other extreme [below](#mycontract1). + + +# Low-level + +## `my_contract_1` + +```rust +// The PUBLIC_INPUTS adhere to the Aztec 3 ABI for a private circuit. +fn my_private_function( + PRIVATE_INPUTS: { + unpacked_public_call_stack: [ + { + // Here's the call stack item for the call to `my_public_function` + function_signature: { + contract_address: 0, // `0` is understood by the private kernel + // snark to mean `address(this)`. The + // correct address will be inserted here + // in the private kernel snark. + vk_index: 0, + is_private: false, + is_contract_deployment: false, + is_callback: false, + }, + public_inputs: { + // All of the public inputs of a public function call + customPublicInputs: [ + a, + b, + c, + ], + emittedPublicInputs: {}, + executedCallback: {}, + + state_transitions: [ + // none shown in example + ], + state_reads: [ + // none shown in example + ] + + public_call_stack: [], + contract_deployment_call_stack: [], + partial_l1_call_stack: [], + callback_stack: [], + + old_private_data_tree_root, + + is_fee_payment: false, + pay_fee_from_l1: false, + called_from_l1: false, + } + call_context: { + msg_sender: 0xdef456, + storage_contract_address: 0xabc123, + }, + is_delegate_call: false, + is_static_call: false, + }, + ] + }, + PUBLIC_INPUTS: { + customPublicInputs: [ + a, + b, + ], + emittedPublicInputs: {}, + executedCallback: {}, + + output_commitments: { + // none shown in example + }, + input_nullifiers: { + // none shown in example + }, + + private_call_stack: [], + public_call_stack: [ + my_public_function_call_stack_item_hash, + ], + contract_deployment_call_stack: [], + partial_l1_call_stack: [], + callback_stack: [], + + old_private_data_tree_root, + + is_fee_payment: false, + pay_fee_from_l1: false, + pay_fee_from_public_l2: false, + called_from_l1: false, + } +) { + let a = PUBLIC_INPUTS.custom_public_inputs.a; + let b = PUBLIC_INPUTS.custom_public_inputs.b; + + let c = a + b; + +// Make the call: + let call_stack_item = PRIVATE_INPUTS.unpacked_public_call_stack[0]; + + // Check the correct contract address is being called. + // address(this) is a special case: we put 0 in this circuit, and the kernel + // circuit will insert the correct address. + assert(call_stack_item.function_signature.contract_address == 0); + + // Check the vkIndex (which can be inferred from the ordering of functions in + // this contract). + assert(call_stack_item.function_signature.vkIndex == 0); + + // Check the correct parameters are being passed to the function: + assert(call_stack_item.public_inputs.custom_public_inputs[0] == a); + assert(call_stack_item.public_inputs.custom_public_inputs[1] == b); + assert(call_stack_item.public_inputs.custom_public_inputs[2] == c); + + // The call context will be checked in the kernel snark, so we don't need + // to check it here. + + // Calculate the callStackItemHash of the call to my_public_function: + assert( + PUBLIC_INPUTS.public_call_stack. + my_public_function_call_stack_item_hash + == ped::hash(call_stack_item) // Note: this is a massive hash. + // We'll eventually optimise the structures to + // to be more efficient. + ); +} +``` \ No newline at end of file diff --git a/circuits/specs/src/noir-stuff/extremes/call-public.md b/circuits/specs/src/noir-stuff/extremes/call-public.md new file mode 100644 index 00000000000..63d12d20dbc --- /dev/null +++ b/circuits/specs/src/noir-stuff/extremes/call-public.md @@ -0,0 +1,147 @@ +In these examples, we omit any 'other logic' and focus on making a public call. Therefore the code shown might not make much sense as a useful contract, since it won't do anything except call another function. + +# High-level + +```js +// Suppose this is deployed at contract address 0xabc123. +contract Other_Contract { + // vkIndex = 0 in this example. + function other_public_function(uint a, uint b, uint c) { + // do a thing + } +} + +// Suppose this is deployed at contract address 0xdef456. +contract My_Contract_1 { + + function my_private_function(uint a, uint b) { + uint c = a + b; + + Other_Contract other_contract = Other_Contract(0xabc123); // hard-coded + // external address + // in this e.g. + other_contract.other_private_function(a, b, c); + } +} +``` +See the other extreme [below](#mycontract1). + +# Low-level + +## `my_contract_1` + +```rust +// The PUBLIC_INPUTS adhere to the Aztec 3 ABI for a private circuit. +fn my_private_function( + PRIVATE_INPUTS: { + unpacked_public_call_stack: [ + { + // Here's the call stack item for the call to `my_public_function` + function_signature: { + contract_address: 0xabc123, + vk_index: 0, + is_private: false, + is_contract_deployment: false, + is_callback: false, + }, + public_inputs: { + // All of the public inputs of a public function call + customPublicInputs: [ + a, + b, + c, + ], + emittedPublicInputs: {}, + executedCallback: {}, + + state_transitions: [ + // none shown in example + ], + state_reads: [ + // none shown in example + ] + + public_call_stack: [], + contract_deployment_call_stack: [], + partial_l1_call_stack: [], + callback_stack: [], + + old_private_data_tree_root, + + is_fee_payment: false, + pay_fee_from_l1: false, + called_from_l1: false, + } + call_context: { + msg_sender: 0xdef456, + storage_contract_address: 0xabc123, + }, + is_delegate_call: false, + is_static_call: false, + }, + ] + }, + PUBLIC_INPUTS: { + customPublicInputs: [ + a, + b, + ], + emittedPublicInputs: {}, + executedCallback: {}, + + output_commitments: { + // none shown in example + }, + input_nullifiers: { + // none shown in example + }, + + private_call_stack: [], + public_call_stack: [ + other_contract_other_public_function_call_stack_item_hash, + ], + contract_deployment_call_stack: [], + partial_l1_call_stack: [], + callback_stack: [], + + old_private_data_tree_root, + + is_fee_payment: false, + pay_fee_from_l1: false, + pay_fee_from_public_l2: false, + called_from_l1: false, + } +) { + let a = PUBLIC_INPUTS.custom_public_inputs.a; + let b = PUBLIC_INPUTS.custom_public_inputs.b; + + let c = a + b; + +// Make the call: + let call_stack_item = PRIVATE_INPUTS.unpacked_public_call_stack[0]; + + // Check the correct contract address is being called. + assert(call_stack_item.function_signature.contract_address == 0xabc123); + + // Check the vkIndex (which can be inferred from the ordering of functions in + // this contract). + assert(call_stack_item.function_signature.vkIndex == 0); + + // Check the correct parameters are being passed to the function: + assert(call_stack_item.public_inputs.custom_public_inputs[0] == a); + assert(call_stack_item.public_inputs.custom_public_inputs[1] == b); + assert(call_stack_item.public_inputs.custom_public_inputs[2] == c); + + // The call context will be checked in the kernel snark, so we don't need + // to check it here. + + // Calculate the callStackItemHash of the call to the other_public_function: + assert( + PUBLIC_INPUTS.public_call_stack. + my_public_function_call_stack_item_hash + == ped::hash(call_stack_item) // Note: this is a massive hash. + // We'll eventually optimise the structures to + // to be more efficient. + ); +} +``` \ No newline at end of file diff --git a/circuits/specs/src/noir-stuff/extremes/callback.md b/circuits/specs/src/noir-stuff/extremes/callback.md new file mode 100644 index 00000000000..c861cb29aa8 --- /dev/null +++ b/circuits/specs/src/noir-stuff/extremes/callback.md @@ -0,0 +1 @@ +See [call l1](./call-l1.md) or [claim simple](./claim-simple.md), for examples of L1 callbacks, for now. \ No newline at end of file diff --git a/circuits/specs/src/noir-stuff/extremes/claim-simple.md b/circuits/specs/src/noir-stuff/extremes/claim-simple.md new file mode 100644 index 00000000000..ce08abbb89b --- /dev/null +++ b/circuits/specs/src/noir-stuff/extremes/claim-simple.md @@ -0,0 +1,190 @@ +A real-world (ish) example of making an Aztec-Connect-like claim. + +# High-level + +```js +/******************************************************************************** + * ON-CHAIN SOLIDITY: + *******************************************************************************/ +// THIS FUNCTION IS SOLIDITY, IMPORTED SOMEHOW... +// Suppose this is deployed at L1 Portal Contract address 0xabc123. +contract L1_Portal_Contract { + function l1_swap_a_for_b(uint total_deposit_amount_a) { + // do an on-chain swap of amount_a for some amount_b + return total_amount_b; // This result is added to a results tree through + // Aztec 3's architecture. + } +} + +/******************************************************************************** + * CIRCUITS: + *******************************************************************************/ + +// Suppose this is deployed at contract address 0xdef456. +/** + * @dev This EXAMPLE contract is a hugely simplified version of a defi bridge. + * Specifically, it facilitates swaps from asset A to asset B (but not the other + * was around, for simplicity!). + * The main illustration of this example is the `secret storage slot` pointer ideas. + */ +contract My_Contract_1 { + secret mapping(address => uint) token_balances_a; // user => balance + secret mapping(address => uint) token_balances_b; // user => balance + // interaction_id => (secret_slot => amount): + mapping(uint => uint) total_deposits_a; // interaction_id => amount + mapping(uint => uint) claimable_amounts_a; // interaction_id => amount + mapping(uint => uint) claimable_amounts_b; // interaction_id => amount + uint interaction_id; + uint deposit_counter; // A counter for the currently pending interaction's num + // pending deposits so far. + struct DepositLog = { + uint deposited_amount; + uint* token_balance_a_addend_slot; // PLACEHOLDER SYNTAX (discussion welcome!) + uint* token_balance_b_addend_slot; // "pointer" decorator (like c++). + // Points to a 'secret storage slot': the pedersen hash of a + // `(storageSlot, owner, secret)` tuple. + // + // The motivation behind this syntax is to allow some _other_ user to inject + // a value into a secret storage slot, without them learning the owner, + // secret, or (in the case of mappings/arrays) the storageSlot. + } + mapping(uint => mapping(secret_slot => DepositLog)) deposit_logs_a; + + + // Private function because it edits a private state. + function user_deposit_a(amount_a) { + token_balances_a[msg_sender] -= amount_a; + add_pending_deposit_a( + amount_a, + &token_balances_a[msg_sender], // PLACEHOLDER SYNTAX (discussion welcome!) + &token_balances_b[msg_sender] // Like the "address of" operator of c++. + // Or, more accurately, the "secret storage slot of" operator. + // + // The motivation behind this syntax is to allow some _other_ user to inject + // a value into a secret storage slot, without them learning the owner, + // secret, or (in the case of mappings/arrays) the storageSlot. + // + // In this example, since `token_balances_a[msg_sender]` is a + // 'partitioned' state (a UTXO state), this `&` operator will return the + // pedersen hash of a `storageSlot, owner, secret` tuple, provided by the + // caller. + // + // This `&` operator would only be usable on secret states within a private + // function. + ); + } + + // Public function because it edits a public state. + function add_pending_deposit_a( + uint amount_a, + uint* token_balance_a_addend_slot, + uint* token_balance_b_addend_slot + ) internal { + deposit_logs_a[interaction_id][deposit_counter++] = DepositLog( + amount_a, + token_balance_a_addend_slot, + token_balance_b_addend_slot + ); + + total_deposits_a[interaction_id] += amount_a; + } + + function process_pending_deposits_a() external { + uint total_deposit_amount_a = total_deposits_a[interaction_id]; + + // An L2 function can _only_ make L1 calls to its own L1 Portal Contract + // (and not to any other L1 contract). + // Here's some pseudocode for a special 'L1Promise' type. + // Kind of like Rust's. Kind of like handling a JS Promise. + // Please make the syntax better! + // An L1 call (from L2) always must return an L1Promise. + L1Promise promise = L1_Portal_Contract.l1_swap_a_for_b(total_deposit_amount_a); + + promise.then( + result => permit_claims_b(interaction_id, result[0]), + // On success, the result will effectively be an array of values. + // Note: a result value cannot be passed to a 'secret' arg's position. + permit_claims_a(interaction_id, total_deposit_amount_a), + // On failure, nothing is returned by L1 + // (not even an error message), so the failure + // callback is executed with existing args. + ); + + ++interaction_id; + } + + // TODO: discuss this. This _would_ technically have to be called by a user + // or rollup provider, but we only want them to be able to call it as part of a + // callback. + // I put the word 'internal', but that's not quite right, perhaps. + function permit_claims_b( + uint historic_interaction_id, + uint total_amount_b + ) internal { + claimable_amounts_b[historic_interaction_id] += total_amount_b; + } + + function permit_claims_a( + uint historic_interaction_id, + uint total_amount_a + ) internal { + claimable_amounts_a[historic_interaction_id] += total_amount_a; + } + + function make_claim_a( + uint historic_interaction_id, + uint historic_deposit_counter, + ) external { + DepositLog deposit_log = + deposit_logs_a[historic_interaction_id][historic_deposit_counter]; + deposited_amount_a = deposit_log.deposited_amount; + + uint claimable_amount_a = + claimable_amounts_a[historic_interaction_id] * + ( + deposited_amount_a / + total_deposits_a[historic_interaction_id] + ); + + // PLACEHOLDER SYNTAX (discussion welcome!) + // "contents of" operator (like the c++ dereference operator). + // 'Completes' the pedersen commitment by adding a value to the + // 'secret storage slot' pointed-to by the pointer. + *deposit_log.token_balance_a_addend_slot = claimable_amount_a; + + // Prevent user from claiming again: + delete deposit_logs_a[historic_interaction_id][historic_deposit_counter]; + } + + function make_claim_b( + uint historic_interaction_id, + uint historic_deposit_counter, + ) external { + DepositLog deposit_log = + deposit_logs_a[historic_interaction_id][historic_deposit_counter]; + deposited_amount_a = deposit_log.deposited_amount; + + uint claimable_amount_b = + claimable_amounts_b[historic_interaction_id] * + ( + deposited_amount_a / + total_deposits_a[historic_interaction_id] + ); + + // PLACEHOLDER SYNTAX (discussion welcome!) + // "contents of" operator (like the c++ dereference operator). + // 'Completes' the pedersen commitment by adding a value to the + // 'secret storage slot' pointed-to by the pointer. + *deposit_log.token_balance_b_addend_slot = claimable_amount_b; + + // Prevent user from claiming again: + delete deposit_logs_a[historic_interaction_id][historic_deposit_counter]; + } +} +``` + +# Low-level + +## `user_deposit_a()` + +TODO. Very big, complex example. Will take time. \ No newline at end of file diff --git a/circuits/specs/src/noir-stuff/extremes/decr-private-owned.md b/circuits/specs/src/noir-stuff/extremes/decr-private-owned.md new file mode 100644 index 00000000000..622513f08c2 --- /dev/null +++ b/circuits/specs/src/noir-stuff/extremes/decr-private-owned.md @@ -0,0 +1,272 @@ +# High-level + +```js +contract my_contract_1 { + secret uint x; // a SECRET state + + /** + * @param amount - is annotated as SECRET so must NOT be exposed + */ + function decrement_my_own_private_state(secret uint amount) { + x -= amount; // knowledge of this private state's + // secret key is needed to make this edit. + } +} +``` +See the other extreme [below](#mycontract1). + + + +```js +contract my_contract_2 { + secret uint x; // a SECRET state + + function decrement_my_own_private_state(secret amount) { + x -= amount; // This is inferred to be a PARTITIONED state, + // due to the function below. + // Hence, we'll nullify up-to 2 part-states + // and create a new part-state equal to `x - amount` + } + + function increment_someone_elses_private_state(secret amount) { + unknown x += amount; // 'unknown' means the caller doesn't + // necessarily need to be the _owner_ + // of this private state, to make this + // edit. + // The existence of 'unknown' means this + // state must be PARTITIONED across many + // UTXOs. + } +} +``` +See the other extreme [below](#mycontract2). + + +# Low-level + +## `my_contract_1` + +```rust +// The PUBLIC_INPUTS adhere to the Aztec 3 ABI for a private circuit. +fn decrement_my_own_private_state( + PRIVATE_INPUTS: { + amount, // because the param was decorated as SECRET + + x_owner_private_key, + + x_old_value, + x_old_salt, + x_old_input_nullifier, + x_old_leaf_index, + x_old_sibling_path, + + x_new_salt, + }, + PUBLIC_INPUTS: { + custom_public_inputs: {}, // lots of unused stuff denoted by {} or []. + emitted_public_inputs: {}, + executed_callback: {}, + + output_commitments: { + x_new_commitment, + }, + input_nullifiers: { + x_old_nullifier, + }, + + private_call_stack: [], + public_call_stack: [], + contract_deployment_call_stack: [], + partial_l1_call_stack: [], + callback_stack: [], + + old_private_data_tree_root, + + is_fee_payment: false, + pay_fee_from_l1: false, + pay_fee_from_public_l2: false, + called_from_l1: false, + } +) { + + /******************************************************************************** + * NULLIFY OLD STATE + *******************************************************************************/ + + // Calculate a proof of knowledge of secret key to permit editing of this state: + x_owner_public_key = derive_public_key(x_owner_private_key); + + // Calculate commitment of the old value: + let x_old_commitment = ped::hash( + 1, // assume `x` occupies storage slot 1. + x_old_value, // value + x_owner_public_key, // owner + x_old_salt, // salt + x_old_input_nullifier // input_nullifier of some prev tx (to ensure uniqueness) + ); + + // Check x_old_commitment exists in the old tree: + merkle_check( + old_private_data_tree_root, + x_old_commitment, + x_old_leaf_index, + x_old_sibling_path, + ); + + // Nullify x_old_value: + let x_old_nullifier_check = ped::hash( + x_old_commitment, + x_owner_private_key + ) + assert(x_old_nullifier_check == x_old_nullifier); + + /******************************************************************************** + * MUTATE THE STATE + *******************************************************************************/ + + let x_new_value = x_old_value - amount; + + /******************************************************************************** + * PUSH NEW STATE + *******************************************************************************/ + + // Calculate commitments of the final value: + let x_new_commitment_check = ped::hash( + 1, // assume `x` occupies storage slot 1. + x_new_value, // value + x_owner_public_key, // owner + x_new_salt // salt + x_old_nullifier // input_nullifier + ); + assert(x_new_commitment_check == x_new_commitment); + +} +``` + + +## `my_contract_2` + +```rust +// The PUBLIC_INPUTS adhere to the Aztec 3 ABI for a private circuit. +fn decrement_my_own_private_state( + PRIVATE_INPUTS: { + amount, // because the param was decorated as SECRET + + x_owner_private_key, + + x_old_value_1, + x_old_salt_1, + x_old_input_nullifier_1, + x_old_leaf_index_1, + x_old_sibling_path_1, + + x_old_value_2, + x_old_salt_2, + x_old_input_nullifier_2, + x_old_leaf_index_2, + x_old_sibling_path_2, + + x_new_salt, + }, + PUBLIC_INPUTS: { + custom_public_inputs: {}, // lots of unused stuff denoted by {} or []. + emitted_public_inputs: {}, + executed_callback: {}, + + output_commitments: { + x_new_commitment, + }, + input_nullifiers: { + x_old_nullifier_1, + x_old_nullifier_2, + }, + + private_call_stack: [], + public_call_stack: [], + contract_deployment_call_stack: [], + partial_l1_call_stack: [], + callback_stack: [], + + old_private_data_tree_root, + + is_fee_payment: false, + pay_fee_from_l1: false, + pay_fee_from_public_l2: false, + called_from_l1: false, + } +) { + + /******************************************************************************** + * NULLIFY OLD STATE + *******************************************************************************/ + + // Calculate a proof of knowledge of secret key to permit editing of this state: + x_owner_public_key = derive_public_key(x_owner_private_key); + + // Calculate commitments of the old values: + let x_old_commitment_1 = ped::hash( + 1, // assume `x` occupies storage slot 1. + x_old_value_1, // value + x_owner_public_key, // owner + x_old_salt_1, // salt + x_old_input_nullifier_1 // input_nullifier of some prev tx (to ensure uniqueness) + ); + + let x_old_commitment_2 = ped::hash( + 1, // assume `x` occupies storage slot 1. + x_old_value_2, // value + x_owner_public_key, // owner + x_old_salt_2, // salt + x_old_input_nullifier_2 // input_nullifier of some prev tx (to ensure uniqueness) + ); + + // Check old commitments exists in the old tree: + merkle_check( + old_private_data_tree_root, + x_old_commitment_1, + x_old_leaf_index_1, + x_old_sibling_path_1, + ); + + merkle_check( + old_private_data_tree_root, + x_old_commitment_2, + x_old_leaf_index_2, + x_old_sibling_path_2, + ); + + // Nullify old commitments: + let x_old_nullifier_check_1 = ped::hash( + x_old_commitment_1, + x_owner_private_key + ) + assert(x_old_nullifier_check_1 == x_old_nullifier_1); + + let x_old_nullifier_check_2 = ped::hash( + x_old_commitment_2, + x_owner_private_key + ) + assert(x_old_nullifier_check_2 == x_old_nullifier_2); + + /******************************************************************************** + * MUTATE THE STATE + *******************************************************************************/ + + let x_new_value = x_old_value_1 + x_old_value_2 - amount; + + /******************************************************************************** + * PUSH NEW STATE + *******************************************************************************/ + + // Calculate commitments of the final value: + let x_new_commitment_check = ped::hash( + 1, // assume `x` occupies storage slot 1. + x_new_value, // value + x_owner_public_key, // owner + x_new_salt // salt + x_old_nullifier_1 // input_nullifier + ); + assert(x_new_commitment_check == x_new_commitment); + +} +``` \ No newline at end of file diff --git a/circuits/specs/src/noir-stuff/extremes/deploy-contract.md b/circuits/specs/src/noir-stuff/extremes/deploy-contract.md new file mode 100644 index 00000000000..a9ec63dfa74 --- /dev/null +++ b/circuits/specs/src/noir-stuff/extremes/deploy-contract.md @@ -0,0 +1,293 @@ +This is an example of deploying a contract _from within_ another contract. + +The `DeplotTest` contract deploys the `Test` contract. + + +# High-level + + +```js +// Suppose this contract will be deployed to address 0xdef456 by the DeployTest +// contract. +contract Test { + uint a; + secret uint b; + + private_constructor(secret uint _b) public { + b += _b; // Assume it's a partitioned state (so it can only be incremented + // or decremented). + } + + public_constructor(uint _a) public { + a = _a; + } +} + +// Suppose this contract is already deployed at address 0xabc123. +contract DeployTest { + function deploy() public { + new Test{ + salt: 0xfedcba, + private_constructor_args: [123], + public_constructor_args: [456], + }; + } +} +``` + +`contractAddress = hash(deployerAddress, salt, vkRoot, constructorHash)` + + +# Low-level +## `DeployTest` + +### `deploy()` + +Note: because the `deploy()` function makes a call to a _private_ constructor, `deploy()` must be a private function itself (since only private functions and L1 functions can call private functions). + +```rust +// The PUBLIC_INPUTS adhere to the Aztec 3 ABI for a private circuit. +fn deploy( + PRIVATE_INPUTS: { + // This unpacked data is needed because this function passes specific + // constructor arguments to the constructors, and a specific salt to define + // the new contract's address. We need this circuit to check they're + // included in the contract_deployment_call_stack_item_hash. + // TODO: hashing _all_ of this data is inefficient. Eventually we'll need to + // optimise this in the architecture. + unpacked_contract_deployment_call_stack: [ + { + unpacked_data: { + private_constructor_public_inputs, // This preimage is needed to + // validate the constructor args. + public_constructor_public_inputs, // ... and this. + }, + call_stack_item: { + // Here's the call stack item for the contract deployment call. + // Notice: no function signature for contract deployment calls. + public_inputs: { + private_constructor_public_inputs_hash, // TODO: consider having the unpacked public inputs here instead, for ease. + public_constructor_public_inputs_hash, + private_constructor_vk_hash, + public_constructor_vk_hash, + contract_address, + salt, + vk_root, + circuit_data_keccak_hash, // optional, passes straight through + // unchecked. + portal_contract_address, + }, + // NOT SURE IF A CALL CONTEXT ACTUALLY NEEDS TO BE PROVIDED HERE. + call_context: { + msg_sender: 0xabc123, // The address of the entity making the call; + // in this case, the DeployTest contract's + // address. + storage_contract_address: 0xdef456, // This can be calculated in + // advance by the caller, since new contract addresses are + // deterministic. + }, + is_delegate_call: false, + is_static_call: false, + }, + }, + ], + }, + PUBLIC_INPUTS: { + custom_public_inputs: [], + emitted_public_inputs: {}, + executed_callback: {}, + + output_commitments: {}, + input_nullifiers: {}, + + private_call_stack: [], + public_call_stack: [], + contract_deployment_call_stack: [ + test_contract_call_stack_item_hash, + ], + partial_l1_call_stack: [], + callback_stack: [], + + old_private_data_tree_root, + + is_fee_payment: false, + pay_fee_from_l1: false, + pay_fee_from_public_l2: false, + called_from_l1: false, + } +) { + +// Make the 'contract deployment' call: +// We need to ensure the parameters being passed to the constructors are as expected. + let { + unpacked_data, + call_stack_item + } = PRIVATE_INPUTS.unpacked_contract_deployment_call_stack[0]; + let { + private_constructor_public_inputs_hash, + public_constructor_public_inputs_hash, + contract_address, + salt, + } = call_stack_item; + let { + private_constructor_public_inputs, + public_constructor_public_inputs, + } = unpacked_data; + + + + // Check the correct parameters are being passed to the constructors: + assert(private_constructor_public_inputs.custom_public_inputs[0] == 123); + assert(public_constructor_public_inputs.custom_public_inputs[0] == 456); + + // The call contexts will be checked in the kernel snark, so we don't need + // to check it here. + +// Calculate the callStackItemHashes of the constructor calls: + // First calculate the public input hashes: + assert(private_constructor_public_inputs_hash == + ped::hash(private_constructor_public_inputs); + // Note: this is a massive hash. TODO: We'll eventually optimise the structures to + // to be more efficient. + ); + assert(public_constructor_public_inputs_hash == + ped::hash(public_constructor_public_inputs); + // Note: this is a massive hash. TODO: We'll eventually optimise the structures to + // to be more efficient. + ); + + // Check the contract address uses the provided `salt = 0xfedcba`: + assert(salt == 0xfedcba); + + assert(PUBLIC_INPUTS.contract_deployment_call_stack[0] == + ped::hash(call_stack_item)); + + // Notice: other public inputs of the contractDeploymentCallStackItem + // (such as vk hashes, the vk root, the portal contract address) aren't + // checked here. Those checks will be done by the contract deployment + // kernel circuit, and by users validating/reconciling the code for themselves. +} +``` + +### private constructor circuit + +```js +fn private_constructor( + PRIVATE_INPUTS: { + + b_owner_public_key, + + b_old_dummy_commitment, + b_old_dummy_private_key, + + b_new_salt, + }, + PUBLIC_INPUTS: { + custom_public_inputs: [ + _b, // Although this param was decorated as `secret`, it cannot be a + // private input to the circuit, because it's passed into the circuit + // by another circuit (which must validate the correctness of the + // value being passed in). + // It will still be hidden from the world, since the private kernel + // circuit will swallow all custom_public_inputs, unless they're also + // emitted as events. + // TODO: prevent `secret` params from being exposed by an app via + // the `emittedPublicInputs` or call stacks, so that the kernel circuit + // does indeed swallow the secret param with no leaks. + ], + emitted_public_inputs: {}, + executed_callback: {}, + + output_commitments: { + b_new_commitment, + }, + input_nullifiers: { + b_old_dummy_nullifier, // dummy + }, + + private_call_stack: [], + public_call_stack: [], + contract_deployment_call_stack: [], + partial_l1_call_stack: [], + callback_stack: [], + + old_private_data_tree_root, + + is_fee_payment: false, + pay_fee_from_l1: false, + pay_fee_from_public_l2: false, + called_from_l1: false, + } + +) { + // Calculate a proof of knowledge of secret key to permit editing of this state: + x_owner_public_key = derive_public_key(x_owner_private_key); + + // Compute dummy nullifier: + let b_old_dummy_nullifier_check = ped::hash( + b_old_dummy_commitment, + b_old_dummy_private_key, + is_dummy = true, + ) + assert(b_old_dummy_nullifier_check == b_old_dummy_nullifier); + + + // Calculate a commitment to the new 'part' of the state: + let b_new_commitment_check = ped::hash( + 2, // assume `b` occupies storage slot 2. + _b, // value + b_owner_public_key, // owner + b_new_salt // salt + b_old_dummy_nullifier // input_nullifier + ); + assert(b_new_commitment_check == b_new_commitment); +} +``` + +### public constructor circuit + +```rust +// The PUBLIC_INPUTS adhere to the Aztec 3 ABI for a private circuit. +fn public_constructor( + PRIVATE_INPUTS: {}, + PUBLIC_INPUTS: { + customPublicInputs: [ + _a, + ], + emittedPublicInputs: {}, + executedCallback: {}, + + state_transitions: [ + [a_storage_slot, a_old_value, a_new_value], + // The old and new values will be provided by the rollup provider at the + // time of execution. + ], + state_reads: [ + // none shown in example + ] + + private_call_stack: [], + public_call_stack: [], + contract_deployment_call_stack: [], + partial_l1_call_stack: [], + callback_stack: [], + + old_private_data_tree_root, + + is_fee_payment: false, + pay_fee_from_l1: false, + pay_fee_from_public_l2: false, + called_from_l1: false, + } +) { + let amount = PUBLIC_INPUTS.custom_public_inputs.amount; + +// Perform the calculation (for example): + require(a_storage_slot == 1); + let a_new_value_check = _a; + require(a_new_value_check == a_new_value); + +// That's it. The public _kernel_ circuit is the circuit which does membership +// checks of the old value and inserts the new value into the public data tree. +} +``` \ No newline at end of file diff --git a/circuits/specs/src/noir-stuff/extremes/edit-public.md b/circuits/specs/src/noir-stuff/extremes/edit-public.md new file mode 100644 index 00000000000..78c44109adc --- /dev/null +++ b/circuits/specs/src/noir-stuff/extremes/edit-public.md @@ -0,0 +1,66 @@ +In these examples, we omit any 'other logic' and focus on editing a public state. Therefore the code shown might not make much sense as a useful contract, since it won't do anything except edit a single state. + +# High-level + +```js +// Suppose this is deployed at contract address 0xdef456. +contract My_Contract_1 { + + uint x; // a PUBLIC state at storage slot 1 of this contract. + + function my_public_function(uint amount) { + x += amount; + } +} +``` +See the other extreme [below](#mycontract1). + +# Low-level + +## `my_contract_1` + +```rust +// The PUBLIC_INPUTS adhere to the Aztec 3 ABI for a private circuit. +fn my_public_function( + PRIVATE_INPUTS: {}, + PUBLIC_INPUTS: { + customPublicInputs: [ + amount, + ], + emittedPublicInputs: {}, + executedCallback: {}, + + state_transitions: [ + [x_storage_slot, x_old_value, x_new_value], + // The old and new values will be provided by the rollup provider at the + // time of execution. + ], + state_reads: [ + // none shown in example + ] + + private_call_stack: [], + public_call_stack: [], + contract_deployment_call_stack: [], + partial_l1_call_stack: [], + callback_stack: [], + + old_private_data_tree_root, + + is_fee_payment: false, + pay_fee_from_l1: false, + pay_fee_from_public_l2: false, + called_from_l1: false, + } +) { + let amount = PUBLIC_INPUTS.custom_public_inputs.amount; + +// Perform the calculation: + require(x_storage_slot == 1); + let x_new_value_check = x_old_value + amount; + require(x_new_value_check == x_new_value); + +// That's it. The public _kernel_ circuit is the circuit which does membership +// checks of the old value and inserts the new value into the public data tree. +} +``` \ No newline at end of file diff --git a/circuits/specs/src/noir-stuff/extremes/emit-event.md b/circuits/specs/src/noir-stuff/extremes/emit-event.md new file mode 100644 index 00000000000..67b8fb06e58 --- /dev/null +++ b/circuits/specs/src/noir-stuff/extremes/emit-event.md @@ -0,0 +1,109 @@ +In these examples, we omit any 'other logic' and focus on emitting an event from a circuit. + +# High-level + +```js +/******************************************************************************** + * ON-CHAIN SOLIDITY: + *******************************************************************************/ + +// THIS FUNCTION IS SOLIDITY, IMPORTED SOMEHOW... +// Suppose this is deployed at L1 Portal Contract address 0xabc123. +contract L1_Contract { + function l1_to_l2_call() { + // Code not shown here because it's a faff, but imagine this function + // passes a callStackItemHash to the Rollup Processor. + // See the ERC20 'deposit' example in this book for _much_ more + // smart contract detail. + // Call the RollupProcessor contract: + rollupProcessor.callL2AndPayFee( + l2CallHash, + callback, + callbackOnCancel, + l2Fee, + l2FeeCurrency, + ); + } + + function callback_after_l2_function_executed( + uint256 l2CallHash, + uint256 callIndex, + bytes functionSignature, + uint256[4] emittedPublicInputs, // THIS IS EVENT DATA FROM L2! + ) { + // Logic to validate the functionSignature, emittedPublicInputs were as + // expected. E.g.: + require(emittedPublicInputs[0] == 123); + require(emittedPublicInputs[1] == 456); + // The l2CallHash & callIndex can be used to lookup data from when the + // l1_to_l2_call was originally made. + } +} + +/******************************************************************************** + * CIRCUITS: + *******************************************************************************/ + +// Suppose this is deployed at contract address 0xdef456. +contract My_Contract_1 { + + event MyEvent(uint param1, uint param2); + + function called_by_l1(uint a, uint b) { + // do some stuff + emit MyEvent(123, 456); + } +} +``` +See the other extreme [below](#mycontract1). + +# Low-level + +## `my_contract_1` + +```rust +// The PUBLIC_INPUTS adhere to the Aztec 3 ABI for a private circuit. +fn called_by_l1( + PRIVATE_INPUTS: { + // none shown + }, + PUBLIC_INPUTS: { + custom_public_inputs: [ + a, + b, + ], + emitted_public_inputs: [ + 123, + 456, + ], + executed_callback: {}, + + output_commitments: { + // none shown in example + }, + input_nullifiers: { + // none shown in example + }, + + private_call_stack: [ + other_contract_other_private_function_call_stack_item_hash, + ], + public_call_stack: [], + contract_deployment_call_stack: [], + partial_l1_call_stack: [], + callback_stack: [], + + old_private_data_tree_root, + + is_fee_payment: false, + pay_fee_from_l1: false, + pay_fee_from_public_l2: false, + called_from_l1: false, + } +) { + // Noddy example: + let { emitted_public_inputs } = PUBLIC_INPUTS; + assert(emitted_public_inputs[0] == 123); + assert(emitted_publit_inputs[1] == 456); +} +``` \ No newline at end of file diff --git a/circuits/specs/src/noir-stuff/extremes/extremes.md b/circuits/specs/src/noir-stuff/extremes/extremes.md new file mode 100644 index 00000000000..1ee1cad6c96 --- /dev/null +++ b/circuits/specs/src/noir-stuff/extremes/extremes.md @@ -0,0 +1,28 @@ +# Extremes + +This is all investigative. + +This section sets out (in non-Noir pseudocode) what Noir functions might look like in two extremes: +(TODO: feel free to update these to Noir syntax) +- Extreme 1: Noir knows all about the architecture of Aztec 3, and so can abstract all of the 'inner workings' of Aztec 3 away from the developer. +- Extreme 2: Noir doesn't know any of the inner workings of Aztec 3, and so the developer would have to manually write circuits which exactly conform to Aztec 3's architecture. + +We'll probably end up somewhere in the middle. + +## Examples covered: + +- [incrementation of private state _not_ owned by caller](./incr-private-not-owned.md) + - Note: if a private state is _not_ owned by the caller, then this is the only mutation that can safely be done on that state. This is because the caller cannot know the current value of the state they're modifying. So they can only safely add to it. (Unless we relax some design constraints, perhaps). +- [incrementation of private state owned by the caller](./incr-private-owned.md) +- [decrementation of private state owned by the caller](./decr-private-owned.md) +- [editing a public state](./edit-public.md) +- [reading a public state](./read-public.md) +- [calling a private function of a different contract](./call-private.md) +- [calling a public function of a different contract](./call-public.md) +- [calling a public function from a private function of the same contract](./call-public-same.md) +- [calling an L1 function](./call-l1.md) +- [emitting an 'event'](./emit-event.md) +- [executing a function as a callback, following an L1 result](./callback.md) +- [deploying a contract from a private/public function](./deploy-contract.md) +- [new contract constructors]() +- ['globally' available variables](./global-vars.md) \ No newline at end of file diff --git a/circuits/specs/src/noir-stuff/extremes/global-vars.md b/circuits/specs/src/noir-stuff/extremes/global-vars.md new file mode 100644 index 00000000000..5d1dff564ed --- /dev/null +++ b/circuits/specs/src/noir-stuff/extremes/global-vars.md @@ -0,0 +1,10 @@ +TODO. + +There are a few things which have special meaning, or are global 'blockchain' states like: +- `msg_sender` +- `min_timestamp` +- `block.timestamp` +- `block.number` +etc. + +Not properly spec'd yet. diff --git a/circuits/specs/src/noir-stuff/extremes/incr-private-not-owned.md b/circuits/specs/src/noir-stuff/extremes/incr-private-not-owned.md new file mode 100644 index 00000000000..7a37b8012c3 --- /dev/null +++ b/circuits/specs/src/noir-stuff/extremes/incr-private-not-owned.md @@ -0,0 +1,83 @@ +# High-level + +```js +contract my_contract_3 { + secret uint x; // a SECRET state + + function increment_someone_elses_private_state(secret amount) { + unknown x += amount; // 'unknown' means the caller doesn't + // necessarily need to be the _owner_ + // of this private state, to make this + // edit. + // The existence of 'unknown' means this + // state must be PARTITIONED across many + // UTXOs. + } +} +``` +See the other extreme [below](#mycontract1). + + +# Low-level + +## my_contract_1 + +```rust +// The PUBLIC_INPUTS adhere to the Aztec 3 ABI for a private circuit. +fn increment_someone_elses_private_state( + PRIVATE_INPUTS: { + amount, // because the param was decorated as SECRET + + x_owner_public_key, + + x_old_dummy_commitment, + x_old_dummy_private_key, + + x_new_salt, + }, + PUBLIC_INPUTS: { + custom_public_inputs: {}, // lots of unused stuff denoted by {} or []. + emitted_public_inputs: {}, + executed_callback: {}, + + output_commitments: { + x_new_commitment, + }, + input_nullifiers: { + x_old_dummy_nullifier, + }, + + private_call_stack: [], + public_call_stack: [], + contract_deployment_call_stack: [], + partial_l1_call_stack: [], + callback_stack: [], + + old_private_data_tree_root, + + is_fee_payment: false, + pay_fee_from_l1: false, + pay_fee_from_public_l2: false, + called_from_l1: false, + } +) { + // Compute dummy nullifier: + let x_old_dummy_nullifier_check = ped::hash( + x_old_dummy_commitment, + x_old_dummy_private_key, + is_dummy = true, + ) + assert(x_old_dummy_nullifier_check == x_old_dummy_nullifier); + + + // Calculate a commitment to the new 'part' of the state: + let x_new_commitment_check = ped::hash( + 1, // assume `x` occupies storage slot 1. + amount, // value + x_owner_public_key, // owner + x_new_salt // salt + x_old_dummy_nullifier // input_nullifier + ); + assert(x_new_commitment_check == x_new_commitment); +} +``` \ No newline at end of file diff --git a/circuits/specs/src/noir-stuff/extremes/incr-private-owned.md b/circuits/specs/src/noir-stuff/extremes/incr-private-owned.md new file mode 100644 index 00000000000..7bf3e3ebd7d --- /dev/null +++ b/circuits/specs/src/noir-stuff/extremes/incr-private-owned.md @@ -0,0 +1,286 @@ +# High-level + +```js +contract my_contract_1 { + secret uint x; // a SECRET state + + /** + * @param amount - is annotated as SECRET so must NOT be exposed + */ + function increment_my_own_private_state(secret uint amount) { + x += amount; // knowledge of this private state's + // secret key is needed to make this edit. + } +} +``` +See the other extreme [below](#mycontract1). + + +```js +contract my_contract_2 { + secret uint x; // a SECRET state + + /** + * @param amount - is NOT annotated as SECRET so must be exposed + */ + function increment_my_own_private_state(uint amount) { + x += amount; // knowledge of this private state's + // secret key is needed to make this edit. + } +} +``` +See the other extreme [below](#mycontract2). + +# Low-level + +```js +contract my_contract_3 { + secret uint x; // a SECRET state + + // Weird quirk: there'll be no difference in these two circuits in this case. + function increment_my_own_private_state(secret amount) { + x += amount; // This is inferred to be a PARTITIONED state, + // due to the function below. + // That makes this incrementation nonsensical, + // since _anyone_ can add a 'part' to this + // state, owned by themselves. + // We can compile it, but it's dangerous. + } + + function increment_someone_elses_private_state(secret amount) { + unknown x += amount; // 'unknown' means the caller doesn't + // necessarily need to be the _owner_ + // of this private state, to make this + // edit. + // The existence of 'unknown' means this + // state must be PARTITIONED across many + // UTXOs. + } +} +``` +See the other extreme [below](#mycontract3). + + + +## `my_contract_1`: + +```rust +// The PUBLIC_INPUTS adhere to the Aztec 3 ABI for a private circuit. +fn increment_my_own_private_state( + PRIVATE_INPUTS: { + amount, // because the param was decorated as SECRET + + x_owner_private_key, + + x_old_value, + x_old_salt, + x_old_input_nullifier, + x_old_leaf_index, + x_old_sibling_path, + + x_new_salt, + }, + PUBLIC_INPUTS: { + custom_public_inputs: {}, // lots of unused stuff denoted by {} or []. + emitted_public_inputs: {}, + executed_callback: {}, + + output_commitments: { + x_new_commitment, + }, + input_nullifiers: { + x_old_nullifier, + }, + + private_call_stack: [], + public_call_stack: [], + contract_deployment_call_stack: [], + partial_l1_call_stack: [], + callback_stack: [], + + old_private_data_tree_root, + + is_fee_payment: false, + pay_fee_from_l1: false, + pay_fee_from_public_l2: false, + called_from_l1: false, + } +) { + + // Calculate a proof of knowledge of secret key to permit editing of this state: + x_owner_public_key = derive_public_key(x_owner_private_key); + + // Calculate commitment of the old value: + let x_old_commitment = ped::hash( + 1, // assume `x` occupies storage slot 1. + x_old_value, // value + x_owner_public_key, // owner + x_old_salt, // salt + x_old_input_nullifier // input_nullifier of some prev tx (to ensure uniqueness) + ); + + // Check x_old_commitment exists in the old tree: + merkle_check( + old_private_data_tree_root, + x_old_commitment, + x_old_leaf_index, + x_old_sibling_path, + ); + + // Nullify x_old_value: + let x_old_nullifier_check = ped::hash( + x_old_commitment, + x_owner_private_key + ) + assert(x_old_nullifier_check == x_old_nullifier); + + /******************************************************************************* + MUTATE THE STATE + *******************************************************************************/ + + let x_new_value = x_old_value + amount; + + //****************************************************************************** + + // Calculate commitments of the final value: + let x_new_commitment_check = ped::hash( + 1, // assume `x` occupies storage slot 1. + x_new_value, // value + x_owner_public_key, // owner + x_new_salt // salt + x_old_nullifier // input_nullifier + ); + assert(x_new_commitment_check == x_new_commitment); + +} +``` + +## `my_contract_2` + +Exactly the same as `my_contract_1.increment_my_own_private_state()`, except the `amount` parameter has not been decorated as `secret`, and so it must be made public. Therefore it gets put in `PUBLIC_INPUTS.customPublicInputs` instead of being in the `PRIVATE_INPUTS`. + + +## `my_contract_3`: + +```rust +// The PUBLIC_INPUTS adhere to the Aztec 3 ABI for a private circuit. +fn increment_my_own_private_state( + PRIVATE_INPUTS: { + amount, // because the param was decorated as SECRET + + x_owner_private_key, + + x_old_dummy_commitment, + x_old_dummy_private_key, + + x_new_salt, + }, + PUBLIC_INPUTS: { + customPublicInputs: {}, // lots of unused stuff denoted by {} or []. + emittedPublicInputs: {}, + executedCallback: {}, + + output_commitments: { + x_new_commitment, + }, + input_nullifiers: { + x_old_dummy_nullifier, + }, + + private_call_stack: [], + public_call_stack: [], + contract_deployment_call_stack: [], + partial_l1_call_stack: [], + callback_stack: [], + + old_private_data_tree_root, + + is_fee_payment: false, + pay_fee_from_l1: false, + pay_fee_from_public_l2: false, + called_from_l1: false, + } +) { + // Calculate a proof of knowledge of secret key to permit editing of this state: + x_owner_public_key = derive_public_key(x_owner_private_key); + + // Compute dummy nullifier: + let x_old_dummy_nullifier_check = ped::hash( + x_old_dummy_commitment, + x_old_dummy_private_key, + is_dummy = true, + ) + assert(x_old_dummy_nullifier_check == x_old_dummy_nullifier); + + + // Calculate a commitment to the new 'part' of the state: + let x_new_commitment_check = ped::hash( + 1, // assume `x` occupies storage slot 1. + amount, // value + x_owner_public_key, // owner + x_new_salt // salt + x_old_dummy_nullifier // input_nullifier + ); + assert(x_new_commitment_check == x_new_commitment); +} + + + +// The PUBLIC_INPUTS adhere to the Aztec 3 ABI for a private circuit. +fn increment_someone_elses_private_state( + PRIVATE_INPUTS: { + amount, // because the param was decorated as SECRET + + x_owner_public_key, + + x_old_dummy_commitment, + x_old_dummy_private_key, + + x_new_salt, + }, + PUBLIC_INPUTS: { + custom_public_inputs: {}, // lots of unused stuff denoted by {} or []. + emitted_public_inputs: {}, + executed_callback: {}, + + output_commitments: { + x_new_commitment, + }, + input_nullifiers: { + x_old_dummy_nullifier, + }, + + private_call_stack: [], + public_call_stack: [], + contract_deployment_call_stack: [], + partial_l1_call_stack: [], + callback_stack: [], + + old_private_data_tree_root, + + is_fee_payment: false, + pay_fee_from_l1: false, + pay_fee_from_public_l2: false, + called_from_l1: false, + } +) { + // Compute dummy nullifier: + let x_old_dummy_nullifier_check = ped::hash( + x_old_dummy_commitment, + x_old_dummy_private_key, + is_dummy = true, + ) + assert(x_old_dummy_nullifier_check == x_old_dummy_nullifier); + + + // Calculate a commitment to the new 'part' of the state: + let x_new_commitment_check = ped::hash( + 1, // assume `x` occupies storage slot 1. + amount, // value + x_owner_public_key, // owner + x_new_salt // salt + x_old_dummy_nullifier // input_nullifier + ); + assert(x_new_commitment_check == x_new_commitment); +} +``` \ No newline at end of file diff --git a/circuits/specs/src/noir-stuff/extremes/read-public.md b/circuits/specs/src/noir-stuff/extremes/read-public.md new file mode 100644 index 00000000000..4fdaebad1d3 --- /dev/null +++ b/circuits/specs/src/noir-stuff/extremes/read-public.md @@ -0,0 +1,67 @@ +In these examples, we omit any 'other logic' and focus on reading a public state. Therefore the code shown might not make much sense as a useful contract, since it won't do anything except read a single state. + +# High-level + +```js +// Suppose this is deployed at contract address 0xdef456. +contract My_Contract_1 { + + uint x; // a PUBLIC state at storage slot 1 of this contract. + uint y; // a PUBLIC state at storage slot 2 of this contract. + + function my_public_function() { + x += y; // so we _read_ y (and _edit_ x). + } +} +``` +See the other extreme [below](#mycontract1). + + +# Low-level + +## `my_contract_1` + +```rust +// The PUBLIC_INPUTS adhere to the Aztec 3 ABI for a private circuit. +fn my_private_function( + PRIVATE_INPUTS: {}, + PUBLIC_INPUTS: { + customPublicInputs: [], + emittedPublicInputs: {}, + executedCallback: {}, + + state_transitions: [ + [x_storage_slot, x_old_value, x_new_value], + // The old and new values will be provided by the rollup provider at the + // time of execution. + ], + state_reads: [ + [y_storage_slot, y_current_value], + ] + + private_call_stack: [], + public_call_stack: [], + contract_deployment_call_stack: [], + partial_l1_call_stack: [], + callback_stack: [], + + old_private_data_tree_root, + + is_fee_payment: false, + pay_fee_from_l1: false, + pay_fee_from_public_l2: false, + called_from_l1: false, + } +) { + let amount = PUBLIC_INPUTS.custom_public_inputs.amount; + +// Perform the calculation: + require(x_storage_slot == 1); + require(y_storage_slot == 2); + let x_new_value_check = x_old_value + y_current_value; // this is the read. + require(x_new_value_check == x_new_value); + +// That's it. The public _kernel_ circuit is the circuit which does membership +// checks of the current value in the public data tree. +} +``` \ No newline at end of file diff --git a/circuits/specs/src/noir-stuff/noir-stuff.md b/circuits/specs/src/noir-stuff/noir-stuff.md new file mode 100644 index 00000000000..7a2a4c5a440 --- /dev/null +++ b/circuits/specs/src/noir-stuff/noir-stuff.md @@ -0,0 +1,4 @@ +# Noir Stuff + +Various things to consider when designing how Noir and Aztec 3 could interoperate. + diff --git a/circuits/specs/theme/css/general.css b/circuits/specs/theme/css/general.css new file mode 100644 index 00000000000..a5cba4ecf16 --- /dev/null +++ b/circuits/specs/theme/css/general.css @@ -0,0 +1,215 @@ +/* Base styles and content styles */ + +@import 'variables.css'; + +:root { + /* Browser default font-size is 16px, this way 1 rem = 10px */ + font-size: 62.5%; +} + +html { + font-family: 'Open Sans', sans-serif; + color: var(--fg); + background-color: var(--bg); + text-size-adjust: none; + -webkit-text-size-adjust: none; +} + +body { + margin: 0; + font-size: 1.6rem; + overflow-x: hidden; +} + +code { + font-family: 'Source Code Pro', Consolas, 'Ubuntu Mono', Menlo, 'DejaVu Sans Mono', monospace, monospace !important; + font-size: 0.875em; /* please adjust the ace font size accordingly in editor.js */ +} + +/* Don't change font size in headers. */ +h1 code, +h2 code, +h3 code, +h4 code, +h5 code, +h6 code { + font-size: unset; +} + +.left { + float: left; +} +.right { + float: right; +} +.boring { + opacity: 0.6; +} +.hide-boring .boring { + display: none; +} +.hidden { + display: none !important; +} + +h2, +h3 { + margin-top: 2.5em; +} +h4, +h5 { + margin-top: 2em; +} + +.header + .header h3, +.header + .header h4, +.header + .header h5 { + margin-top: 1em; +} + +h1:target::before, +h2:target::before, +h3:target::before, +h4:target::before, +h5:target::before, +h6:target::before { + display: inline-block; + content: '»'; + margin-left: -30px; + width: 30px; +} + +/* This is broken on Safari as of version 14, but is fixed + in Safari Technology Preview 117 which I think will be Safari 14.2. + https://bugs.webkit.org/show_bug.cgi?id=218076 +*/ +:target { + scroll-margin-top: calc(var(--menu-bar-height) + 0.5em); +} + +.page { + outline: 0; + padding: 0 var(--page-padding); + margin-top: calc(0px - var(--menu-bar-height)); /* Compensate for the #menu-bar-hover-placeholder */ +} +.page-wrapper { + box-sizing: border-box; +} +.js:not(.sidebar-resizing) .page-wrapper { + transition: margin-left 0.3s ease, transform 0.3s ease; /* Animation: slide away */ +} + +.content { + overflow-y: auto; + padding: 0 15px; + padding-bottom: 50px; +} +.content main { + margin-left: auto; + /* margin-left: calc(50% - var(--content-max-width) / 2 - 100px); */ + margin-right: auto; + max-width: var(--content-max-width); +} +.content p { + line-height: 1.45em; +} +.content ol { + line-height: 1.45em; +} +.content ul { + line-height: 1.45em; +} +.content a { + text-decoration: none; +} +.content a:hover { + text-decoration: underline; +} +.content img, +.content video { + max-width: 100%; +} +.content .header:link, +.content .header:visited { + color: var(--fg); +} +.content .header:link, +.content .header:visited:hover { + text-decoration: none; +} + +table { + margin: 0 auto; + border-collapse: collapse; +} +table td { + padding: 3px 20px; + border: 1px var(--table-border-color) solid; +} +table thead { + background: var(--table-header-bg); +} +table thead td { + font-weight: 700; + border: none; +} +table thead th { + padding: 3px 20px; +} +table thead tr { + border: 1px var(--table-header-bg) solid; +} +/* Alternate background colors for rows */ +table tbody tr:nth-child(2n) { + background: var(--table-alternate-bg); +} + +blockquote { + margin: 20px 0; + padding: 0 20px; + color: var(--fg); + background-color: var(--quote-bg); + border-top: 0.1em solid var(--quote-border); + border-bottom: 0.1em solid var(--quote-border); +} + +:not(.footnote-definition) + .footnote-definition, +.footnote-definition + :not(.footnote-definition) { + margin-top: 2em; +} +.footnote-definition { + font-size: 0.9em; + margin: 0.5em 0; +} +.footnote-definition p { + display: inline; +} + +.tooltiptext { + position: absolute; + visibility: hidden; + color: #fff; + background-color: #333; + transform: translateX(-50%); /* Center by moving tooltip 50% of its width left */ + left: -8px; /* Half of the width of the icon */ + top: -35px; + font-size: 0.8em; + text-align: center; + border-radius: 6px; + padding: 5px 8px; + margin: 5px; + z-index: 1000; +} +.tooltipped .tooltiptext { + visibility: visible; +} + +.chapter li.part-title { + color: var(--sidebar-fg); + margin: 5px 0px; + font-weight: bold; +} + +.result-no-output { + font-style: italic; +} diff --git a/circuits/specs/theme/css/style.css b/circuits/specs/theme/css/style.css new file mode 100644 index 00000000000..38f3985c97b --- /dev/null +++ b/circuits/specs/theme/css/style.css @@ -0,0 +1,42 @@ +@media only screen and (max-width: 1439px) { + .sidetoc { + display: none; + } +} + +@media only screen and (min-width: 1440px) { + main { + position: relative; + } + .sidetoc { + margin-left: auto; + margin-right: auto; + left: calc(100% + (var(--content-max-width)) / 4 - 140px); + position: absolute; + } + .pagetoc { + position: fixed; + width: 200px; + height: calc(100vh - var(--menu-bar-height) - 0.67em * 4); + overflow: auto; + } + .pagetoc a { + border-left: 1px solid var(--sidebar-bg); + color: var(--fg) !important; + display: block; + padding-bottom: 5px; + padding-top: 5px; + padding-left: 10px; + text-align: left; + text-decoration: none; + } + .pagetoc a:hover, + .pagetoc a.active { + background: var(--sidebar-bg); + color: var(--sidebar-fg) !important; + } + .pagetoc .active { + background: var(--sidebar-bg); + color: var(--sidebar-fg); + } +} diff --git a/circuits/specs/theme/css/variables.css b/circuits/specs/theme/css/variables.css new file mode 100644 index 00000000000..615d34a95cb --- /dev/null +++ b/circuits/specs/theme/css/variables.css @@ -0,0 +1,255 @@ +/* The same as this https://github.com/rust-lang/mdBook/blob/master/src/theme/css/variables.css, except some variables are changed for our book. */ + +/* Globals */ + +:root { + --sidebar-width: 300px; + --page-padding: 15px; + --content-max-width: 750px; + /* --content-max-width: 900px; */ + --menu-bar-height: 50px; +} + +/* Themes */ + +.ayu { + --bg: hsl(210, 25%, 8%); + --fg: #c5c5c5; + + --sidebar-bg: #14191f; + --sidebar-fg: #c8c9db; + --sidebar-non-existant: #5c6773; + --sidebar-active: #ffb454; + --sidebar-spacer: #2d334f; + + --scrollbar: var(--sidebar-fg); + + --icons: #737480; + --icons-hover: #b7b9cc; + + --links: #0096cf; + + --inline-code-color: #ffb454; + + --theme-popup-bg: #14191f; + --theme-popup-border: #5c6773; + --theme-hover: #191f26; + + --quote-bg: hsl(226, 15%, 17%); + --quote-border: hsl(226, 15%, 22%); + + --table-border-color: hsl(210, 25%, 13%); + --table-header-bg: hsl(210, 25%, 28%); + --table-alternate-bg: hsl(210, 25%, 11%); + + --searchbar-border-color: #848484; + --searchbar-bg: #424242; + --searchbar-fg: #fff; + --searchbar-shadow-color: #d4c89f; + --searchresults-header-fg: #666; + --searchresults-border-color: #888; + --searchresults-li-bg: #252932; + --search-mark-bg: #e3b171; +} + +.coal { + --bg: hsl(200, 7%, 8%); + --fg: #98a3ad; + + --sidebar-bg: #292c2f; + --sidebar-fg: #a1adb8; + --sidebar-non-existant: #505254; + --sidebar-active: #3473ad; + --sidebar-spacer: #393939; + + --scrollbar: var(--sidebar-fg); + + --icons: #43484d; + --icons-hover: #b3c0cc; + + --links: #2b79a2; + + --inline-code-color: #c5c8c6; + + --theme-popup-bg: #141617; + --theme-popup-border: #43484d; + --theme-hover: #1f2124; + + --quote-bg: hsl(234, 21%, 18%); + --quote-border: hsl(234, 21%, 23%); + + --table-border-color: hsl(200, 7%, 13%); + --table-header-bg: hsl(200, 7%, 28%); + --table-alternate-bg: hsl(200, 7%, 11%); + + --searchbar-border-color: #aaa; + --searchbar-bg: #b7b7b7; + --searchbar-fg: #000; + --searchbar-shadow-color: #aaa; + --searchresults-header-fg: #666; + --searchresults-border-color: #98a3ad; + --searchresults-li-bg: #2b2b2f; + --search-mark-bg: #355c7d; +} + +.light { + --bg: hsl(0, 0%, 100%); + --fg: hsl(0, 0%, 0%); + + --sidebar-bg: #fafafa; + --sidebar-fg: hsl(0, 0%, 0%); + --sidebar-non-existant: #aaaaaa; + --sidebar-active: #1f1fff; + --sidebar-spacer: #f4f4f4; + + --scrollbar: #8f8f8f; + + --icons: #747474; + --icons-hover: #000000; + + --links: #20609f; + + --inline-code-color: #301900; + + --theme-popup-bg: #fafafa; + --theme-popup-border: #cccccc; + --theme-hover: #e6e6e6; + + --quote-bg: hsl(197, 37%, 96%); + --quote-border: hsl(197, 37%, 91%); + + --table-border-color: hsl(0, 0%, 95%); + --table-header-bg: hsl(0, 0%, 80%); + --table-alternate-bg: hsl(0, 0%, 97%); + + --searchbar-border-color: #aaa; + --searchbar-bg: #fafafa; + --searchbar-fg: #000; + --searchbar-shadow-color: #aaa; + --searchresults-header-fg: #666; + --searchresults-border-color: #888; + --searchresults-li-bg: #e4f2fe; + --search-mark-bg: #a2cff5; +} + +.navy { + --bg: hsl(226, 23%, 11%); + --fg: #bcbdd0; + + --sidebar-bg: #282d3f; + --sidebar-fg: #c8c9db; + --sidebar-non-existant: #505274; + --sidebar-active: #2b79a2; + --sidebar-spacer: #2d334f; + + --scrollbar: var(--sidebar-fg); + + --icons: #737480; + --icons-hover: #b7b9cc; + + --links: #2b79a2; + + --inline-code-color: #c5c8c6; + + --theme-popup-bg: #161923; + --theme-popup-border: #737480; + --theme-hover: #282e40; + + --quote-bg: hsl(226, 15%, 17%); + --quote-border: hsl(226, 15%, 22%); + + --table-border-color: hsl(226, 23%, 16%); + --table-header-bg: hsl(226, 23%, 31%); + --table-alternate-bg: hsl(226, 23%, 14%); + + --searchbar-border-color: #aaa; + --searchbar-bg: #aeaec6; + --searchbar-fg: #000; + --searchbar-shadow-color: #aaa; + --searchresults-header-fg: #5f5f71; + --searchresults-border-color: #5c5c68; + --searchresults-li-bg: #242430; + --search-mark-bg: #a2cff5; +} + +.rust { + --bg: hsl(60, 9%, 87%); + --fg: #262625; + + --sidebar-bg: #3b2e2a; + --sidebar-fg: #c8c9db; + --sidebar-non-existant: #505254; + --sidebar-active: #e69f67; + --sidebar-spacer: #45373a; + + --scrollbar: var(--sidebar-fg); + + --icons: #737480; + --icons-hover: #262625; + + --links: #2b79a2; + + --inline-code-color: #6e6b5e; + + --theme-popup-bg: #e1e1db; + --theme-popup-border: #b38f6b; + --theme-hover: #99908a; + + --quote-bg: hsl(60, 5%, 75%); + --quote-border: hsl(60, 5%, 70%); + + --table-border-color: hsl(60, 9%, 82%); + --table-header-bg: #b3a497; + --table-alternate-bg: hsl(60, 9%, 84%); + + --searchbar-border-color: #aaa; + --searchbar-bg: #fafafa; + --searchbar-fg: #000; + --searchbar-shadow-color: #aaa; + --searchresults-header-fg: #666; + --searchresults-border-color: #888; + --searchresults-li-bg: #dec2a2; + --search-mark-bg: #e69f67; +} + +@media (prefers-color-scheme: dark) { + .light.no-js { + --bg: hsl(200, 7%, 8%); + --fg: #98a3ad; + + --sidebar-bg: #292c2f; + --sidebar-fg: #a1adb8; + --sidebar-non-existant: #505254; + --sidebar-active: #3473ad; + --sidebar-spacer: #393939; + + --scrollbar: var(--sidebar-fg); + + --icons: #43484d; + --icons-hover: #b3c0cc; + + --links: #2b79a2; + + --inline-code-color: #c5c8c6; + + --theme-popup-bg: #141617; + --theme-popup-border: #43484d; + --theme-hover: #1f2124; + + --quote-bg: hsl(234, 21%, 18%); + --quote-border: hsl(234, 21%, 23%); + + --table-border-color: hsl(200, 7%, 13%); + --table-header-bg: hsl(200, 7%, 28%); + --table-alternate-bg: hsl(200, 7%, 11%); + + --searchbar-border-color: #aaa; + --searchbar-bg: #b7b7b7; + --searchbar-fg: #000; + --searchbar-shadow-color: #aaa; + --searchresults-header-fg: #666; + --searchresults-border-color: #98a3ad; + --searchresults-li-bg: #2b2b2f; + --search-mark-bg: #355c7d; + } +} diff --git a/circuits/specs/theme/index.hbs b/circuits/specs/theme/index.hbs new file mode 100644 index 00000000000..14cae0bf78a --- /dev/null +++ b/circuits/specs/theme/index.hbs @@ -0,0 +1,310 @@ + + + + + + {{ title }} + {{#if is_print }} + + {{/if}} + {{#if base_url}} + + {{/if}} + + + + {{> head}} + + + + + + + {{#if favicon_svg}} + + {{/if}} + {{#if favicon_png}} + + {{/if}} + + + + {{#if print_enable}} + + {{/if}} + + + + {{#if copy_fonts}} + + {{/if}} + + + + + + + + {{#each additional_css}} + + {{/each}} + + {{#if mathjax_support}} + + + {{/if}} + + + + + + + + + + + + + + + + +
+ +
+ {{> header}} + + + + {{#if search_enabled}} + + {{/if}} + + + + +
+
+ +
+ + {{{ content }}} +
+ + +
+
+ + + +
+ + {{#if livereload}} + + + {{/if}} + + {{#if google_analytics}} + + + {{/if}} + + {{#if playground_line_numbers}} + + {{/if}} + + {{#if playground_copyable}} + + {{/if}} + + {{#if playground_js}} + + + + + + {{/if}} + + {{#if search_js}} + + + + {{/if}} + + + + + + + {{#each additional_js}} + + {{/each}} + + {{#if is_print}} + {{#if mathjax_support}} + + {{else}} + + {{/if}} + {{/if}} + + + \ No newline at end of file diff --git a/circuits/specs/theme/sidebar.js b/circuits/specs/theme/sidebar.js new file mode 100644 index 00000000000..785fac18dae --- /dev/null +++ b/circuits/specs/theme/sidebar.js @@ -0,0 +1,66 @@ +// Un-active everything when you click it +Array.prototype.forEach.call(document.getElementsByClassName("pagetoc")[0].children, function(el) { + el.addEventHandler("click", function() { + Array.prototype.forEach.call(document.getElementsByClassName("pagetoc")[0].children, function(el) { + el.classList.remove("active"); + }); + el.classList.add("active"); + }); +}); + +var updateFunction = function() { + + var id; + var elements = document.getElementsByClassName("header"); + Array.prototype.forEach.call(elements, function(el) { + if (window.pageYOffset >= el.offsetTop) { + id = el; + } + }); + + Array.prototype.forEach.call(document.getElementsByClassName("pagetoc")[0].children, function(el) { + el.classList.remove("active"); + }); + + Array.prototype.forEach.call(document.getElementsByClassName("pagetoc")[0].children, function(el) { + if (id.href.localeCompare(el.href) == 0) { + el.classList.add("active"); + } + }); +}; + +// Populate sidebar on load +window.addEventListener('load', function() { + var pagetoc = document.getElementsByClassName("pagetoc")[0]; + var elements = document.getElementsByClassName("header"); + Array.prototype.forEach.call(elements, function(el) { + var link = document.createElement("a"); + + // Indent shows hierarchy + var indent = ""; + switch (el.parentElement.tagName) { + case "H2": + indent = "20px"; + break; + case "H3": + indent = "40px"; + break; + case "H4": + indent = "60px"; + break; + default: + break; + } + + link.appendChild(document.createTextNode(el.text)); + link.style.paddingLeft = indent; + link.href = el.href; + pagetoc.appendChild(link); + }); + updateFunction.call(); +}); + + + +// Handle active elements on scroll +window.addEventListener("scroll", updateFunction); \ No newline at end of file From 4d6335e61aee7075cbb319bae85b6c2f2d6f8212 Mon Sep 17 00:00:00 2001 From: iAmMichaelConnor Date: Mon, 4 Apr 2022 23:58:16 +0000 Subject: [PATCH 003/166] tools for writing az3 test_apps with private states --- .../app-circuits/public-input-abis.md | 19 +- circuits/specs/src/examples/erc20/withdraw.md | 2 +- .../src/noir-stuff/extremes/claim-simple.md | 2 +- circuits/src/aztec3/CMakeLists.txt | 3 + circuits/src/aztec3/circuits/CMakeLists.txt | 3 + .../src/aztec3/circuits/abis/CMakeLists.txt | 5 + circuits/src/aztec3/circuits/abis/README.md | 8 + .../src/aztec3/circuits/abis/abis.test.cpp | 256 +++++++++++ .../src/aztec3/circuits/abis/call_context.hpp | 91 ++++ .../aztec3/circuits/abis/call_stack_item.hpp | 98 +++++ .../circuits/abis/callback_stack_item.hpp | 94 +++++ ...contract_deployment_call_public_inputs.hpp | 117 ++++++ .../circuits/abis/executed_callback.hpp | 78 ++++ .../circuits/abis/function_signature.hpp | 89 ++++ circuits/src/aztec3/circuits/abis/index.hpp | 10 + .../abis/private_circuit_public_inputs.hpp | 397 ++++++++++++++++++ .../abis/public_circuit_public_inputs.hpp | 181 ++++++++ .../src/aztec3/circuits/abis/state_read.hpp | 61 +++ .../aztec3/circuits/abis/state_transition.hpp | 66 +++ .../src/aztec3/circuits/apps/CMakeLists.txt | 8 + circuits/src/aztec3/circuits/apps/README.md | 44 ++ .../aztec3/circuits/apps/contract_factory.hpp | 100 +++++ .../src/aztec3/circuits/apps/function.hpp | 21 + circuits/src/aztec3/circuits/apps/index.hpp | 5 + circuits/src/aztec3/circuits/apps/l1_call.hpp | 86 ++++ .../src/aztec3/circuits/apps/l1_function.hpp | 57 +++ .../src/aztec3/circuits/apps/l1_function.tpp | 27 ++ .../src/aztec3/circuits/apps/l1_promise.hpp | 42 ++ .../src/aztec3/circuits/apps/l1_promise.tpp | 91 ++++ .../src/aztec3/circuits/apps/l1_result.hpp | 28 ++ .../aztec3/circuits/apps/oracle_wrapper.hpp | 91 ++++ .../circuits/apps/private_state.test.cpp | 116 +++++ .../circuits/apps/private_state_factory.hpp | 101 +++++ .../circuits/apps/private_state_note.hpp | 136 ++++++ .../circuits/apps/private_state_note.tpp | 229 ++++++++++ .../apps/private_state_note_preimage.hpp | 98 +++++ .../circuits/apps/private_state_operand.hpp | 44 ++ .../circuits/apps/private_state_var.hpp | 135 ++++++ .../circuits/apps/private_state_var.tpp | 288 +++++++++++++ .../circuits/apps/test_apps/escrow/README.md | 3 + .../apps/test_apps/escrow/constants.hpp | 25 ++ .../apps/test_apps/escrow/contract.hpp | 33 ++ .../apps/test_apps/escrow/deposit.cpp | 55 +++ .../apps/test_apps/escrow/deposit.hpp | 9 + .../apps/test_apps/escrow/escrow.test.cpp | 112 +++++ .../circuits/apps/test_apps/escrow/events.hpp | 19 + .../circuits/apps/test_apps/escrow/index.hpp | 6 + .../circuits/apps/test_apps/escrow/init.hpp | 21 + .../apps/test_apps/escrow/l1_interface.hpp | 10 + .../circuits/apps/test_apps/escrow/states.hpp | 17 + .../apps/test_apps/escrow/transfer.cpp | 96 +++++ .../apps/test_apps/escrow/transfer.hpp | 16 + .../apps/test_apps/escrow/withdraw.cpp | 102 +++++ .../apps/test_apps/escrow/withdraw.hpp | 15 + .../escrow/withdraw_failure_callback.cpp | 61 +++ .../escrow/withdraw_failure_callback.hpp | 13 + .../src/aztec3/circuits/apps/type_check.hpp | 13 + .../src/aztec3/circuits/kernel/CMakeLists.txt | 9 + circuits/src/aztec3/circuits/kernel/index.hpp | 2 + .../src/aztec3/circuits/kernel/play.test.cpp | 97 +++++ .../circuits/kernel/play_app_circuit.hpp | 20 + .../circuits/kernel/play_kernel_circuit.hpp | 99 +++++ .../aztec3/circuits/kernel/private_kernel.hpp | 28 ++ .../src/aztec3/circuits/types/address.hpp | 140 ++++++ circuits/src/aztec3/constants.hpp | 57 +++ circuits/src/aztec3/dbs/CMakeLists.txt | 36 ++ circuits/src/aztec3/dbs/private_state_db.hpp | 150 +++++++ circuits/src/aztec3/oracle/CMakeLists.txt | 8 + circuits/src/aztec3/oracle/README.md | 13 + circuits/src/aztec3/oracle/oracle.hpp | 140 ++++++ 70 files changed, 4741 insertions(+), 11 deletions(-) create mode 100644 circuits/src/aztec3/CMakeLists.txt create mode 100644 circuits/src/aztec3/circuits/CMakeLists.txt create mode 100644 circuits/src/aztec3/circuits/abis/CMakeLists.txt create mode 100644 circuits/src/aztec3/circuits/abis/README.md create mode 100644 circuits/src/aztec3/circuits/abis/abis.test.cpp create mode 100644 circuits/src/aztec3/circuits/abis/call_context.hpp create mode 100644 circuits/src/aztec3/circuits/abis/call_stack_item.hpp create mode 100644 circuits/src/aztec3/circuits/abis/callback_stack_item.hpp create mode 100644 circuits/src/aztec3/circuits/abis/contract_deployment_call_public_inputs.hpp create mode 100644 circuits/src/aztec3/circuits/abis/executed_callback.hpp create mode 100644 circuits/src/aztec3/circuits/abis/function_signature.hpp create mode 100644 circuits/src/aztec3/circuits/abis/index.hpp create mode 100644 circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp create mode 100644 circuits/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp create mode 100644 circuits/src/aztec3/circuits/abis/state_read.hpp create mode 100644 circuits/src/aztec3/circuits/abis/state_transition.hpp create mode 100644 circuits/src/aztec3/circuits/apps/CMakeLists.txt create mode 100644 circuits/src/aztec3/circuits/apps/README.md create mode 100644 circuits/src/aztec3/circuits/apps/contract_factory.hpp create mode 100644 circuits/src/aztec3/circuits/apps/function.hpp create mode 100644 circuits/src/aztec3/circuits/apps/index.hpp create mode 100644 circuits/src/aztec3/circuits/apps/l1_call.hpp create mode 100644 circuits/src/aztec3/circuits/apps/l1_function.hpp create mode 100644 circuits/src/aztec3/circuits/apps/l1_function.tpp create mode 100644 circuits/src/aztec3/circuits/apps/l1_promise.hpp create mode 100644 circuits/src/aztec3/circuits/apps/l1_promise.tpp create mode 100644 circuits/src/aztec3/circuits/apps/l1_result.hpp create mode 100644 circuits/src/aztec3/circuits/apps/oracle_wrapper.hpp create mode 100644 circuits/src/aztec3/circuits/apps/private_state.test.cpp create mode 100644 circuits/src/aztec3/circuits/apps/private_state_factory.hpp create mode 100644 circuits/src/aztec3/circuits/apps/private_state_note.hpp create mode 100644 circuits/src/aztec3/circuits/apps/private_state_note.tpp create mode 100644 circuits/src/aztec3/circuits/apps/private_state_note_preimage.hpp create mode 100644 circuits/src/aztec3/circuits/apps/private_state_operand.hpp create mode 100644 circuits/src/aztec3/circuits/apps/private_state_var.hpp create mode 100644 circuits/src/aztec3/circuits/apps/private_state_var.tpp create mode 100644 circuits/src/aztec3/circuits/apps/test_apps/escrow/README.md create mode 100644 circuits/src/aztec3/circuits/apps/test_apps/escrow/constants.hpp create mode 100644 circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp create mode 100644 circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp create mode 100644 circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.hpp create mode 100644 circuits/src/aztec3/circuits/apps/test_apps/escrow/escrow.test.cpp create mode 100644 circuits/src/aztec3/circuits/apps/test_apps/escrow/events.hpp create mode 100644 circuits/src/aztec3/circuits/apps/test_apps/escrow/index.hpp create mode 100644 circuits/src/aztec3/circuits/apps/test_apps/escrow/init.hpp create mode 100644 circuits/src/aztec3/circuits/apps/test_apps/escrow/l1_interface.hpp create mode 100644 circuits/src/aztec3/circuits/apps/test_apps/escrow/states.hpp create mode 100644 circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp create mode 100644 circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.hpp create mode 100644 circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp create mode 100644 circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.hpp create mode 100644 circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw_failure_callback.cpp create mode 100644 circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw_failure_callback.hpp create mode 100644 circuits/src/aztec3/circuits/apps/type_check.hpp create mode 100644 circuits/src/aztec3/circuits/kernel/CMakeLists.txt create mode 100644 circuits/src/aztec3/circuits/kernel/index.hpp create mode 100644 circuits/src/aztec3/circuits/kernel/play.test.cpp create mode 100644 circuits/src/aztec3/circuits/kernel/play_app_circuit.hpp create mode 100644 circuits/src/aztec3/circuits/kernel/play_kernel_circuit.hpp create mode 100644 circuits/src/aztec3/circuits/kernel/private_kernel.hpp create mode 100644 circuits/src/aztec3/circuits/types/address.hpp create mode 100644 circuits/src/aztec3/constants.hpp create mode 100644 circuits/src/aztec3/dbs/CMakeLists.txt create mode 100644 circuits/src/aztec3/dbs/private_state_db.hpp create mode 100644 circuits/src/aztec3/oracle/CMakeLists.txt create mode 100644 circuits/src/aztec3/oracle/README.md create mode 100644 circuits/src/aztec3/oracle/oracle.hpp diff --git a/circuits/specs/src/architecture/app-circuits/public-input-abis.md b/circuits/specs/src/architecture/app-circuits/public-input-abis.md index 7fd33a5821c..50ab9aed450 100644 --- a/circuits/specs/src/architecture/app-circuits/public-input-abis.md +++ b/circuits/specs/src/architecture/app-circuits/public-input-abis.md @@ -12,10 +12,11 @@ All private contract circuits have a fixed number of public inputs. Most of thes | Data type | Description | | -------- | -------- | -| `customPublicInputs` | Up to 32 circuit-specific inputs passed into this circuit. All of these inputs will be 'swallowed' by the private kernel snark.
Note: for a private circuit, we don't need a field for 'custom outputs' from the circuit, since all inputs/output must be known in advance, and so for simplicity can all be considered 'inputs'. | +| *`customPublicInputs` | Up to 32 circuit-specific inputs passed into this circuit. All of these inputs will be 'swallowed' by the private kernel snark. Hence any private args can safely be put here, which enables private circuits to call other private circuits, and pass private data to them. To reveal data to the 'public world', either call a public function or emit an event. | +| *`customPublicOutputs` | Up to 32 circuit-specific values _returned by_ circuit. All of these inputs will be 'swallowed' by the private kernel snark. Hence any private outputs can safely be put here, which enables private circuits to call other private circuits, and pass private data to them. | | `emittedPublicInputs` | Public inputs which will be revealed to the 'public world' (L1 or L2). E.g. allowing certain inputs to be more-easily extracted by the RollupProcessor contract (rather than having to unpack this vast ABI object of inputs, which would cost too much hash-wise). An example of its usefulness is passing a value from L1 to L2 when doing an L1->L2 tx (see 'deposit' example in the other doc). TODO: consider whether this could be a single value, for simplicity. It could be a hash of data if more values need to be exposed. If so, we'll rename to `emittedPublicInputsHash`. | -| `executedCallback: {` | Populated if this circuit is a callback, so that the purported L1 Result to which this circuit is responding can be validated against the l1ResultsTree. | -| `- l1ResultHash`, | If this function is a callback function, following some L1 call, then it needs to expose the `l1ResultHash` to ensure the callback is actually using data emitted by L1. The preimage of the `l1ResultHash` will need to be passed in as private inputs to the circuit. Note: the `l1ResultHash` MUST be computed with a sha256 hash, because that's what the RollupProcessor will have used. This is unfortunate, as it forces apps to adhere to a specific calculation within their circuits. | +| *`executedCallback: {` | Populated if this circuit is a callback, so that the purported L1 Result to which this circuit is responding can be validated against the l1ResultsTree. | +| `- l1ResultHash`, | If this function is a callback function, following some L1 call, then it needs to expose the `l1ResultHash` to ensure the callback is actually using data emitted by L1. The preimage of the `l1ResultHash` will need to be passed in as private inputs to the circuit. Note: the `l1ResultHash` MUST be computed with a sha256 hash, because that's what the RollupProcessor will have used. This is unfortunate, as it forces apps to adhere to a specific calculation within their circuits. DISAGREE NOW - we don't need to calcualte this within the app circuit: we can just hash the custom_public_inputs and compare that hash against the L1ResultHash. | | `- l1ResultsTreeLeafIndex`, | Communicates to the rollup provider the correct leaf to prove membership against in the l1ResultsTree. Only if we don't want to hide the callback will the rollup provider perform the membership check (within the Base Rollup Circuit). Otherwise it'll be performed in the Private Kernel Circuit. | | `}`| | `outputCommitments` | output notes to be added into the `privateDataTree` (up to 16) | @@ -25,14 +26,14 @@ All private contract circuits have a fixed number of public inputs. Most of thes | `contractDeploymentCallStack` | additional calls which _deploy contracts_, created by this transaction (up to 1?) | | `partialL1CallStack` | additional calls to L1 created by this transaction (up to 16). "Partial" because the kernel circuit will add the correct portal contract address to 'complete' the call into a proper L1 CallStack Item. See [here](../contracts/l1-calls.md). | |
callbackStack = [{
  callbackPublicKey,
  successCallbackCallHash,
  failureCallbackCallHash,
  successResultArgMapAcc,
},...]
| An element in the array for each new L1 call on the `l1CallStack`. See [more](../contracts/l1-calls.md). We need to expose all of this data so that the kernel snark ensures the callback is a function of the same contract which made the call. | -| `oldPrivateDataTreeRoot` | used to query the `privateDataTree` | +| *`oldPrivateDataTreeRoot` | used to query the `privateDataTree` | | Booleans: | | -| `bool isFeePayment` | Notifies the kernel circuit that the following public inputs of this private circuit MUST be revealed to the public kernel circuit:
  • `functionSignature` - so that the rollup provider can see how they're to be paid
  • `emittedPublicInputs` - so that the rollup provider can validate the amount they'll be paid (they'll need to be provided with the underlying public inputs separately, to validate the hash).
| -| `bool payFeeFromL1`| Provides a way of paying for private L2 function execution from L1 (the RollupProcessor.sol could provide the interface for ETH or ERC20... but we could generalise this by somehow pointing to a particular 'other' payment L1 contract state?). "Submit on-chain the callHash and state a fee (in L1 currency) for the L2 tx, and then when the L2 tx is executed, the rollup provider may redeem the previously-published fee".

Notifies the kernel circuit that the following public inputs of this private circuit MUST be revealed to the public kernel circuit:
  • `callHash` - no other data is needed (in order to allow the user to keep the function they've actually executed private).
| -| `bool payFeeFromPublicL2`| Provides a way of paying for private L2 function execution from a public L2 circuit. This input being `true` will cause the rollup provider to look for an `isFeePayment` tx in the _public_ callStack. | -| `bool calledFromL1` | If the L1 contract wants to call a specific L2 circuit, then the function signature needs to be revealed on-chain so that it can be checked that the correct, intended function was executed.

Notifies the private kernel circuit that an L1 contract wants to call this specific private L2 circuit, and so the following MUST be revealed to the public kernel circuit:
  • `functionSignature` - needed so the L1 contract can confirm the intended function was executed on L2. Although a callHash contains the functionSignature, the L1 contract wouldn't (cheaply) be able to unpack the callHash. So we expose the function signature as well to keep costs down. Although this leaks the function which was called, there's no way around that; this is an L1 -> L2 call after all.
  • `callHash` - used as a 'lookup' key. The RollupProcessor will store this `callHash`, and await an L2 tx with this `callHash` before triggering a callback to the L1 contract which made this L1 -> L2 call in the first place.
  • `emittedPublicInputs` - needed so that a set of values can be emitted by an L2 function and exposed to L1. It would be too expensive to unpack the callHash and extract all of the custom public inputs of a circuit. This is much cheaper, and is very similar to how the EVM exposes only a few values (via event emissions) to JavaScript (for example).


We need this convoluted process, because the RollupProcessor has to be _sure_ an L1 fee has been set-aside for them, before they add any corresponding L2 states. | +| *`bool isFeePayment` | Notifies the kernel circuit that the following public inputs of this private circuit MUST be revealed to the public kernel circuit:
  • `functionSignature` - so that the rollup provider can see how they're to be paid
  • `emittedPublicInputs` - so that the rollup provider can validate the amount they'll be paid (they'll need to be provided with the underlying public inputs separately, to validate the hash).
| +| *`bool payFeeFromL1`| Provides a way of paying for private L2 function execution from L1 (the RollupProcessor.sol could provide the interface for ETH or ERC20... but we could generalise this by somehow pointing to a particular 'other' payment L1 contract state?). "Submit on-chain the callHash and state a fee (in L1 currency) for the L2 tx, and then when the L2 tx is executed, the rollup provider may redeem the previously-published fee".

Notifies the kernel circuit that the following public inputs of this private circuit MUST be revealed to the public kernel circuit:
  • `callHash` - no other data is needed (in order to allow the user to keep the function they've actually executed private).
| +| *`bool payFeeFromPublicL2`| Provides a way of paying for private L2 function execution from a public L2 circuit. This input being `true` will cause the rollup provider to look for an `isFeePayment` tx in the _public_ callStack. | +| *`bool calledFromL1` | If the L1 contract wants to call a specific L2 circuit, then the function signature needs to be revealed on-chain so that it can be checked that the correct, intended function was executed.

Notifies the private kernel circuit that an L1 contract wants to call this specific private L2 circuit, and so the following MUST be revealed to the public kernel circuit:
  • `functionSignature` - needed so the L1 contract can confirm the intended function was executed on L2. Although a callHash contains the functionSignature, the L1 contract wouldn't (cheaply) be able to unpack the callHash. So we expose the function signature as well to keep costs down. Although this leaks the function which was called, there's no way around that; this is an L1 -> L2 call after all.
  • `callHash` - used as a 'lookup' key. The RollupProcessor will store this `callHash`, and await an L2 tx with this `callHash` before triggering a callback to the L1 contract which made this L1 -> L2 call in the first place.
  • `emittedPublicInputs` - needed so that a set of values can be emitted by an L2 function and exposed to L1. It would be too expensive to unpack the callHash and extract all of the custom public inputs of a circuit. This is much cheaper, and is very similar to how the EVM exposes only a few values (via event emissions) to JavaScript (for example).


We need this convoluted process, because the RollupProcessor has to be _sure_ an L1 fee has been set-aside for them, before they add any corresponding L2 states. | | Global vars: | | -| `minTimestamp` | a timestamp value that must be exceeded when the block containing this txn is mined | +| *`minTimestamp` | a timestamp value that must be exceeded when the block containing this txn is mined | Apart from the public input API, the structure of a private contract circuit is undefined by the Aztec 3 architecture. diff --git a/circuits/specs/src/examples/erc20/withdraw.md b/circuits/specs/src/examples/erc20/withdraw.md index 0aafb8f751e..8eeedf01365 100644 --- a/circuits/specs/src/examples/erc20/withdraw.md +++ b/circuits/specs/src/examples/erc20/withdraw.md @@ -14,7 +14,7 @@ Withdrawal is an example of a [L2 --> L1 call](../../architecture/contracts/l1-c - We don't need a 'success' callback in this example. If the money is successfully transferred, nothing else needs to happen on L2 after the L1 call succeeds (the money has already been nullified on L2). - We add a 'failure' callback to reinstate the private value note containing the `amount`, if the L1 tx fails. - This failure callback can either be a public function or private, depending on the developer's preferences. It can be public, since the 'amount' and 'recipient' are already public knowledge by this point. But it could also be private, which would then allow the user to hide that the callback has even been executed. - - In particular, in this example, the `customPublicInputs` will need to contain the `amount` and maybe also the `recipient`, as a way of forcing the callback to only reinstate the correct amount to the correct user. + - In particular, in this example, the `customPublicInputs` to the callback will need to contain the `amount` and maybe also the `recipient`, as a way of forcing the callback to only reinstate the correct amount to the correct user. Alternatively, the public input could have been the replacement commitment itself, which could have been created by the withdrawal circuit. - Recall that the initial call to L1 must go via the Portal Contract - ...So the Portal Contract will receive a call from RollupProcessor.sol - If successful, it will return some result data (of variable size), and the RollupProcessor will sha256 hash this data (the amount of data to hash might need to be bounded to prevent griefing attacks). diff --git a/circuits/specs/src/noir-stuff/extremes/claim-simple.md b/circuits/specs/src/noir-stuff/extremes/claim-simple.md index ce08abbb89b..14184905705 100644 --- a/circuits/specs/src/noir-stuff/extremes/claim-simple.md +++ b/circuits/specs/src/noir-stuff/extremes/claim-simple.md @@ -30,7 +30,6 @@ contract L1_Portal_Contract { contract My_Contract_1 { secret mapping(address => uint) token_balances_a; // user => balance secret mapping(address => uint) token_balances_b; // user => balance - // interaction_id => (secret_slot => amount): mapping(uint => uint) total_deposits_a; // interaction_id => amount mapping(uint => uint) claimable_amounts_a; // interaction_id => amount mapping(uint => uint) claimable_amounts_b; // interaction_id => amount @@ -48,6 +47,7 @@ contract My_Contract_1 { // a value into a secret storage slot, without them learning the owner, // secret, or (in the case of mappings/arrays) the storageSlot. } + // interaction_id => (secret_slot => amount): mapping(uint => mapping(secret_slot => DepositLog)) deposit_logs_a; diff --git a/circuits/src/aztec3/CMakeLists.txt b/circuits/src/aztec3/CMakeLists.txt new file mode 100644 index 00000000000..c3f0d8fc73a --- /dev/null +++ b/circuits/src/aztec3/CMakeLists.txt @@ -0,0 +1,3 @@ +add_subdirectory(circuits) +add_subdirectory(oracle) +add_subdirectory(dbs) \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/CMakeLists.txt b/circuits/src/aztec3/circuits/CMakeLists.txt new file mode 100644 index 00000000000..feb12203cad --- /dev/null +++ b/circuits/src/aztec3/circuits/CMakeLists.txt @@ -0,0 +1,3 @@ +add_subdirectory(apps) +add_subdirectory(abis) +add_subdirectory(kernel) \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/abis/CMakeLists.txt b/circuits/src/aztec3/circuits/abis/CMakeLists.txt new file mode 100644 index 00000000000..45ff2652ca1 --- /dev/null +++ b/circuits/src/aztec3/circuits/abis/CMakeLists.txt @@ -0,0 +1,5 @@ +barretenberg_module( + aztec3_circuits_abis + stdlib_primitives + stdlib_pedersen +) \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/abis/README.md b/circuits/src/aztec3/circuits/abis/README.md new file mode 100644 index 00000000000..c9d52a2dda6 --- /dev/null +++ b/circuits/src/aztec3/circuits/abis/README.md @@ -0,0 +1,8 @@ +# aztec3::circuits::abis + +Contains all ABIs for use by: +- Test app circuits +- Kernel circuits +- Rollup circuits + +All ABIs are generalised by an `NCT` template parameter (meaning `NativeOrCircuitTypes`). `NCT` can be either `plonk::stdlib::types::NativeTypes` or `plonk::stdlib::types::CircuitTypes` for some `Composer`. The idea being, there's a single implementation of every struct/class for native and circuit types. NativeType structs can be switched to CircuitType with the `to_circuit_type()` method. \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/abis/abis.test.cpp b/circuits/src/aztec3/circuits/abis/abis.test.cpp new file mode 100644 index 00000000000..da25c526960 --- /dev/null +++ b/circuits/src/aztec3/circuits/abis/abis.test.cpp @@ -0,0 +1,256 @@ +#include +#include +#include +// #include +#include "index.hpp" +#include + +namespace aztec3::circuits::abis { + +using TurboComposer = plonk::stdlib::types::turbo::Composer; +using CT = plonk::stdlib::types::CircuitTypes; +using NT = plonk::stdlib::types::NativeTypes; + +class abi_tests : public ::testing::Test {}; + +TEST(abi_tests, test_native_function_signature) +{ + FunctionSignature function_signature = { + .contract_address = 10, + .vk_index = 11, + .is_private = false, + .is_constructor = false, + .is_callback = false, + }; + + info("function signature: ", function_signature); + + auto buffer = to_buffer(function_signature); + auto function_signature_2 = from_buffer>(buffer.data()); + + EXPECT_EQ(function_signature, function_signature_2); +} + +TEST(abi_tests, test_native_to_circuit_function_signature) +{ + FunctionSignature native_function_signature = { + .contract_address = 10, + .vk_index = 11, + .is_private = false, + .is_constructor = false, + .is_callback = false, + }; + + info("function signature: ", native_function_signature); + + TurboComposer turbo_composer; + FunctionSignature circuit_function_signature = native_function_signature.to_circuit_type(turbo_composer); + + info("function signature: ", circuit_function_signature); +} + +TEST(abi_tests, test_native_call_context) +{ + CallContext call_context = { + .msg_sender = 10, + .storage_contract_address = 11, + }; + + info("call context: ", call_context); +} + +TEST(abi_tests, test_native_to_circuit_call_context) +{ + CallContext native_call_context = { + .msg_sender = 10, + .storage_contract_address = 11, + }; + + info("call context: ", native_call_context); + + TurboComposer turbo_composer; + CallContext circuit_call_context = native_call_context.to_circuit_type(turbo_composer); + + info("call context: ", circuit_call_context); +} + +TEST(abi_tests, test_native_public_inputs) +{ + PublicCircuitPublicInputs public_inputs = { + .custom_public_inputs = { 1, 2, 3, 4, 5, 6, 7, 8 }, + .custom_outputs = { 9, 10, 11, 12 }, + .emitted_public_inputs = { 13, 14, 15, 16 }, + .emitted_outputs = { 17, 18, 19, 20 }, + .executed_callback = ExecutedCallback::empty(), + .state_transitions = { { { 21, 22, 23 }, { 21, 22, 23 }, { 21, 22, 23 }, { 21, 22, 23 } } }, + .state_reads = { { { 24, 25 }, { 24, 25 }, { 24, 25 }, { 24, 25 } } }, + .public_call_stack = { 26, 27, 28, 29 }, + .contract_deployment_call_stack = { 30, 31 }, + .partial_l1_call_stack = { 32, 33 }, + .callback_stack = { { { 34, 35, 36, 37 }, { 34, 35, 36, 37 } } }, + .old_private_data_tree_root = 38, + }; + + info("public_circuit_public_inputs: ", public_inputs); +} + +TEST(abi_tests, test_native_to_circuit_public_circuit_public_inputs) +{ + PublicCircuitPublicInputs native_public_inputs = { + .custom_public_inputs = { 1, 2, 3, 4, 5, 6, 7, 8 }, + .custom_outputs = { 9, 10, 11, 12 }, + .emitted_public_inputs = { 13, 14, 15, 16 }, + .emitted_outputs = { 17, 18, 19, 20 }, + .executed_callback = ExecutedCallback::empty(), + .state_transitions = { { { 21, 22, 23 }, { 21, 22, 23 }, { 21, 22, 23 }, { 21, 22, 23 } } }, + .state_reads = { { { 24, 25 }, { 24, 25 }, { 24, 25 }, { 24, 25 } } }, + .public_call_stack = { 26, 27, 28, 29 }, + .contract_deployment_call_stack = { 30, 31 }, + .partial_l1_call_stack = { 32, 33 }, + .callback_stack = { { { 34, 35, 36, 37 }, { 34, 35, 36, 37 } } }, + .old_private_data_tree_root = 38, + }; + + info("public_circuit_public_inputs: ", native_public_inputs); + + TurboComposer turbo_composer; + PublicCircuitPublicInputs circuit_public_inputs = native_public_inputs.to_circuit_type(turbo_composer); + + info("public_circuit_public_inputs: ", circuit_public_inputs); +} + +TEST(abi_tests, test_native_call_stack_item) +{ + PublicCircuitPublicInputs public_inputs = { + .custom_public_inputs = { 1, 2, 3, 4, 5, 6, 7, 8 }, + .custom_outputs = { 9, 10, 11, 12 }, + .emitted_public_inputs = { 13, 14, 15, 16 }, + .emitted_outputs = { 17, 18, 19, 20 }, + .executed_callback = ExecutedCallback::empty(), + .state_transitions = { { { 21, 22, 23 }, { 21, 22, 23 }, { 21, 22, 23 }, { 21, 22, 23 } } }, + .state_reads = { { { 24, 25 }, { 24, 25 }, { 24, 25 }, { 24, 25 } } }, + .public_call_stack = { 26, 27, 28, 29 }, + .contract_deployment_call_stack = { 30, 31 }, + .partial_l1_call_stack = { 32, 33 }, + .callback_stack = { { { 34, 35, 36, 37 }, { 34, 35, 36, 37 } } }, + .old_private_data_tree_root = 38, + }; + + CallStackItem call_stack_item = { + .function_signature = { + .contract_address = 10, + .vk_index = 11, + .is_private = false, + .is_constructor = false, + .is_callback = false, + }, + .public_inputs = public_inputs, + .call_context = { + .msg_sender = 13, + .storage_contract_address = 14, + }, + .is_delegate_call = false, + .is_static_call = false, + }; + + info("call stack item: ", call_stack_item); +} + +TEST(abi_tests, test_native_to_circuit_call_stack_item) +{ + PublicCircuitPublicInputs public_inputs = { + .custom_public_inputs = { 1, 2, 3, 4, 5, 6, 7, 8 }, + .custom_outputs = { 9, 10, 11, 12 }, + .emitted_public_inputs = { 13, 14, 15, 16 }, + .emitted_outputs = { 17, 18, 19, 20 }, + .executed_callback = ExecutedCallback::empty(), + .state_transitions = { { { 21, 22, 23 }, { 21, 22, 23 }, { 21, 22, 23 }, { 21, 22, 23 } } }, + .state_reads = { { { 24, 25 }, { 24, 25 }, { 24, 25 }, { 24, 25 } } }, + .public_call_stack = { 26, 27, 28, 29 }, + .contract_deployment_call_stack = { 30, 31 }, + .partial_l1_call_stack = { 32, 33 }, + .callback_stack = { { { 34, 35, 36, 37 }, { 34, 35, 36, 37 } } }, + .old_private_data_tree_root = 38, + }; + + CallStackItem native_call_stack_item = { + .function_signature = { + .contract_address = 10, + .vk_index = 11, + .is_private = false, + .is_constructor = false, + .is_callback = false, + }, + .public_inputs = public_inputs, + .call_context = { + .msg_sender = 13, + .storage_contract_address = 14, + }, + .is_delegate_call = false, + .is_static_call = false, + }; + + info("call stack item: ", native_call_stack_item); + + TurboComposer turbo_composer; + CallStackItem circuit_call_stack_item = + native_call_stack_item.to_circuit_type(turbo_composer); + + info("call stack item: ", circuit_call_stack_item); +} + +TEST(abi_tests, test_native_callback_stack_item) +{ + CallbackStackItem callback_stack_item = { + .callback_public_key = 1, + .success_callback_call_hash = 2, + .failure_callback_call_hash = 3, + .success_result_arg_map_acc = 4, + }; + + info("callback stack item: ", callback_stack_item); +} + +TEST(abi_tests, test_native_to_circuit_callback_stack_item) +{ + CallbackStackItem native_callback_stack_item = { + .callback_public_key = 1, + .success_callback_call_hash = 2, + .failure_callback_call_hash = 3, + .success_result_arg_map_acc = 4, + }; + + info("callback stack item: ", native_callback_stack_item); + + TurboComposer turbo_composer; + CallbackStackItem circuit_callback_stack_item = native_callback_stack_item.to_circuit_type(turbo_composer); + + info("callback stack item: ", circuit_callback_stack_item); +} + +TEST(abi_tests, test_native_executed_callback) +{ + ExecutedCallback executed_callback = { + .l1_result_hash = 1, + .l1_results_tree_leaf_index = 2, + }; + + info("executed callback: ", executed_callback); +} + +TEST(abi_tests, test_native_to_circuit_executed_callback) +{ + ExecutedCallback native_executed_callback = { + .l1_result_hash = 1, + .l1_results_tree_leaf_index = 2, + }; + + info("executed callback: ", native_executed_callback); + + TurboComposer turbo_composer; + ExecutedCallback circuit_executed_callback = native_executed_callback.to_circuit_type(turbo_composer); + + info("executed callback: ", circuit_executed_callback); +} + +} // namespace aztec3::circuits::abis \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/abis/call_context.hpp b/circuits/src/aztec3/circuits/abis/call_context.hpp new file mode 100644 index 00000000000..6d17551c2f7 --- /dev/null +++ b/circuits/src/aztec3/circuits/abis/call_context.hpp @@ -0,0 +1,91 @@ +#pragma once +#include +#include +#include +#include +#include +#include + +namespace aztec3::circuits::abis { + +using plonk::stdlib::witness_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; + +template struct CallContext { + typedef typename NCT::address address; + typedef typename NCT::grumpkin_point grumpkin_point; + typedef typename NCT::fr fr; + + address msg_sender; + address storage_contract_address; + + bool operator==(CallContext const&) const = default; + + static CallContext empty() { return { 0, 0 }; }; + + template CallContext> to_circuit_type(Composer& composer) const + { + static_assert((std::is_same::value)); + + // Capture the composer: + auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + + CallContext> call_context = { + to_ct(msg_sender), + to_ct(storage_contract_address), + }; + + return call_context; + }; + + fr hash() + { + std::vector inputs = { + msg_sender.to_field(), + storage_contract_address.to_field(), + }; + + return NCT::compress(inputs, GeneratorIndex::CALL_CONTEXT); + } + + template void assert_is_zero() + { + static_assert((std::is_same, NCT>::value)); + + msg_sender.to_field().assert_is_zero(); + storage_contract_address.to_field().assert_is_zero(); + } + + template void set_public() + { + static_assert((std::is_same, NCT>::value)); + + msg_sender.to_field().set_public(); + storage_contract_address.to_field().set_public(); + } +}; + +template void read(uint8_t const*& it, CallContext& call_context) +{ + using serialize::read; + + read(it, call_context.msg_sender); + read(it, call_context.storage_contract_address); +}; + +template void write(std::vector& buf, CallContext const& call_context) +{ + using serialize::write; + + write(buf, call_context.msg_sender); + write(buf, call_context.storage_contract_address); +}; + +template std::ostream& operator<<(std::ostream& os, CallContext const& call_context) +{ + return os << "msg_sender: " << call_context.msg_sender << "\n" + << "storage_contract_address: " << call_context.storage_contract_address << "\n"; +} + +} // namespace aztec3::circuits::abis \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/abis/call_stack_item.hpp b/circuits/src/aztec3/circuits/abis/call_stack_item.hpp new file mode 100644 index 00000000000..7ddb04018c2 --- /dev/null +++ b/circuits/src/aztec3/circuits/abis/call_stack_item.hpp @@ -0,0 +1,98 @@ +#pragma once +#include "./function_signature.hpp" +#include "./call_context.hpp" +#include "./private_circuit_public_inputs.hpp" +#include "./public_circuit_public_inputs.hpp" +#include +#include +#include +#include + +namespace aztec3::circuits::abis { + +using plonk::stdlib::witness_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; +using std::conditional; +using std::is_same; + +enum class CallType { + Public, + Private, +}; + +template struct CallStackItem { + typedef typename NCT::boolean boolean; + + template + using PublicInputs = typename std:: + conditional, PrivateCircuitPublicInputs>::type; + + FunctionSignature function_signature; + PublicInputs public_inputs; // TODO: can we just do args? + CallContext call_context; + boolean is_delegate_call = false; + boolean is_static_call = false; + + bool operator==(CallStackItem const&) const = default; + + template static CallStackItem empty() + { + return { FunctionSignature::empty(), PublicInputs::empty(), CallContext::empty(), 0, 0 }; + }; + + template + CallStackItem, call_type> to_circuit_type(Composer& composer) const + { + static_assert((std::is_same::value)); + + // Capture the composer: + auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + + CallStackItem, call_type> call_stack_item = { + function_signature.to_circuit_type(composer), + public_inputs.to_circuit_type(composer), + call_context.to_circuit_type(composer), + to_ct(is_delegate_call), + to_ct(is_static_call), + }; + + return call_stack_item; + }; +}; + +template +void read(uint8_t const*& it, CallStackItem& call_stack_item) +{ + using serialize::read; + + read(it, call_stack_item.function_signature); + read(it, call_stack_item.public_inputs_hash); + read(it, call_stack_item.call_context); + read(it, call_stack_item.is_delegate_call); + read(it, call_stack_item.is_callback); +}; + +template +void write(std::vector& buf, CallStackItem const& call_stack_item) +{ + using serialize::write; + + write(buf, call_stack_item.function_signature); + write(buf, call_stack_item.public_inputs_hash); + write(buf, call_stack_item.call_context); + write(buf, call_stack_item.is_delegate_call); + write(buf, call_stack_item.is_static_call); +}; + +template +std::ostream& operator<<(std::ostream& os, CallStackItem const& call_stack_item) +{ + return os << "function_signature: " << call_stack_item.function_signature << "\n" + << "public_inputs: " << call_stack_item.public_inputs << "\n" + << "call_context: " << call_stack_item.call_context << "\n" + << "is_delegate_call: " << call_stack_item.is_delegate_call << "\n" + << "is_static_call: " << call_stack_item.is_static_call << "\n"; +} + +} // namespace aztec3::circuits::abis \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/abis/callback_stack_item.hpp b/circuits/src/aztec3/circuits/abis/callback_stack_item.hpp new file mode 100644 index 00000000000..158b28eee39 --- /dev/null +++ b/circuits/src/aztec3/circuits/abis/callback_stack_item.hpp @@ -0,0 +1,94 @@ +#pragma once +#include +#include +#include +#include + +namespace aztec3::circuits::abis { + +using plonk::stdlib::witness_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; + +template struct CallbackStackItem { + typedef typename NCT::address address; + typedef typename NCT::fr fr; + + address callback_public_key; + fr success_callback_call_hash; + fr failure_callback_call_hash; + fr success_result_arg_map_acc; + + bool operator==(CallbackStackItem const&) const = default; + + static CallbackStackItem empty() { return { 0, 0, 0, 0 }; }; + + template CallbackStackItem> to_circuit_type(Composer& composer) const + { + static_assert((std::is_same::value)); + + // Capture the composer: + auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + + CallbackStackItem> callback_stack_item = { + to_ct(callback_public_key), + to_ct(success_callback_call_hash), + to_ct(failure_callback_call_hash), + to_ct(success_result_arg_map_acc), + }; + + return callback_stack_item; + }; + + template void assert_is_zero() + { + static_assert((std::is_same, NCT>::value)); + + callback_public_key.to_field().assert_is_zero(); + success_callback_call_hash.assert_is_zero(); + failure_callback_call_hash.assert_is_zero(); + success_result_arg_map_acc.assert_is_zero(); + } + + template void set_public() + { + static_assert((std::is_same, NCT>::value)); + + callback_public_key.to_field().set_public(); + success_callback_call_hash.set_public(); + failure_callback_call_hash.set_public(); + success_result_arg_map_acc.set_public(); + } +}; + +template void read(uint8_t const*& it, CallbackStackItem& callback_stack_item) +{ + using serialize::read; + + read(it, callback_stack_item.callback_public_key); + read(it, callback_stack_item.success_callback_call_hash); + read(it, callback_stack_item.failure_callback_call_hash); + read(it, callback_stack_item.success_result_arg_map_acc); + read(it, callback_stack_item.is_callback); +}; + +template void write(std::vector& buf, CallbackStackItem const& callback_stack_item) +{ + using serialize::write; + + write(buf, callback_stack_item.callback_public_key); + write(buf, callback_stack_item.success_callback_call_hash); + write(buf, callback_stack_item.failure_callback_call_hash); + write(buf, callback_stack_item.success_result_arg_map_acc); + write(buf, callback_stack_item.is_static_call); +}; + +template std::ostream& operator<<(std::ostream& os, CallbackStackItem const& callback_stack_item) +{ + return os << "callback_public_key: " << callback_stack_item.callback_public_key << "\n" + << "success_callback_call_hash: " << callback_stack_item.success_callback_call_hash << "\n" + << "failure_callback_call_hash: " << callback_stack_item.failure_callback_call_hash << "\n" + << "success_result_arg_map_acc: " << callback_stack_item.success_result_arg_map_acc << "\n"; +} + +} // namespace aztec3::circuits::abis \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/abis/contract_deployment_call_public_inputs.hpp b/circuits/src/aztec3/circuits/abis/contract_deployment_call_public_inputs.hpp new file mode 100644 index 00000000000..bdaed6f5998 --- /dev/null +++ b/circuits/src/aztec3/circuits/abis/contract_deployment_call_public_inputs.hpp @@ -0,0 +1,117 @@ +#pragma once +// #include +#include +#include +#include +#include +#include +#include "../../constants.hpp" +#include "./executed_callback.hpp" +#include "./callback_stack_item.hpp" + +namespace aztec3::circuits::abis { + +using plonk::stdlib::witness_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; + +template class ContractDeploymentCallPublicInputs { + typedef typename NCT::fr fr; + + public: + fr private_constructor_public_inputs_hash; + fr public_constructor_public_inputs_hash; + + fr private_constructor_vk_hash; + fr public_constructor_vk_hash; + + fr contract_address; + fr salt; + fr vk_root; + + fr circuit_data_hash; // TODO: no uint256 circuit type? + + fr portal_contract_address; // TODO: no uint160 circuit type? + + bool operator==(ContractDeploymentCallPublicInputs const&) const = default; + + static ContractDeploymentCallPublicInputs empty() { return { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; }; + + template + ContractDeploymentCallPublicInputs> to_circuit_type(Composer& composer) const + { + static_assert((std::is_same::value)); + + // Capture the composer: + auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + + ContractDeploymentCallPublicInputs> pis = { + to_ct(private_constructor_public_inputs_hash), + to_ct(public_constructor_public_inputs_hash), + to_ct(private_constructor_vk_hash), + to_ct(public_constructor_vk_hash), + to_ct(contract_address), + to_ct(salt), + to_ct(vk_root), + to_ct(circuit_data_hash), + to_ct(portal_contract_address), + }; + + return pis; + }; +}; + +template +void read(uint8_t const*& it, ContractDeploymentCallPublicInputs& contract_deployment_call_public_inputs) +{ + using serialize::read; + + ContractDeploymentCallPublicInputs& pis = contract_deployment_call_public_inputs; + read(it, pis.private_constructor_public_inputs_hash); + read(it, pis.public_constructor_public_inputs_hash); + read(it, pis.private_constructor_vk_hash); + read(it, pis.public_constructor_vk_hash); + read(it, pis.contract_address); + read(it, pis.salt); + read(it, pis.vk_root); + read(it, pis.circuit_data_hash); + read(it, pis.portal_contract_address); +}; + +template +void write(std::vector& buf, + ContractDeploymentCallPublicInputs const& contract_deployment_call_public_inputs) +{ + using serialize::write; + + ContractDeploymentCallPublicInputs const& pis = contract_deployment_call_public_inputs; + + write(buf, pis.private_constructor_public_inputs_hash); + write(buf, pis.public_constructor_public_inputs_hash); + write(buf, pis.private_constructor_vk_hash); + write(buf, pis.public_constructor_vk_hash); + write(buf, pis.contract_address); + write(buf, pis.salt); + write(buf, pis.vk_root); + write(buf, pis.circuit_data_hash); + write(buf, pis.portal_contract_address); +}; + +template +std::ostream& operator<<(std::ostream& os, + ContractDeploymentCallPublicInputs const& contract_deployment_call_public_inputs) + +{ + ContractDeploymentCallPublicInputs const& pis = contract_deployment_call_public_inputs; + return os << "private_constructor_public_inputs_hash: " << pis.private_constructor_public_inputs_hash << "\n" + << "public_constructor_public_inputs_hash: " << pis.public_constructor_public_inputs_hash << "\n" + << "private_constructor_vk_hash: " << pis.private_constructor_vk_hash << "\n" + << "public_constructor_vk_hash: " << pis.public_constructor_vk_hash << "\n" + << "contract_address: " << pis.contract_address << "\n" + << "salt: " << pis.salt << "\n" + << "vk_root: " << pis.vk_root << "\n" + << "circuit_data_hash: " << pis.circuit_data_hash << "\n" + << "portal_contract_address: " << pis.portal_contract_address << "\n"; +} + +} // namespace aztec3::circuits::abis \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/abis/executed_callback.hpp b/circuits/src/aztec3/circuits/abis/executed_callback.hpp new file mode 100644 index 00000000000..50f9e4730c9 --- /dev/null +++ b/circuits/src/aztec3/circuits/abis/executed_callback.hpp @@ -0,0 +1,78 @@ +#pragma once +#include +#include +#include +#include + +namespace aztec3::circuits::abis { + +using plonk::stdlib::witness_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; + +template struct ExecutedCallback { + typedef typename NCT::fr fr; + typedef typename NCT::uint32 uint32; + + fr l1_result_hash; + uint32 l1_results_tree_leaf_index; + + bool operator==(ExecutedCallback const&) const = default; + + static ExecutedCallback empty() { return { 0, 0 }; }; + + template ExecutedCallback> to_circuit_type(Composer& composer) const + { + static_assert((std::is_same::value)); + + // Capture the composer: + auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + + ExecutedCallback> executed_callback = { + to_ct(l1_result_hash), + to_ct(l1_results_tree_leaf_index), + }; + + return executed_callback; + }; + + template void assert_is_zero() + { + static_assert((std::is_same, NCT>::value)); + + l1_result_hash.assert_is_zero(); + fr(l1_results_tree_leaf_index).assert_is_zero(); + } + + template void set_public() + { + static_assert((std::is_same, NCT>::value)); + + l1_result_hash.set_public(); + fr(l1_results_tree_leaf_index).set_public(); + } +}; + +template void read(uint8_t const*& it, ExecutedCallback& executed_callback) +{ + using serialize::read; + + read(it, executed_callback.l1_result_hash); + read(it, executed_callback.l1_results_tree_leaf_index); +}; + +template void write(std::vector& buf, ExecutedCallback const& executed_callback) +{ + using serialize::write; + + write(buf, executed_callback.l1_result_hash); + write(buf, executed_callback.l1_results_tree_leaf_index); +}; + +template std::ostream& operator<<(std::ostream& os, ExecutedCallback const& executed_callback) +{ + return os << "l1_result_hash: " << executed_callback.l1_result_hash << "\n" + << "l1_results_tree_leaf_index: " << executed_callback.l1_results_tree_leaf_index << "\n"; +} + +} // namespace aztec3::circuits::abis \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/abis/function_signature.hpp b/circuits/src/aztec3/circuits/abis/function_signature.hpp new file mode 100644 index 00000000000..50db89fe955 --- /dev/null +++ b/circuits/src/aztec3/circuits/abis/function_signature.hpp @@ -0,0 +1,89 @@ +#pragma once +#include +#include +#include +#include +#include +#include + +namespace aztec3::circuits::abis { + +using plonk::stdlib::witness_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; +using std::is_same; + +template struct FunctionSignature { + typedef typename NCT::address address; + typedef typename NCT::uint32 uint32; + typedef typename NCT::boolean boolean; + typedef typename NCT::grumpkin_point grumpkin_point; + typedef typename NCT::fr fr; + + address contract_address; + uint32 vk_index; + boolean is_private = false; + boolean is_constructor = false; + boolean is_callback = false; // TODO: move this to be with is_delegate_call and is_static_call, since it's a runtime + // bool, rather than a constant property of the function. + + bool operator==(FunctionSignature const&) const = default; + + static FunctionSignature empty() { return { 0, 0, 0, 0, 0 }; }; + + template FunctionSignature> to_circuit_type(Composer& composer) const + { + static_assert((std::is_same::value)); + + // Capture the composer: + auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + + FunctionSignature> function_signature = { + to_ct(contract_address), to_ct(vk_index), to_ct(is_private), to_ct(is_constructor), to_ct(is_callback), + }; + + return function_signature; + }; + + fr hash() + { + std::vector inputs = { + contract_address.to_field(), fr(vk_index), fr(is_private), fr(is_constructor), fr(is_callback), + }; + + return NCT::compress(inputs, GeneratorIndex::FUNCTION_SIGNATURE); + } +}; + +template void read(uint8_t const*& it, FunctionSignature& function_signature) +{ + using serialize::read; + + read(it, function_signature.contract_address); + read(it, function_signature.vk_index); + read(it, function_signature.is_private); + read(it, function_signature.is_constructor); + read(it, function_signature.is_callback); +}; + +template void write(std::vector& buf, FunctionSignature const& function_signature) +{ + using serialize::write; + + write(buf, function_signature.contract_address); + write(buf, function_signature.vk_index); + write(buf, function_signature.is_private); + write(buf, function_signature.is_constructor); + write(buf, function_signature.is_callback); +}; + +template std::ostream& operator<<(std::ostream& os, FunctionSignature const& function_signature) +{ + return os << "contract_address: " << function_signature.contract_address << "\n" + << "vk_index: " << function_signature.vk_index << "\n" + << "is_private: " << function_signature.is_private << "\n" + << "is_constructor: " << function_signature.is_constructor << "\n" + << "is_callback: " << function_signature.is_callback << "\n"; +} + +} // namespace aztec3::circuits::abis \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/abis/index.hpp b/circuits/src/aztec3/circuits/abis/index.hpp new file mode 100644 index 00000000000..652cf95ae00 --- /dev/null +++ b/circuits/src/aztec3/circuits/abis/index.hpp @@ -0,0 +1,10 @@ +#include "call_context.hpp" +#include "call_stack_item.hpp" +#include "callback_stack_item.hpp" +#include "contract_deployment_call_public_inputs.hpp" +#include "executed_callback.hpp" +#include "function_signature.hpp" +#include "private_circuit_public_inputs.hpp" +#include "private_circuit_public_inputs.hpp" +#include "state_read.hpp" +#include "state_transition.hpp" \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp b/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp new file mode 100644 index 00000000000..867614f5d3d --- /dev/null +++ b/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp @@ -0,0 +1,397 @@ +#pragma once +// #include +#include +#include +#include +#include +#include +#include "../../constants.hpp" +#include "call_context.hpp" +#include "executed_callback.hpp" +#include "callback_stack_item.hpp" + +namespace aztec3::circuits::abis { + +using plonk::stdlib::witness_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; + +template class PrivateCircuitPublicInputs { + typedef typename NCT::address address; + typedef typename NCT::fr fr; + typedef typename NCT::boolean boolean; + typedef typename std::optional opt_fr; + typedef typename std::optional opt_boolean; + + public: + std::optional> call_context; + + std::array custom_public_inputs; + std::array emitted_public_inputs; + + std::optional> executed_callback; + + std::array output_commitments; + std::array input_nullifiers; + + std::array private_call_stack; + std::array public_call_stack; + std::array contract_deployment_call_stack; + std::array partial_l1_call_stack; + std::array>, CALLBACK_STACK_LENGTH> callback_stack; + + opt_fr old_private_data_tree_root; + + opt_boolean is_fee_payment; + opt_boolean pay_fee_from_l1; + opt_boolean pay_fee_from_public_l2; + opt_boolean called_from_l1; + + bool operator==(PrivateCircuitPublicInputs const&) const = default; + + static PrivateCircuitPublicInputs create() + { + + auto new_inputs = PrivateCircuitPublicInputs(); + + new_inputs.call_context = std::nullopt; + + new_inputs.custom_public_inputs.fill(std::nullopt); + new_inputs.emitted_public_inputs.fill(std::nullopt); + + new_inputs.executed_callback = std::nullopt; + + new_inputs.output_commitments.fill(std::nullopt); + new_inputs.input_nullifiers.fill(std::nullopt); + + new_inputs.private_call_stack.fill(std::nullopt); + new_inputs.public_call_stack.fill(std::nullopt); + new_inputs.contract_deployment_call_stack.fill(std::nullopt); + new_inputs.partial_l1_call_stack.fill(std::nullopt); + new_inputs.callback_stack.fill(std::nullopt); + + new_inputs.old_private_data_tree_root = std::nullopt; + + return new_inputs; + }; + + void set_commitments(std::vector commitments) + { + if (commitments.size() > output_commitments.size()) { + throw_or_abort("Too many commitments for the number supported by the public inputs ABI."); + } + for (size_t i = 0; i < commitments.size(); ++i) { + output_commitments[i] = commitments[i]; + } + } + + void set_nullifiers(std::vector nullifiers) + { + if (nullifiers.size() > input_nullifiers.size()) { + throw_or_abort("Too many commitments for the number supported by the public inputs ABI."); + } + for (size_t i = 0; i < nullifiers.size(); ++i) { + input_nullifiers[i] = nullifiers[i]; + } + } + + template void make_unused_inputs_zero(Composer& composer) + { + static_assert((std::is_same, NCT>::value)); + + make_unused_element_zero(composer, call_context); + + make_unused_array_elements_zero(composer, custom_public_inputs); + make_unused_array_elements_zero(composer, emitted_public_inputs); + + make_unused_element_zero(composer, executed_callback); + + make_unused_array_elements_zero(composer, output_commitments); + make_unused_array_elements_zero(composer, input_nullifiers); + + make_unused_array_elements_zero(composer, private_call_stack); + make_unused_array_elements_zero(composer, public_call_stack); + make_unused_array_elements_zero(composer, contract_deployment_call_stack); + make_unused_array_elements_zero(composer, partial_l1_call_stack); + make_unused_array_elements_zero(composer, callback_stack); + + make_unused_element_zero(composer, old_private_data_tree_root); + + make_unused_element_zero(composer, is_fee_payment); + make_unused_element_zero(composer, pay_fee_from_l1); + make_unused_element_zero(composer, pay_fee_from_public_l2); + make_unused_element_zero(composer, called_from_l1); + + all_elements_populated = true; + } + + template void set_public(Composer& composer) + { + static_assert((std::is_same, NCT>::value)); + + make_unused_inputs_zero(composer); + + // Optional members are guaranteed to be nonempty from here. + + (*call_context).template set_public(); + + set_array_public(custom_public_inputs); + set_array_public(emitted_public_inputs); + + (*executed_callback).template set_public(); + + set_array_public(output_commitments); + set_array_public(input_nullifiers); + + set_array_public(private_call_stack); + set_array_public(public_call_stack); + set_array_public(contract_deployment_call_stack); + set_array_public(partial_l1_call_stack); + set_array_public(callback_stack); + + (*old_private_data_tree_root).set_public(); + + fr(*is_fee_payment).set_public(); + fr(*pay_fee_from_l1).set_public(); + fr(*pay_fee_from_public_l2).set_public(); + fr(*called_from_l1).set_public(); + } + + template + PrivateCircuitPublicInputs> to_circuit_type(Composer& composer) const + { + static_assert((std::is_same::value)); + + // Capture the composer: + auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + auto to_circuit_type = [&](auto& e) { return e.to_circuit_type(composer); }; + + PrivateCircuitPublicInputs> pis = { + .call_context = to_circuit_type(call_context), + + .custom_public_inputs = to_ct(custom_public_inputs), + .emitted_public_inputs = to_ct(emitted_public_inputs), + + .executed_callback = to_circuit_type(executed_callback), + + .output_commitments = to_ct(output_commitments), + .input_nullifiers = to_ct(input_nullifiers), + + .private_call_stack = to_ct(private_call_stack), + .public_call_stack = to_ct(public_call_stack), + .contract_deployment_call_stack = to_ct(contract_deployment_call_stack), + .partial_l1_call_stack = to_ct(partial_l1_call_stack), + .callback_stack = map(callback_stack, to_circuit_type), + + .is_fee_payment = to_ct(is_fee_payment), + .pay_fee_from_l1 = to_ct(pay_fee_from_l1), + .pay_fee_from_public_l2 = to_ct(pay_fee_from_public_l2), + .called_from_l1 = to_ct(called_from_l1), + }; + + return pis; + }; + + private: + bool all_elements_populated = false; + + /// TODO: unused? + // template bool check_all_elements_populated() + // { + // static_assert((std::is_same, NCT>::value)); + + // bool check_if_populated = [&](std::optional& e) { + // if (!e) { + // return false; + // } + // return true; + // }; + + // bool still_populated = true; + + // // call_context is not optional. + + // still_populated &= std::all_of(custom_public_inputs.begin(), custom_public_inputs.end(), check_if_populated); + // still_populated &= std::all_of(emitted_public_inputs.begin(), emitted_public_inputs.end(), + // check_if_populated); + + // // executed_callback.make_unused_inputs_zero(composer); + + // still_populated &= std::all_of(output_commitments.begin(), output_commitments.end(), check_if_populated); + // still_populated &= std::all_of(input_nullifiers.begin(), input_nullifiers.end(), check_if_populated); + + // still_populated &= std::all_of(private_call_stack.begin(), private_call_stack.end(), check_if_populated); + // still_populated &= std::all_of(public_call_stack.begin(), public_call_stack.end(), check_if_populated); + // still_populated &= std::all_of( + // contract_deployment_call_stack.begin(), contract_deployment_call_stack.end(), check_if_populated); + // still_populated &= std::all_of(partial_l1_call_stack.begin(), partial_l1_call_stack.end(), + // check_if_populated); still_populated &= std::all_of(callback_stack.begin(), callback_stack.end(), + // check_if_populated); + + // still_populated &= check_if_populated(old_private_data_tree_root); + // still_populated &= check_if_populated(is_fee_payment); + // still_populated &= check_if_populated(pay_fee_from_l1); + // still_populated &= check_if_populated(pay_fee_from_public_l2); + // still_populated &= check_if_populated(called_from_l1); + + // all_elements_populated = still_populated; + + // return all_elements_populated; + // } + + template + void make_unused_array_elements_zero(Composer& composer, std::array, SIZE>& arr) + { + static_assert((std::is_same, NCT>::value)); + + for (std::optional& e : arr) { + make_unused_element_zero(composer, e); + } + } + + template + void make_unused_element_zero(Composer& composer, std::optional& element) + { + static_assert((std::is_same, NCT>::value)); + + if (!element) { + element = + T(witness_t(&composer, 0)); // convert the nullopt value to a circuit witness value of `0` + fr(*element).assert_is_zero(); + } + } + + template + void make_unused_element_zero(Composer& composer, std::optional>>& element) + { + static_assert((std::is_same, NCT>::value)); + + if (!element) { + element = CallbackStackItem::empty().to_circuit_type( + composer); // convert the nullopt value to a circuit witness value of `0` + (*element).template assert_is_zero(); + } + } + + template + void make_unused_element_zero(Composer& composer, std::optional>>& element) + { + static_assert((std::is_same, NCT>::value)); + + if (!element) { + element = CallContext::empty().to_circuit_type(composer); + (*element).template assert_is_zero(); + } + } + + template + void make_unused_element_zero(Composer& composer, std::optional>>& element) + { + static_assert((std::is_same, NCT>::value)); + + if (!element) { + element = ExecutedCallback::empty().to_circuit_type(composer); + (*element).template assert_is_zero(); + } + } + + // template + // void make_unused_element_zero(Composer& composer, std::optional>>& element) + // { + // static_assert((std::is_same, NCT>::value)); + + // if (!element) { + // element = CallContext::empty().to_circuit_type(composer); + // (*element).template assert_is_zero(); + // } + // } + + // Make sure this is only called by functions which have implemented a "CT only" check. + template void set_array_public(std::array, SIZE>& arr) + { + for (std::optional& e : arr) { + fr(*e).set_public(); + } + } + + template + void set_array_public(std::array>>, SIZE>& arr) + { + for (auto& e : arr) { + (*e).template set_public(); + } + } +}; + +template void read(uint8_t const*& it, PrivateCircuitPublicInputs& private_circuit_public_inputs) +{ + using serialize::read; + + PrivateCircuitPublicInputs& pis = private_circuit_public_inputs; + read(it, pis.call_context); + read(it, pis.custom_public_inputs); + read(it, pis.emitted_public_inputs); + read(it, pis.executed_callback); + read(it, pis.output_commitments); + read(it, pis.input_nullifiers); + read(it, pis.private_call_stack); + read(it, pis.public_call_stack); + read(it, pis.contract_deployment_call_stack); + read(it, pis.partial_l1_call_stack); + read(it, pis.callback_stack); + read(it, pis.old_private_data_tree_root); + read(it, pis.is_fee_payment); + read(it, pis.pay_fee_from_l1); + read(it, pis.pay_fee_from_public_l2); + read(it, pis.called_from_l1); +}; + +template +void write(std::vector& buf, PrivateCircuitPublicInputs const& private_circuit_public_inputs) +{ + using serialize::write; + + PrivateCircuitPublicInputs const& pis = private_circuit_public_inputs; + + write(buf, pis.call_context); + write(buf, pis.custom_public_inputs); + write(buf, pis.emitted_public_inputs); + write(buf, pis.executed_callback); + write(buf, pis.output_commitments); + write(buf, pis.input_nullifiers); + write(buf, pis.private_call_stack); + write(buf, pis.public_call_stack); + write(buf, pis.contract_deployment_call_stack); + write(buf, pis.partial_l1_call_stack); + write(buf, pis.callback_stack); + write(buf, pis.old_private_data_tree_root); + write(buf, pis.is_fee_payment); + write(buf, pis.pay_fee_from_l1); + write(buf, pis.pay_fee_from_public_l2); + write(buf, pis.called_from_l1); +}; + +template +std::ostream& operator<<(std::ostream& os, PrivateCircuitPublicInputs const& private_circuit_public_inputs) + +{ + PrivateCircuitPublicInputs const& pis = private_circuit_public_inputs; + return os << "call_context: " << pis.call_context << "\n" + << "custom_public_inputs: " << pis.custom_public_inputs << "\n" + << "emitted_public_inputs: " << pis.emitted_public_inputs << "\n" + << "executed_callback: " << pis.executed_callback << "\n" + << "output_commitments: " << pis.output_commitments << "\n" + << "input_nullifiers: " << pis.input_nullifiers << "\n" + << "private_call_stack: " << pis.private_call_stack << "\n" + << "public_call_stack: " << pis.public_call_stack << "\n" + << "contract_deployment_call_stack: " << pis.contract_deployment_call_stack << "\n" + << "partial_l1_call_stack: " << pis.partial_l1_call_stack << "\n" + << "callbck_stack: " << pis.callback_stack << "\n" + << "old_private_data_tree_root: " << pis.old_private_data_tree_root << "\n" + << "is_fee_payment: " << pis.is_fee_payment << "\n" + << "pay_fee_from_l1: " << pis.pay_fee_from_l1 << "\n" + << "pay_fee_from_public_l2: " << pis.pay_fee_from_public_l2 << "\n" + << "called_from_l1: " << pis.called_from_l1 << "\n"; +} + +} // namespace aztec3::circuits::abis \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp b/circuits/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp new file mode 100644 index 00000000000..bca058fd82a --- /dev/null +++ b/circuits/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp @@ -0,0 +1,181 @@ +#pragma once +// #include +#include +#include +#include +#include +#include "../../constants.hpp" +#include "./state_transition.hpp" +#include "./state_read.hpp" +// #include "./executed_callback.hpp" +// #include "./callback_stack_item.hpp" + +namespace aztec3::circuits::abis { + +using plonk::stdlib::witness_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; + +template struct PublicCircuitPublicInputs { + typedef typename NCT::fr fr; + typedef typename NCT::boolean boolean; + typedef typename NCT::address address; + + // address msg_sender; // TODO! + + std::array custom_public_inputs; + std::array custom_outputs; + + std::array emitted_public_inputs; + std::array emitted_outputs; + + ExecutedCallback executed_callback; + + std::array, STATE_TRANSITIONS_LENGTH> state_transitions; + std::array, STATE_READS_LENGTH> state_reads; + + std::array public_call_stack; + std::array contract_deployment_call_stack; + std::array partial_l1_call_stack; + std::array, CALLBACK_STACK_LENGTH> callback_stack; + + fr old_private_data_tree_root; + + address prover_address = 0; + + boolean is_fee_payment = false; + boolean pay_fee_from_l1 = false; + boolean called_from_l1 = false; + + bool operator==(PublicCircuitPublicInputs const&) const = default; + + static PublicCircuitPublicInputs empty() + { + PublicCircuitPublicInputs pis = { + std::array::fill(0), + std::array::fill(0), + + std::array::fill(0), + std::array::fill(0), + + ExecutedCallback::empty(), + + std::array, STATE_TRANSITIONS_LENGTH>::fill(StateTransition::empty()), + std::array, STATE_READS_LENGTH>::fill(StateRead::empty()), + + std::array::fill(0), + + std::array::fill(0), + std::array::fill(0), + std::array, CALLBACK_STACK_LENGTH>::fill(CallbackStackItem::empty()), + + .old_private_data_tree_root = 0, + }; + return pis; + }; + + template + PublicCircuitPublicInputs> to_circuit_type(Composer& composer) const + { + static_assert((std::is_same::value)); + + // Capture the composer: + auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + auto to_circuit_type = [&](auto& e) { return e.to_circuit_type(composer); }; + + PublicCircuitPublicInputs> pis = { + .custom_public_inputs = to_ct(custom_public_inputs), + .custom_outputs = to_ct(custom_outputs), + .emitted_public_inputs = to_ct(emitted_public_inputs), + .emitted_outputs = to_ct(emitted_outputs), + + .executed_callback = to_circuit_type(executed_callback), + + .state_transitions = map(state_transitions, to_circuit_type), + .state_reads = map(state_reads, to_circuit_type), + + .public_call_stack = to_ct(public_call_stack), + .contract_deployment_call_stack = to_ct(contract_deployment_call_stack), + .partial_l1_call_stack = to_ct(partial_l1_call_stack), + .callback_stack = map(callback_stack, to_circuit_type), + + .prover_address = to_ct(prover_address), + + .is_fee_payment = to_ct(is_fee_payment), + .pay_fee_from_l1 = to_ct(pay_fee_from_l1), + .called_from_l1 = to_ct(called_from_l1), + }; + + return pis; + }; +}; + +template void read(uint8_t const*& it, PublicCircuitPublicInputs& private_circuit_public_inputs) +{ + using serialize::read; + + PublicCircuitPublicInputs& pis = private_circuit_public_inputs; + read(it, pis.custom_public_inputs); + read(it, pis.custom_outputs); + read(it, pis.emitted_public_inputs); + read(it, pis.emitted_ouputs); + read(it, pis.executed_callback); + read(it, pis.state_transitions); + read(it, pis.state_reads); + read(it, pis.public_call_stack); + read(it, pis.contract_deployment_call_stack); + read(it, pis.partial_l1_call_stack); + read(it, pis.callback_stack); + read(it, pis.old_private_data_tree_root); + read(it, pis.is_fee_payment); + read(it, pis.pay_fee_from_l1); + read(it, pis.called_from_l1); +}; + +template +void write(std::vector& buf, PublicCircuitPublicInputs const& private_circuit_public_inputs) +{ + using serialize::write; + + PublicCircuitPublicInputs const& pis = private_circuit_public_inputs; + + write(buf, pis.custom_public_inputs); + write(buf, pis.custom_outputs); + write(buf, pis.emitted_public_inputs); + write(buf, pis.emitted_ouputs); + write(buf, pis.executed_callback); + write(buf, pis.state_transitions); + write(buf, pis.state_reads); + write(buf, pis.public_call_stack); + write(buf, pis.contract_deployment_call_stack); + write(buf, pis.partial_l1_call_stack); + write(buf, pis.callback_stack); + write(buf, pis.old_private_data_tree_root); + write(buf, pis.is_fee_payment); + write(buf, pis.pay_fee_from_l1); + write(buf, pis.called_from_l1); +}; + +template +std::ostream& operator<<(std::ostream& os, PublicCircuitPublicInputs const& private_circuit_public_inputs) + +{ + PublicCircuitPublicInputs const& pis = private_circuit_public_inputs; + return os << "custom_public_inputs: " << pis.custom_public_inputs << "\n" + << "custom_outputs: " << pis.custom_outputs << "\n" + << "emitted_public_inputs: " << pis.emitted_public_inputs << "\n" + << "emitted_outputs: " << pis.emitted_outputs << "\n" + << "executed_callback: " << pis.executed_callback << "\n" + << "state_transitions: " << pis.state_transitions << "\n" + << "state_reads: " << pis.state_reads << "\n" + << "public_call_stack: " << pis.public_call_stack << "\n" + << "contract_deployment_call_stack: " << pis.contract_deployment_call_stack << "\n" + << "partial_l1_call_stack: " << pis.partial_l1_call_stack << "\n" + << "callback_stack: " << pis.callback_stack << "\n" + << "old_private_data_tree_root: " << pis.old_private_data_tree_root << "\n" + << "is_fee_payment: " << pis.is_fee_payment << "\n" + << "pay_fee_from_l1: " << pis.pay_fee_from_l1 << "\n" + << "called_from_l1: " << pis.called_from_l1 << "\n"; +} + +} // namespace aztec3::circuits::abis \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/abis/state_read.hpp b/circuits/src/aztec3/circuits/abis/state_read.hpp new file mode 100644 index 00000000000..fcb85aaf3de --- /dev/null +++ b/circuits/src/aztec3/circuits/abis/state_read.hpp @@ -0,0 +1,61 @@ +#pragma once +#include +#include +#include +#include + +namespace aztec3::circuits::abis { + +using plonk::stdlib::witness_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; + +template struct StateRead { + typedef typename NCT::fr fr; + + fr storage_slot; + fr current_value; + + bool operator==(StateRead const&) const = default; + + static StateRead empty() { return { 0, 0 }; }; + + template StateRead> to_circuit_type(Composer& composer) const + { + static_assert((std::is_same::value)); + + // Capture the composer: + auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + + StateRead> state_read = { + to_ct(storage_slot), + to_ct(current_value), + }; + + return state_read; + }; +}; + +template void read(uint8_t const*& it, StateRead& state_read) +{ + using serialize::read; + + read(it, state_read.l1_result_hash); + read(it, state_read.current_value); +}; + +template void write(std::vector& buf, StateRead const& state_read) +{ + using serialize::write; + + write(buf, state_read.storage_slot); + write(buf, state_read.current_value); +}; + +template std::ostream& operator<<(std::ostream& os, StateRead const& state_read) +{ + return os << "storage_slot: " << state_read.storage_slot << "\n" + << "current_value: " << state_read.current_value << "\n"; +} + +} // namespace aztec3::circuits::abis diff --git a/circuits/src/aztec3/circuits/abis/state_transition.hpp b/circuits/src/aztec3/circuits/abis/state_transition.hpp new file mode 100644 index 00000000000..58f91d89a54 --- /dev/null +++ b/circuits/src/aztec3/circuits/abis/state_transition.hpp @@ -0,0 +1,66 @@ +#pragma once +#include +#include +#include +#include + +namespace aztec3::circuits::abis { + +using plonk::stdlib::witness_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; + +template struct StateTransition { + typedef typename NCT::fr fr; + + fr storage_slot; + fr old_value; + fr new_value; + + bool operator==(StateTransition const&) const = default; + + static StateTransition empty() { return { 0, 0, 0 }; }; + + template StateTransition> to_circuit_type(Composer& composer) const + { + static_assert((std::is_same::value)); + + // Capture the composer: + auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + + StateTransition> state_transition = { + to_ct(storage_slot), + to_ct(old_value), + to_ct(new_value), + }; + + return state_transition; + }; +}; + +template void read(uint8_t const*& it, StateTransition& state_transition) +{ + using serialize::read; + + read(it, state_transition.l1_result_hash); + read(it, state_transition.old_value); + read(it, state_transition.new_value); +}; + +template void write(std::vector& buf, StateTransition const& state_transition) +{ + using serialize::write; + + write(buf, state_transition.storage_slot); + write(buf, state_transition.old_value); + write(buf, state_transition.new_value); +}; + +template std::ostream& operator<<(std::ostream& os, StateTransition const& state_transition) +{ + return os << "storage_slot: " << state_transition.storage_slot << "\n" + << "old_value: " << state_transition.old_value << "\n" + << "new_value: " << state_transition.new_value << "\n"; +} + +} // namespace aztec3::circuits::abis \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/CMakeLists.txt b/circuits/src/aztec3/circuits/apps/CMakeLists.txt new file mode 100644 index 00000000000..b2167c79207 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/CMakeLists.txt @@ -0,0 +1,8 @@ +barretenberg_module( + aztec3_circuits_apps + # ecc + crypto_pedersen + stdlib_primitives + stdlib_pedersen + stdlib_blake2s +) \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/README.md b/circuits/src/aztec3/circuits/apps/README.md new file mode 100644 index 00000000000..b03139ecb08 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/README.md @@ -0,0 +1,44 @@ +# aztec3::circuits::apps + +All code in this dir is for: +- Demonstrating how our users' (developers) apps will need to be written, in terms of: + - Public inputs + - Commitment/nullifier creation (recommendations) + - Function calls + - Everything from the 'Noir Examples' section of the Aztec3 book. +- To help illustrate ideas to the Noir team +- To allow test app circuits to be mocked-up as quickly and easily as possible + +## Private State Code + +This is some complex code, which attempts to abstract-away stuff to do with creating commitments, nullifiers, and Aztec3 public input ABIs. All that, so that test app circuits can be mocked-up without too much faff. Some explanation is needed: + +``` +private_state_factory + |___private_state_vars + | |___private_state_var (fr state) + | |___private_state_var (mapping state) + | |___private_state_var (fr state) + | |... + | |___private_state_var (fr state) + | ___________________| + | | fr states can creates notes + | v + |___private_state_notes + | |___private_state_note + | |___private_state_note_preimage + | | + | |___ preimage members are std::optional + | so that partial commitments can be + | created in one tx, and completed in + | a later tx. + | + |___commitments + |___nullifiers once all notes have been created by the circuit, we can + `finalise()` the state_factory. This will figure out whether + we need more: + - dummy nullifiers (to use as input_nullifiers to + commitments). + Only at this stage are the commitments (and partial commitments) + and nullifiers computed. +``` \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/contract_factory.hpp b/circuits/src/aztec3/circuits/apps/contract_factory.hpp new file mode 100644 index 00000000000..e5d10f6cf27 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/contract_factory.hpp @@ -0,0 +1,100 @@ +#pragma once +#include +#include +#include +#include +#include "private_state_note.hpp" +#include "private_state_var.hpp" +#include "function.hpp" +#include "l1_function.hpp" +#include "oracle_wrapper.hpp" + +namespace aztec3::circuits::apps { + +using plonk::stdlib::witness_t; +using plonk::stdlib::types::CircuitTypes; +using NT = plonk::stdlib::types::NativeTypes; +using aztec3::circuits::abis::FunctionSignature; + +template class ContractFactory { + typedef CircuitTypes CT; + typedef typename CT::fr fr; + typedef typename CT::uint32 uint32; + + public: + Composer& composer; + OracleWrapperInterface& oracle; + const std::string contract_name; + PrivateStateFactory private_state_factory; + std::map> function_signatures; + std::map> l1_functions; + + ContractFactory(Composer& composer, OracleWrapperInterface& oracle, std::string contract_name) + : composer(composer) + , oracle(oracle) + , contract_name(contract_name) + , private_state_factory(PrivateStateFactory(composer, oracle, contract_name)) + {} + + void set_functions(std::vector> const& functions) + { + for (uint32_t i = 0; i < functions.size(); ++i) { + const auto& function = functions[i]; + if (function_signatures.contains(function.name)) { + throw_or_abort("Name already exists"); + } + function_signatures[function.name] = FunctionSignature{ + .contract_address = oracle.get_this_contract_address(), + .vk_index = uint32(i), + .is_private = function.is_private, + .is_constructor = function.is_constructor, + }; // TODO: do I need to create witnesses? + } + }; + + FunctionSignature get_function_signature_by_name(std::string const& name) + { + if (!function_signatures.contains(name)) { + throw_or_abort("function signature not found"); + } + return function_signatures[name]; + } + + // FunctionSignature> get_function_signature_by_name(std::string const& name) { + + // } + + void import_l1_function(L1FunctionStruct const& l1_function_struct) + { + L1Function l1_function = L1Function(this, l1_function_struct); + l1_functions.insert(std::make_pair(l1_function_struct.function_name, l1_function)); + }; + + L1Function& get_l1_function(std::string const& name) + { + if (!l1_functions.contains(name)) { + throw_or_abort("L1 function not found. Make sure to import_l1_function()"); + } + return l1_functions[name]; + } + + PrivateStateVar& new_private_state(std::string const& name, + PrivateStateType const& private_state_type = PARTITIONED) + { + return private_state_factory.new_private_state(name, private_state_type); + }; + + // For initialising a private state which is a mapping. + PrivateStateVar& new_private_state(std::string const& name, + std::vector const& mapping_key_names, + PrivateStateType const& private_state_type = PARTITIONED) + { + return private_state_factory.new_private_state(name, mapping_key_names, private_state_type); + }; + + void finalise() { private_state_factory.finalise(); }; + + PrivateStateVar& get_private_state(std::string const& name) { return private_state_factory.get(name); }; +}; + +} // namespace aztec3::circuits::apps \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/function.hpp b/circuits/src/aztec3/circuits/apps/function.hpp new file mode 100644 index 00000000000..5127a88f40e --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/function.hpp @@ -0,0 +1,21 @@ +#pragma once +#include +#include +#include +#include + +namespace aztec3::circuits::apps { + +using plonk::stdlib::witness_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; + +template struct Function { + typedef typename NCT::boolean boolean; + + std::string name; + boolean is_private = false; + boolean is_constructor = false; +}; + +} // namespace aztec3::circuits::apps \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/index.hpp b/circuits/src/aztec3/circuits/apps/index.hpp new file mode 100644 index 00000000000..8b0ce1a872e --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/index.hpp @@ -0,0 +1,5 @@ +#include "private_state_factory.hpp" +#include "private_state_var.hpp" +#include "private_state_note.hpp" +#include "private_state_note_preimage.hpp" +// #include "completable_private_state_note_preimage.hpp" \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/l1_call.hpp b/circuits/src/aztec3/circuits/apps/l1_call.hpp new file mode 100644 index 00000000000..d1522161b76 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/l1_call.hpp @@ -0,0 +1,86 @@ +#pragma once +#include +#include +#include +#include +#include "l1_function.hpp" +// #include +// #include + +namespace aztec3::circuits::apps { + +using plonk::stdlib::witness_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; + +template class L1Call { + typedef typename CircuitTypes::fr fr; + + public: + L1Function& l1_function; + std::vector args; + fr hash_of_argument_encodings; + fr partial_l1_call_stack_item; // keccak(function_selector, hash_of_argument_encodings) + + L1Call(L1Function const& l1_function, std::vector const& args) + : l1_function(l1_function) + , args(args) + { + /// TODO: in reality, we'll need to use keccak hash here, as this will need to be replecated on-chain. + if (args.size() == 0) { + hash_of_argument_encodings = 0; + } else { + hash_of_argument_encodings = args[0]; // lazy stub for a hash! + } + partial_l1_call_stack_item = function_selector; // lazy stub for a hash! + } + + bool operator==(L1Call const&) const = default; + + // static L1Call empty() { return { 0, 0, 0, 0, 0 }; }; + + template L1Call> to_circuit_type(Composer& composer) const + { + static_assert((std::is_same::value)); + + // Capture the composer: + auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + + L1Call> l1_call = { l1_function.to_circuit_type(composer), + to_ct(args), + to_ct(hash_of_argument_encodings), + to_ct(partial_l1_call_stack_item) }; + + return l1_call; + }; +}; + +template void read(uint8_t const*& it, L1Call& l1_call) +{ + using serialize::read; + + read(it, l1_call.l1_function); + read(it, l1_call.args); + read(it, l1_call.hash_of_argument_encodings); + read(it, l1_call.partial_l1_call_stack_item); +}; + +template void write(std::vector& buf, L1Call const& l1_call) +{ + using serialize::write; + + write(buf, l1_call.l1_function); + write(buf, l1_call.args); + write(buf, l1_call.hash_of_argument_encodings); + write(buf, l1_call.partial_l1_call_stack_item); +}; + +template std::ostream& operator<<(std::ostream& os, L1Call const& l1_call) +{ + return os << "l1_function: " << l1_call.l1_function << "\n" + << "args: " << l1_call.args << "\n" + << "hash_of_argument_encodings: " << l1_call.hash_of_argument_encodings << "\n" + << "partial_l1_call_stack_item: " << l1_call.partial_l1_call_stack_item << "\n"; +} + +} // namespace aztec3::circuits::apps \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/l1_function.hpp b/circuits/src/aztec3/circuits/apps/l1_function.hpp new file mode 100644 index 00000000000..123a252e5af --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/l1_function.hpp @@ -0,0 +1,57 @@ +#pragma once +#include +#include +#include +#include +// #include "contract_factory.hpp" // TODO: circular dependency +#include "l1_promise.hpp" +#include "l1_result.hpp" + +namespace aztec3::circuits::apps { + +using plonk::stdlib::witness_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; + +template class ContractFactory; + +// We use the struct to retain designated initialisation, to make contract creation more readable. +template struct L1FunctionStruct { + typedef typename CircuitTypes::fr fr; + + std::string function_name; + fr function_selector; + size_t num_params = 0; +}; + +template class L1Function { + typedef typename CircuitTypes::fr fr; + + public: + ContractFactory* contract_factory; + std::string function_name; + fr function_selector; + size_t num_params; + + L1Function(){}; + + L1Function(ContractFactory* contract_factory, L1FunctionStruct const& l1_fn_struct) + : contract_factory(contract_factory) + , function_name(l1_fn_struct.function_name) + , function_selector(l1_fn_struct.function_selector) + , num_params(l1_fn_struct.num_params) + {} + + // L1Function(L1Function const& l1_function) + // : contract_factory(l1_function.contract_factory) + // , function_name(l1_function.function_name) + // , function_selector(l1_function.function_selector) + // , num_params(l1_function.num_params) + // {} + + std::pair, L1Result> call(std::vector args); +}; + +} // namespace aztec3::circuits::apps + +#include "l1_function.tpp" \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/l1_function.tpp b/circuits/src/aztec3/circuits/apps/l1_function.tpp new file mode 100644 index 00000000000..a68bc1ee312 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/l1_function.tpp @@ -0,0 +1,27 @@ +// #pragma once +#include +#include +#include +#include +#include "contract_factory.hpp" // TODO: circular dependency? +#include "l1_promise.hpp" +#include "l1_result.hpp" + +namespace aztec3::circuits::apps { + +using plonk::stdlib::witness_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; + +template std::pair, L1Result> L1Function::call(std::vector args) +{ + if (args.size() != num_params) { + throw_or_abort("Incorrect number of args"); + } + + auto promise = L1Promise(*contract_factory); + L1Result result; + return std::make_pair(promise, result); +} + +} // namespace aztec3::circuits::apps \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/l1_promise.hpp b/circuits/src/aztec3/circuits/apps/l1_promise.hpp new file mode 100644 index 00000000000..e89431c066a --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/l1_promise.hpp @@ -0,0 +1,42 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +// #include "contract_factory.hpp" // TODO: circular dependency? +#include "l1_result.hpp" + +namespace aztec3::circuits::apps { + +using aztec3::circuits::abis::CallbackStackItem; +using plonk::stdlib::witness_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; + +template class ContractFactory; + +template class L1Promise { + typedef CircuitTypes CT; + typedef typename CT::fr fr; + typedef typename CT::grumpkin_point grumpkin_point; + typedef typename CT::boolean boolean; + + public: + ContractFactory& contract_factory; + CallbackStackItem callback_stack_item; + + L1Promise(ContractFactory& contract_factory) + : contract_factory(contract_factory) + {} + + void on_success(std::string const& function_name, std::vector> const& args); + void on_failure(std::string const& function_name, std::vector const& args); +}; + +} // namespace aztec3::circuits::apps + +#include "l1_promise.tpp" \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/l1_promise.tpp b/circuits/src/aztec3/circuits/apps/l1_promise.tpp new file mode 100644 index 00000000000..818ed7c3686 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/l1_promise.tpp @@ -0,0 +1,91 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include "contract_factory.hpp" +#include "l1_result.hpp" + +namespace aztec3::circuits::apps { + +using aztec3::circuits::abis::FunctionSignature; +using plonk::stdlib::witness_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; + +template +void L1Promise::on_success(std::string const& function_name, + std::vector> const& args) +{ + // construct success_callback_call_hash and success_result_arg_map_acc + auto& oracle = contract_factory.oracle; + + auto function_signature = contract_factory.get_function_signature_by_name(function_name); + function_signature.is_callback = true; + + std::vector> arg_input_pairs; + + for (size_t i = 0; i < args.size(); ++i) { + if (std::holds_alternative(args[i])) { + const fr arg = std::get(args[i]); + arg_input_pairs.push_back(std::make_pair(arg, generator_index_t({ GeneratorIndex::CALL_ARGS, i }))); + } else { + // For L1ResultArgIndex types, we won't know the result's value until after the L1 tx, so we hash using a + // placeholder generator which represents a particular index of the result array: + const size_t& result_arg_index = std::get(args[i]); + arg_input_pairs.push_back( + std::make_pair(fr(1), generator_index_t({ GeneratorIndex::L1_RESULT_PLACEHOLDER, result_arg_index }))); + } + } + + // TODO: do this calc in the CallStackItem struct instead, once we know whether we can simply hash args instead of + // the whole set of public inputs. + fr function_signature_hash = function_signature.hash(); + fr arg_hash = CT::compress(arg_input_pairs); + fr call_context_hash = oracle.get_call_context().hash(); + boolean is_delegate_call = false; + boolean is_static_call = false; + + std::vector success_callback_call_hash_inputs = { + function_signature_hash, arg_hash, call_context_hash, fr(is_delegate_call), fr(is_static_call), + }; + + callback_stack_item.success_callback_call_hash = + CT::compress(success_callback_call_hash_inputs, GeneratorIndex::CALLBACK_STACK_ITEM); +}; + +template +void L1Promise::on_failure(std::string const& function_name, std::vector const& args) +{ + // construct failure_callback_call_hash + auto& oracle = contract_factory.oracle; + + auto function_signature = contract_factory.get_function_signature_by_name(function_name); + function_signature.is_callback = true; + + std::vector> arg_input_pairs; + + for (size_t i = 0; i < args.size(); ++i) { + arg_input_pairs.push_back(std::make_pair(args[i], generator_index_t({ GeneratorIndex::CALL_ARGS, i }))); + } + + // TODO: do this calc in the CallStackItem struct instead, once we know whether we can simply hash args instead of + // the whole set of public inputs. + fr function_signature_hash = function_signature.hash(); + fr arg_hash = CT::compress(arg_input_pairs); + fr call_context_hash = oracle.get_call_context().hash(); + boolean is_delegate_call = false; + boolean is_static_call = false; + + std::vector failure_callback_call_hash_inputs = { + function_signature_hash, arg_hash, call_context_hash, fr(is_delegate_call), fr(is_static_call), + }; + + callback_stack_item.failure_callback_call_hash = + CT::compress(failure_callback_call_hash_inputs, GeneratorIndex::CALLBACK_STACK_ITEM); +}; + +} // namespace aztec3::circuits::apps \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/l1_result.hpp b/circuits/src/aztec3/circuits/apps/l1_result.hpp new file mode 100644 index 00000000000..ec0fa140e13 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/l1_result.hpp @@ -0,0 +1,28 @@ +#pragma once +#include +#include +#include +#include + +namespace aztec3::circuits::apps { + +using plonk::stdlib::witness_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; + +// struct L1ResultArgIndex { +// size_t arg_index; +// }; + +/** + * This just allows some syntactic sugar when writing test circuits. + * This is really just something which returns the index you feed it via `[]`. + */ +class L1Result { + public: + L1Result() {} + + size_t operator[](size_t i) const { return i; } +}; + +} // namespace aztec3::circuits::apps \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/oracle_wrapper.hpp b/circuits/src/aztec3/circuits/apps/oracle_wrapper.hpp new file mode 100644 index 00000000000..3a097db9257 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/oracle_wrapper.hpp @@ -0,0 +1,91 @@ +#pragma once +#include +#include +#include +#include +#include +#include + +namespace aztec3::circuits::apps { + +using NT = plonk::stdlib::types::NativeTypes; +using aztec3::circuits::abis::CallContext; +using aztec3::oracle::NativeOracle; +using plonk::stdlib::types::CircuitTypes; + +/** + * The main purpose of this wrapper is to cache values which have been already given by the oracle. Insecure circuits + * could be built if the same value is queried twice from the oracle (since a malicious prover could provide two + * different witnesses for a single thing). + */ +template class OracleWrapperInterface { + typedef CircuitTypes CT; + typedef typename CT::fr fr; + typedef typename CT::address address; + + public: + Composer& composer; + NativeOracle& oracle; + OracleWrapperInterface(Composer& composer, NativeOracle& oracle) + : composer(composer) + , oracle(oracle){}; + + fr get_msg_sender_private_key() + { + if (msg_sender_private_key) { + return *msg_sender_private_key; + } + msg_sender_private_key = plonk::stdlib::types::to_ct(composer, oracle.get_msg_sender_private_key()); + validate_msg_sender_private_key(); + return *msg_sender_private_key; + }; + + CallContext get_call_context() + { + if (call_context) { + return *call_context; + } + call_context = oracle.get_call_context().to_circuit_type(composer); + return *call_context; + }; + + address get_msg_sender() { return get_call_context().msg_sender; }; + + address get_this_contract_address() { return get_call_context().storage_contract_address; }; + + fr generate_salt() const { return plonk::stdlib::types::to_ct(composer, oracle.generate_salt()); } + + fr generate_random_element() const + { + return plonk::stdlib::types::to_ct(composer, oracle.generate_random_element()); + } + + std::pair, PrivateStateNotePreimage> + get_private_state_note_preimages_for_subtraction(fr const& storage_slot, address const& owner, fr const& subtrahend) + { + std::pair, PrivateStateNotePreimage> native_preimages = + oracle.get_private_state_note_preimages_for_subtraction( + storage_slot.get_value(), NT::address(owner.to_field().get_value()), subtrahend.get_value()); + return std::make_pair(native_preimages.first.to_circuit_type(composer), + native_preimages.second.to_circuit_type(composer)); + } + + private: + std::optional> call_context; + std::optional msg_sender_private_key; + + void validate_msg_sender_private_key() + { + address msg_sender = get_msg_sender(); + address derived_msg_sender = address::derive_from_private_key(*msg_sender_private_key); + msg_sender.assert_equal(derived_msg_sender, + format("msg_sender validation failed.\nmsg_sender_private_key: ", + msg_sender_private_key, + "\nPurported msg_sender: ", + msg_sender, + "\nDerived msg_sender: ", + derived_msg_sender)); + } +}; + +} // namespace aztec3::circuits::apps \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/private_state.test.cpp b/circuits/src/aztec3/circuits/apps/private_state.test.cpp new file mode 100644 index 00000000000..c472f53b077 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/private_state.test.cpp @@ -0,0 +1,116 @@ +#include +#include +#include +// #include +#include "index.hpp" +#include +// #include +// #include +// #include + +namespace aztec3::circuits::apps { + +namespace { +using TurboComposer = plonk::stdlib::types::turbo::Composer; +using CT = plonk::stdlib::types::CircuitTypes; +using NT = plonk::stdlib::types::NativeTypes; +// using plonk::stdlib::pedersen; +} // namespace + +class private_state_tests : public ::testing::Test {}; + +// TEST(private_state_tests, test_native_private_state) +// { +// StateFactory state_factory("MyContract"); +// PrivateStateVar x = state_factory.new_private_state("x"); + +// PrivateStateVar native_private_state = PrivateStateVar(x); + +// auto buffer = to_buffer(native_private_state); + +// auto native_private_state_2 = from_buffer>(buffer.data()); + +// EXPECT_EQ(native_private_state, native_private_state_2); +// } + +// TEST(private_state_tests, test_create_private_state) +// { +// StateFactory state_factory("MyContract"); + +// state_factory.new_private_state("balances", { "asset_id", "owner_address" }); + +// state_factory.new_private_state("x"); + +// // info("state_factory: ", state_factory); +// } + +// TEST(private_state_tests, test_native_private_state_note_preimage) +// { +// StateFactory state_factory("MyContract"); +// PrivateStateVar x = state_factory.new_private_state("x"); + +// PrivateStateNotePreimage native_preimage = { +// .value = 2, +// .owner_address = 3, +// .creator_address = NT::address(4), +// .salt = 5, +// .input_nullifier = 6, +// .memo = 7, +// }; + +// auto buffer = to_buffer(native_preimage); + +// auto native_preimage_2 = from_buffer>(buffer.data()); + +// EXPECT_EQ(native_preimage, native_preimage_2); +// } + +// TEST(private_state_tests, test_native_private_state_note_preimage_mapping) +// { +// StateFactory state_factory("MyContract"); +// PrivateStateVar x = state_factory.new_private_state("x", { "mapping_key_name_1", "mapping_key_name_2" }); + +// PrivateStateNotePreimage native_preimage = { +// .mapping_key_values_by_key_name = std::map>({ { "mapping_key_name_2", 5 } }), +// .value = 2, +// .owner_address = 3, +// .creator_address = NT::address(4), +// .salt = 5, +// .input_nullifier = 6, +// .memo = 7, +// }; + +// auto buffer = to_buffer(native_preimage); + +// auto native_preimage_2 = from_buffer>(buffer.data()); + +// EXPECT_EQ(native_preimage, native_preimage_2); +// } + +// TEST(private_state_tests, test_native_private_state_note_mapping) +// { +// StateFactory state_factory("MyContract"); +// PrivateStateVar x = state_factory.new_private_state("x", { "mapping_key_name_1", "mapping_key_name_2" }); + +// PrivateStateNotePreimage private_state_preimage = { +// .mapping_key_values_by_key_name = std::map>({ { "mapping_key_name_2", 5 } }), +// .value = 2, +// .owner_address = 3, +// .creator_address = NT::address(4), +// .salt = 5, +// .input_nullifier = 6, +// .memo = 7, +// }; + +// PrivateStateNote private_state_note = PrivateStateNote(x, private_state_preimage); + +// auto buffer = to_buffer(private_state_note); + +// auto private_state_note_2 = from_buffer>(buffer.data()); + +// EXPECT_EQ(private_state_note, private_state_note_2); +// } + +/// TODO: figure out how to catch and test errors in gtest. + +} // namespace aztec3::circuits::apps \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/private_state_factory.hpp b/circuits/src/aztec3/circuits/apps/private_state_factory.hpp new file mode 100644 index 00000000000..230ae2b394c --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/private_state_factory.hpp @@ -0,0 +1,101 @@ +#pragma once +#include +#include "private_state_note.hpp" +#include "private_state_var.hpp" +#include "oracle_wrapper.hpp" +#include + +namespace aztec3::circuits::apps { + +using plonk::stdlib::witness_t; +using plonk::stdlib::types::CircuitTypes; +using NT = plonk::stdlib::types::NativeTypes; + +template class PrivateStateFactory { + typedef CircuitTypes CT; + typedef typename CT::fr fr; + + public: + Composer& composer; + OracleWrapperInterface& oracle; + const std::string contract_name; + fr private_state_counter; + + std::map> private_state_vars; + std::vector> private_state_notes; + std::vector commitments; + std::vector nullifiers; + + PrivateStateFactory(Composer& composer, + OracleWrapperInterface& oracle, + std::string contract_name) + : composer(composer) + , oracle(oracle) + , contract_name(contract_name) + { + private_state_counter = witness_t(&composer, 0); + private_state_counter.assert_is_zero(); + }; + + PrivateStateVar& new_private_state(std::string const& name, + PrivateStateType const& private_state_type = PARTITIONED) + { + if (private_state_vars.contains(name)) { + throw_or_abort("name already exists"); + } + PrivateStateVar private_state_var = + PrivateStateVar(this, private_state_type, name, private_state_counter++); + private_state_vars.insert(std::make_pair(name, private_state_var)); + return private_state_vars[name]; + }; + + // For initialising a private state which is a mapping. + PrivateStateVar& new_private_state(std::string const& name, + std::vector const& mapping_key_names, + PrivateStateType const& private_state_type = PARTITIONED) + { + if (private_state_vars.contains(name)) { + throw_or_abort("name already exists"); + } + PrivateStateVar private_state_var = + PrivateStateVar(this, private_state_type, name, private_state_counter++, mapping_key_names); + private_state_vars.insert(std::make_pair(name, private_state_var)); + return private_state_vars[name]; + }; + + void finalise() + { + if (private_state_notes.size() > nullifiers.size()) { + // We want to create more commitments than the number of nullifiers we've created so-far. But we want to + // inject an input_nullifier into each new commitment. So, let's create more dummy nullifiers. + const auto& msg_sender_private_key = oracle.get_msg_sender_private_key(); + for (size_t i = nullifiers.size(); i < private_state_notes.size(); ++i) { + nullifiers.push_back(PrivateStateNote::compute_dummy_nullifier( + oracle.generate_random_element(), msg_sender_private_key)); + } + } + for (size_t i = 0; i < private_state_notes.size(); ++i) { + private_state_notes[i].preimage.input_nullifier = nullifiers[i]; + commitments.push_back(private_state_notes[i].compute_commitment()); + } + } + + PrivateStateVar& get(std::string const& name) + { + if (!private_state_vars.contains(name)) { + throw_or_abort("name not found"); + } + return private_state_vars[name]; + }; + + void push_new_note(PrivateStateNote const private_state_note) + { + private_state_notes.push_back(private_state_note); + } + + void push_new_commitment(fr const& commitment) { commitments.push_back(commitment); } + + void push_new_nullifier(fr const& nullifier) { nullifiers.push_back(nullifier); } +}; + +} // namespace aztec3::circuits::apps \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/private_state_note.hpp b/circuits/src/aztec3/circuits/apps/private_state_note.hpp new file mode 100644 index 00000000000..8f80eef9b99 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/private_state_note.hpp @@ -0,0 +1,136 @@ +#pragma once +#include +#include + +namespace aztec3::circuits::apps { + +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; + +template class PrivateStateVar; +template struct PrivateStateNotePreimage; + +template class PrivateStateNote { + public: + typedef CircuitTypes CT; + typedef typename CT::fr fr; + typedef typename CT::grumpkin_point grumpkin_point; + typedef typename CT::address address; + typedef typename CT::boolean boolean; + + PrivateStateVar& private_state_var; + PrivateStateNotePreimage preimage; + + bool is_partial = false; + + PrivateStateNote(PrivateStateVar& private_state_var, + PrivateStateNotePreimage preimage, + bool commit_on_init = false); + + bool operator==(PrivateStateNote const&) const = default; + + fr get_commitment() const + { + if (!commitment) { + throw_or_abort("No commitment exists for this note. Are you sure you haven't accidentally created a " + "partial commitment? Make sure to populate all preimage values."); + } + return *commitment; + }; + + grumpkin_point get_partial_commitment() const + { + if (!partial_commitment) { + throw_or_abort( + "No partial_commitment exists for this note. Are you sure you haven't accidentally created a " + "complete commitment?"); + } + return *partial_commitment; + }; + + fr get_nullifier() const + { + if (!nullifier) { + throw_or_abort("No nullifier exists for this note yet. Call compute_nullifier() first."); + } + return *nullifier; + }; + + fr compute_commitment() const; + grumpkin_point compute_partial_commitment() const; + + fr compute_nullifier(fr const& owner_private_key); + static fr compute_nullifier(fr const& commitment, + fr const& owner_private_key, + boolean const& is_real_commitment = true); + static fr compute_dummy_nullifier(fr const& dummy_commitment, fr const& owner_private_key); + + private: + bool check_if_partial() const; + + std::optional partial_commitment; + std::optional commitment; + std::optional nullifier; +}; + +// // template PrivateStateNote from_buffer(B const& buffer, size_t offset = 0) +// // { +// // using serialize::read; +// // auto ptr = (uint8_t const*)&buffer[offset]; + +// // PrivateStateVar private_state_var; +// // PrivateStateNotePreimage preimage; + +// // read(ptr, private_state_var); +// // read(ptr, preimage); + +// // PrivateStateNote private_state_note = PrivateStateNote(private_state_var, preimage); + +// // return private_state_note; +// // }; + +// template void read(uint8_t const*& it, PrivateStateNote& note) +// { +// using serialize::read; + +// read(it, note.private_state_var); +// read(it, note.preimage); +// read(it, note.is_partial); +// read(it, note.partial_commitment); +// read(it, note.commitment); +// read(it, note.nullifier); +// }; + +// template +// void write(std::vector& buf, PrivateStateNote const& note) +// { +// using serialize::write; + +// write(buf, note.private_state_var); +// write(buf, note.preimage); +// write(buf, note.is_partial); +// write(buf, note.partial_commitment); +// write(buf, note.commitment); +// write(buf, note.nullifier); +// }; + +// template +// std::ostream& operator<<(std::ostream& os, PrivateStateNote const& note) +// { +// return os << "private_state_var: " << note.private_state_var << "\n" +// << "preimage: " << note.preimage << "\n" +// << "is_partial: " << note.is_partial << "\n" +// << "partial_commitment: " << note.partial_commitment << "\n" +// << "commitment: " << note.commitment << "\n" +// << "nullifier: " << note.nullifier << "\n"; +// } + +} // namespace aztec3::circuits::apps + +// Importing in this way (rather than explicit instantiation of a template class at the bottom of a .cpp file) preserves +// the following: +// - We retain implicit instantiation of templates, meaning we can pick and choose (with static_assert) which class +// methods support native, +// circuit or both types. +// - We don't implement method definitions in this file, to avoid a circular dependency with state_factory.hpp. +#include "private_state_note.tpp" \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/private_state_note.tpp b/circuits/src/aztec3/circuits/apps/private_state_note.tpp new file mode 100644 index 00000000000..eb821249ef2 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/private_state_note.tpp @@ -0,0 +1,229 @@ +// TODO: remove unused inclusions +// #include "private_state_note.hpp" +#include +#include +#include +#include +#include +#include +#include +#include "oracle_wrapper.hpp" +#include "private_state_var.hpp" +#include "private_state_note_preimage.hpp" +#include "plonk/composer/turbo_composer.hpp" + +namespace aztec3::circuits::apps { + +namespace { +using aztec3::GeneratorIndex; +using crypto::pedersen::generator_index_t; +using plonk::stdlib::witness_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; +} // namespace + +template +PrivateStateNote::PrivateStateNote(PrivateStateVar& private_state_var, + PrivateStateNotePreimage preimage, + bool commit_on_init) + : private_state_var(private_state_var) + , preimage(preimage) + , is_partial(check_if_partial()) +{ + if (commit_on_init) { + if (is_partial) { + partial_commitment = compute_partial_commitment(); + } else { + commitment = compute_commitment(); + } + } +} + +template bool PrivateStateNote::check_if_partial() const +{ + const auto& [start_slot, slot_point, value, owner_address, creator_address, salt, input_nullifier, memo, _] = + preimage; + + if (!value || !owner_address || !creator_address || !salt || !input_nullifier || !memo) { + return true; + } + if (private_state_var.is_partial_slot) { + return true; + } + return false; +} + +template typename CircuitTypes::fr PrivateStateNote::compute_commitment() const +{ + if (commitment.has_value()) { + return *commitment; + } + + info("preimage: ", preimage); + + grumpkin_point slot_point = private_state_var.slot_point; + + std::vector inputs; + std::vector generators; + + auto gen_pair_address = [&](std::optional
const& input, size_t const hash_sub_index) { + if (!input) { + throw_or_abort("Cannot commit to a partial preimage. Call compute_partial_commitment instead, or complete " + "the preimage."); + } + return std::make_pair((*input).to_field(), generator_index_t({ GeneratorIndex::COMMITMENT, hash_sub_index })); + }; + + auto gen_pair_fr = [&](std::optional const& input, size_t const hash_sub_index) { + if (!input) { + throw_or_abort("Cannot commit to a partial preimage. Call compute_partial_commitment instead, or complete " + "the preimage."); + } + return std::make_pair(*input, generator_index_t({ GeneratorIndex::COMMITMENT, hash_sub_index })); + }; + + const auto& [start_slot, + mapping_key_values_by_key_name, + value, + owner_address, + creator_address, + salt, + input_nullifier, + memo, + is_real] = preimage; + + const auto commitment_point = + slot_point + + CT::commit( + { gen_pair_fr(value, PrivateStateNoteGeneratorIndex::VALUE), + gen_pair_address(owner_address, PrivateStateNoteGeneratorIndex::OWNER), + gen_pair_address(creator_address, PrivateStateNoteGeneratorIndex::CREATOR), + gen_pair_fr(salt, PrivateStateNoteGeneratorIndex::SALT), + gen_pair_fr(input_nullifier, PrivateStateNoteGeneratorIndex::INPUT_NULLIFIER), + gen_pair_fr(memo, PrivateStateNoteGeneratorIndex::MEMO), + std::make_pair(is_real, + generator_index_t({ GeneratorIndex::COMMITMENT, PrivateStateNoteGeneratorIndex::IS_REAL })) + + }); + + return commitment_point.x; +} + +template +typename CircuitTypes::grumpkin_point PrivateStateNote::compute_partial_commitment() const +{ + if (partial_commitment.has_value()) { + info( + "WARNING: you've already computed a partial commitment for this note. Now, you might have since changed " + "the preimage and you want to update the partial commitment, and that's ok, so we won't throw an error " + "here. But if that's not the case, you should call get_partial_commitment() instead, to save constraints."); + } + + grumpkin_point slot_point = private_state_var.slot_point; + + std::vector inputs; + std::vector generators; + + auto gen_pair_address = [&](std::optional
const& input, size_t const hash_sub_index) { + return input ? std::make_pair((*input).to_field(), + generator_index_t({ GeneratorIndex::COMMITMENT, hash_sub_index })) + : std::make_pair(fr(1), + generator_index_t({ GeneratorIndex::COMMITMENT_PLACEHOLDER, hash_sub_index })); + }; + + auto gen_pair_fr = [&](std::optional const& input, size_t const hash_sub_index) { + return input ? std::make_pair(*input, generator_index_t({ GeneratorIndex::COMMITMENT, hash_sub_index })) + : std::make_pair(fr(1), + generator_index_t({ GeneratorIndex::COMMITMENT_PLACEHOLDER, hash_sub_index })); + }; + + const auto& [start_slot, + mapping_key_values_by_key_name, + value, + owner_address, + creator_address, + salt, + input_nullifier, + memo, + is_real] = preimage; + + return slot_point + CT::commit({ gen_pair_fr(value, PrivateStateNoteGeneratorIndex::VALUE), + gen_pair_address(owner_address, PrivateStateNoteGeneratorIndex::OWNER), + gen_pair_address(creator_address, PrivateStateNoteGeneratorIndex::CREATOR), + gen_pair_fr(salt, PrivateStateNoteGeneratorIndex::SALT), + gen_pair_fr(input_nullifier, PrivateStateNoteGeneratorIndex::INPUT_NULLIFIER), + gen_pair_fr(memo, PrivateStateNoteGeneratorIndex::MEMO), + std::make_pair(is_real, + generator_index_t({ GeneratorIndex::COMMITMENT, + PrivateStateNoteGeneratorIndex::IS_REAL })) + + }); +} + +template +typename CircuitTypes::fr PrivateStateNote::compute_nullifier(fr const& owner_private_key) +{ + if (is_partial) { + throw_or_abort("Can't nullify a partial note."); + } + if (!commitment) { + throw_or_abort("Commitment not yet calculated. Call compute_commitment() or change how you initialise this " + "note to include the `commit_on_init` bool."); + } + if (nullifier.has_value()) { + return *nullifier; + } + nullifier = PrivateStateNote::compute_nullifier(*commitment, owner_private_key, preimage.is_real); + return *nullifier; +}; + +template +typename CircuitTypes::fr PrivateStateNote::compute_nullifier(fr const& commitment, + fr const& owner_private_key, + boolean const& is_real_commitment) +{ + /** + * Hashing the private key in this way enables the following use case: + * - A user can demonstrate to a 3rd party that they have spent a note, by providing the + hashed_private_key + * and the note_commitment. The 3rd party can then recalculate the nullifier. This does not reveal the + * underlying private_key to the 3rd party. */ + const grumpkin_point hashed_private_key = CT::grumpkin_group::template fixed_base_scalar_mul<254>( + owner_private_key, GeneratorIndex::NULLIFIER_HASHED_PRIVATE_KEY); + + const std::vector hash_inputs{ + commitment, + hashed_private_key.x, + hashed_private_key.y, + is_real_commitment, + }; + + // We compress the hash_inputs with Pedersen, because that's cheaper (constraint-wise) than compressing + // the data directly with Blake2s in the next step. + const fr compressed_inputs = CT::compress(hash_inputs, GeneratorIndex::NULLIFIER); + + // Blake2s hash the compressed result. Without this it's possible to leak info from the pedersen + // compression. + /** E.g. we can extract a representation of the hashed_pk: + * Paraphrasing, if: + * nullifier = note_comm * G1 + hashed_pk * G2 + is_real_note * G3 + * Then an observer can derive hashed_pk * G2 = nullifier - note_comm * G1 - is_real_note * G3 + * They can derive this for every tx, to link which txs are being sent by the same user. + * Notably, at the point someone withdraws, the observer would be able to connect `hashed_pk * G2` with a + * specific eth address. + */ + auto blake_input = typename CT::byte_array(compressed_inputs); + auto blake_result = CT::blake2s(blake_input); + return fr(blake_result); +}; + +template +typename CircuitTypes::fr PrivateStateNote::compute_dummy_nullifier(fr const& dummy_commitment, + fr const& owner_private_key) +{ + return PrivateStateNote::compute_nullifier(dummy_commitment, owner_private_key, false); +} + +// template class PrivateStateNote; + +} // namespace aztec3::circuits::apps \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/private_state_note_preimage.hpp b/circuits/src/aztec3/circuits/apps/private_state_note_preimage.hpp new file mode 100644 index 00000000000..5c6fc8dd8bc --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/private_state_note_preimage.hpp @@ -0,0 +1,98 @@ +#pragma once +#include +#include +#include +#include +#include +#include + +namespace aztec3::circuits::apps { + +using crypto::pedersen::generator_index_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; + +template struct PrivateStateNotePreimage { + typedef typename NCT::fr fr; + typedef typename NCT::grumpkin_point grumpkin_point; + typedef typename NCT::address address; + typedef typename NCT::boolean boolean; + + // No custom constructors so that designated initializers can be used (for readability of test circuits). + + std::optional start_slot; // TODO: remove optionality + std::optional slot_point; // TODO: remove optionality? + std::optional value; + std::optional
owner_address; + std::optional
creator_address; + std::optional salt; + std::optional input_nullifier; + std::optional memo; // numerical representation of a string + + boolean is_real; + + bool operator==(PrivateStateNotePreimage const&) const = default; + + template + PrivateStateNotePreimage> to_circuit_type(Composer& composer) const + { + static_assert((std::is_same::value)); + + // Capture the composer: + auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + + PrivateStateNotePreimage> preimage = { + to_ct(start_slot), to_ct(slot_point), to_ct(value), to_ct(owner_address), to_ct(creator_address), + to_ct(salt), to_ct(input_nullifier), to_ct(memo), to_ct(is_real), + }; + + return preimage; + }; +}; + +template void read(uint8_t const*& it, PrivateStateNotePreimage& preimage) +{ + using serialize::read; + + read(it, preimage.start_slot); + read(it, preimage.slot_point); + read(it, preimage.value); + read(it, preimage.owner_address); + read(it, preimage.creator_address); + read(it, preimage.salt); + read(it, preimage.input_nullifier); + read(it, preimage.memo); + read(it, preimage.is_real); +}; + +template void write(std::vector& buf, PrivateStateNotePreimage const& preimage) +{ + using serialize::write; + + write(buf, preimage.start_slot); + write(buf, preimage.slot_point); + write(buf, preimage.value); + write(buf, preimage.owner_address); + write(buf, preimage.creator_address); + write(buf, preimage.salt); + write(buf, preimage.input_nullifier); + write(buf, preimage.memo); + write(buf, preimage.is_real); +}; + +template std::ostream& operator<<(std::ostream& os, PrivateStateNotePreimage const& preimage) +{ + return os << "start_slot: " << preimage.start_slot << "\n" + << "slot_point: " << preimage.slot_point << "\n" + << "value: " << preimage.value << "\n" + << "owner_address: " << preimage.owner_address << "\n" + << "creator_address: " << preimage.creator_address << "\n" + << "salt: " << preimage.salt << "\n" + << "input_nullifier: " << preimage.input_nullifier << "\n" + << "memo: " << preimage.memo << "\n" + << "is_real: " << preimage.is_real << "\n"; +} + +template using MappingKeyValues = std::map>; + +} // namespace aztec3::circuits::apps \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/private_state_operand.hpp b/circuits/src/aztec3/circuits/apps/private_state_operand.hpp new file mode 100644 index 00000000000..3caac8a09d7 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/private_state_operand.hpp @@ -0,0 +1,44 @@ +#pragma once +#include +#include +#include +#include +#include +#include + +namespace aztec3::circuits::apps { + +using crypto::pedersen::generator_index_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; + +template struct PrivateStateOperand { + typedef typename NCT::fr fr; + typedef typename NCT::address address; + + fr value; + address owner_address; + std::optional
creator_address; + std::optional memo; // numerical representation of a string + + bool operator==(PrivateStateOperand const&) const = default; + + template PrivateStateOperand> to_circuit_type(Composer& composer) const + { + static_assert((std::is_same::value)); + + // Capture the composer: + auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + + PrivateStateOperand> preimage = { + to_ct(value), + to_ct(owner_address), + to_ct(creator_address), + to_ct(memo), + }; + + return preimage; + }; +}; + +} // namespace aztec3::circuits::apps \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/private_state_var.hpp b/circuits/src/aztec3/circuits/apps/private_state_var.hpp new file mode 100644 index 00000000000..07d70b1a252 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/private_state_var.hpp @@ -0,0 +1,135 @@ +#pragma once +#include +#include +#include "private_state_note.hpp" +#include "private_state_note_preimage.hpp" +#include "private_state_operand.hpp" +#include + +namespace aztec3::circuits::apps { + +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; + +template class PrivateStateFactory; + +template class PrivateStateVar { + public: + typedef CircuitTypes CT; + typedef typename CT::fr fr; + typedef typename CT::address address; + typedef typename CT::grumpkin_point grumpkin_point; + + PrivateStateFactory* state_factory; + PrivateStateType private_state_type; + std::string name; + fr start_slot; + grumpkin_point slot_point; /// TODO: make this std::optional (since mappings won't have this) + + // A mapping var (in particular) can point to many private_states: + std::map> private_states; + + bool is_mapping = false; + std::optional> mapping_key_names = std::nullopt; + + bool is_partial_slot = false; + + PrivateStateVar(){}; + + PrivateStateVar(PrivateStateVar const& private_state_var) + : state_factory(private_state_var.state_factory) + , private_state_type(private_state_var.private_state_type) + , name(private_state_var.name) + , start_slot(private_state_var.start_slot) + , slot_point(private_state_var.slot_point) + , is_mapping(private_state_var.is_mapping) + , mapping_key_names(private_state_var.mapping_key_names) + , is_partial_slot(private_state_var.is_partial_slot){}; + + // For initialising a basic fr state: + PrivateStateVar(PrivateStateFactory* state_factory, + PrivateStateType const& private_state_type, + std::string const& name, + fr const& start_slot) + : state_factory(state_factory) + , private_state_type(private_state_type) + , name(name) + , start_slot(start_slot) + { + slot_point = compute_start_slot_point(); + }; + + // For initialising a mapping var: + PrivateStateVar(PrivateStateFactory* state_factory, + PrivateStateType const& private_state_type, + std::string const& name, + fr const start_slot, + std::vector const& mapping_key_names) + : state_factory(state_factory) + , private_state_type(private_state_type) + , name(name) + , start_slot(start_slot) + , is_mapping(mapping_key_names.size() > 0) + , mapping_key_names(mapping_key_names.size() > 0 ? std::make_optional(mapping_key_names) : std::nullopt) + , is_partial_slot(true) + { + if (mapping_key_names.size() == 0) { + throw_or_abort("Error. Empty mapping_key_names argument. Try calling the other constructor if you don't " + "want to initialise a mapping state."); + } + }; + + bool operator==(PrivateStateVar const&) const = default; + + PrivateStateVar& at(std::optional const& key) { return at(std::vector>{ key }); }; + + PrivateStateVar& at(std::vector> const& keys); + + std::vector get_mapping_key_names() const; + + size_t get_index_of_mapping_key_name(std::string const& mapping_key_name) const; + + PrivateStateNote new_note(PrivateStateNotePreimage& preimage); + + // Arithmetic on private states: + void add(PrivateStateOperand const& operand); + + void subtract(PrivateStateOperand const& operant); + + static std::tuple compute_slot_point_at_mapping_keys( + NativeTypes::fr const& start_slot, std::vector> const& keys); + + std::tuple compute_slot_point_at_mapping_keys(std::vector> const& keys); + + private: + grumpkin_point compute_start_slot_point(); + + // For initialising an fr state from within a mapping: + PrivateStateVar(PrivateStateFactory* state_factory, + PrivateStateType const& private_state_type, + std::string const& name, + fr const& start_slot, + grumpkin_point const& slot_point, + bool const& is_partial_slot) + : state_factory(state_factory) + , private_state_type(private_state_type) + , name(name) + , start_slot(start_slot) + , slot_point(slot_point) + , is_partial_slot(is_partial_slot){}; + + void arithmetic_checks(); + void validate_operand(PrivateStateOperand const& operand) const; + + size_t op_count = 0; +}; + +} // namespace aztec3::circuits::apps + +// Importing in this way (rather than explicit instantiation of a template class at the bottom of a .cpp file) preserves +// the following: +// - We retain implicit instantiation of templates, meaning we can pick and choose (with static_assert) which class +// methods support native, +// circuit or both types. +// - We don't implement method definitions in this file, to avoid a circular dependency with state_factory.hpp. +#include "private_state_var.tpp" diff --git a/circuits/src/aztec3/circuits/apps/private_state_var.tpp b/circuits/src/aztec3/circuits/apps/private_state_var.tpp new file mode 100644 index 00000000000..dc8440875f0 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/private_state_var.tpp @@ -0,0 +1,288 @@ +// #include "private_state_var.hpp" +// #include +#include +#include +#include +#include +#include +#include +#include +#include "oracle_wrapper.hpp" +#include "private_state_factory.hpp" +#include "private_state_note.hpp" +#include "private_state_note_preimage.hpp" +#include "private_state_operand.hpp" +#include "plonk/composer/turbo_composer.hpp" + +namespace aztec3::circuits::apps { + +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; + +// Fr: |> start_slot * A +// M1: start_slot * A + mk1 * B |> +// M2: start_slot * A + mk1 * B + mk2 * C |> +template +typename CircuitTypes::grumpkin_point PrivateStateVar::compute_start_slot_point() +{ + return CT::commit({ start_slot }, { PrivateStateNoteGeneratorIndex::MAPPING_SLOT }); +} + +template +std::tuple PrivateStateVar::compute_slot_point_at_mapping_keys( + NativeTypes::fr const& start_slot, std::vector> const& keys) +{ + bool is_partial_slot = false; + + std::vector> input_pairs; + + input_pairs.push_back(std::make_pair(start_slot, + generator_index_t({ PrivateStateNoteGeneratorIndex::MAPPING_SLOT, + 0 }))); // hash_sub_index 0 is reserved for the start_slot. + + for (size_t i = 0; i < keys.size(); ++i) { + if (keys[i]) { + input_pairs.push_back( + std::make_pair(*keys[i], + generator_index_t({ PrivateStateNoteGeneratorIndex::MAPPING_SLOT, + i + 1 }))); // hash_sub_index 0 is reserved for the start_slot. + } else { + // If this mapping key has no mapping_key_value (std::nullopt), then we must be partially committing and + // omitting this mapping key from that partial commitment. + // So use a placeholder generator for this mapping key, to signify "this mapping key is missing". + // Note: we can't just commit to a value of `0` for this mapping key, since `0` is a valid value to + // commit to, and so "missing" is distinguished as follows. + input_pairs.push_back( + std::make_pair(NativeTypes::fr(1), + generator_index_t({ PrivateStateNoteGeneratorIndex::MAPPING_SLOT_PLACEHOLDER, i + 1 }))); + } + } + + return std::make_tuple(NativeTypes::commit(input_pairs), is_partial_slot); +} + +template +std::tuple::grumpkin_point, bool> PrivateStateVar< + Composer>::compute_slot_point_at_mapping_keys(std::vector> const& keys) +{ + bool is_partial_slot = false; + + std::vector> input_pairs; + + input_pairs.push_back(std::make_pair(start_slot, + generator_index_t({ PrivateStateNoteGeneratorIndex::MAPPING_SLOT, + 0 }))); // hash_sub_index 0 is reserved for the start_slot. + + for (size_t i = 0; i < keys.size(); ++i) { + if (keys[i]) { + input_pairs.push_back( + std::make_pair(*keys[i], + generator_index_t({ PrivateStateNoteGeneratorIndex::MAPPING_SLOT, + i + 1 }))); // hash_sub_index 0 is reserved for the start_slot. + } else { + // If this mapping key has no mapping_key_value (std::nullopt), then we must be partially committing and + // omitting this mapping key from that partial commitment. + // So use a placeholder generator for this mapping key, to signify "this mapping key is missing". + // Note: we can't just commit to a value of `0` for this mapping key, since `0` is a valid value to + // commit to, and so "missing" is distinguished as follows. + input_pairs.push_back(std::make_pair( + fr(1), generator_index_t({ PrivateStateNoteGeneratorIndex::MAPPING_SLOT_PLACEHOLDER, i + 1 }))); + } + } + + return std::make_tuple(CT::commit(input_pairs), is_partial_slot); +} + +template +PrivateStateVar& PrivateStateVar::at(std::vector> const& keys) +{ + if (!is_mapping) { + throw_or_abort("var is not a mapping - cannot call `at()`"); + } + + if (keys.size() != (*mapping_key_names).size()) { + throw_or_abort("Need to provide a vector of length equal to this mapping's # keys, even if some are keys are " + "intentionally blank (std::optional, for partially-committing"); + } + + // First calculate natively and check to see if we've already calculated this state's slot and stored it in the + // cache, so we don't create unnecessary circuit gates: + std::vector> native_keys; + for (const auto& key : keys) { + std::optional native_key; + if (!key) { + native_key = std::nullopt; + } else { + native_key = NativeTypes::fr((*key).get_value()); + } + native_keys.push_back(native_key); + } + + bool is_partial_slot; + NativeTypes::grumpkin_point native_new_slot_point; + std::tie(native_new_slot_point, is_partial_slot) = + PrivateStateVar::compute_slot_point_at_mapping_keys(start_slot.get_value(), native_keys); + NativeTypes::fr native_lookup = native_new_slot_point.x; + + // Check cache + if (private_states.contains(native_lookup)) { + return private_states[native_lookup]; + } + + // Create gates: + grumpkin_point new_slot_point; + std::tie(new_slot_point, is_partial_slot) = compute_slot_point_at_mapping_keys(keys); + NativeTypes::fr lookup = new_slot_point.x.get_value(); + + if (lookup != native_lookup) { + throw_or_abort("Expected lookup calcs to be equal!"); + } + + PrivateStateVar new_state = + PrivateStateVar(state_factory, private_state_type, name, start_slot, new_slot_point, is_partial_slot); + + private_states[lookup] = new_state; + + return private_states[lookup]; +} + +template std::vector PrivateStateVar::get_mapping_key_names() const +{ + if (!mapping_key_names) { + throw_or_abort("Not a mapping."); + } + return *mapping_key_names; +} + +template +size_t PrivateStateVar::get_index_of_mapping_key_name(std::string const& mapping_key_name) const +{ + if (mapping_key_names) { + auto begin = (*mapping_key_names).begin(); + auto end = (*mapping_key_names).end(); + auto itr = std::find(begin, end, mapping_key_name); + if (itr != end) { + return size_t(itr - begin); + } else { + throw_or_abort("mapping key name not found"); + } + } else { + throw_or_abort("This private state is not a mapping."); + } +} + +template void PrivateStateVar::arithmetic_checks() +{ + if (private_state_type == WHOLE) { + throw_or_abort("Code not yet written to support 'whole' private states"); + } + + if (is_partial_slot) { + throw_or_abort("Arithmetic on a partial state is not supported"); + } + + if (op_count > 0) { + throw_or_abort("Cannot perform more than one operation on this state."); + } + ++op_count; +} + +template +void PrivateStateVar::validate_operand(PrivateStateOperand const& operand) const +{ + if (operand.creator_address) { + auto& oracle = state_factory->oracle; + const auto& msg_sender = oracle.get_msg_sender(); + (*operand.creator_address).assert_is_in_set({ msg_sender, address(0) }); + } +} + +template +void PrivateStateVar::add(PrivateStateOperand> const& operand) +{ + arithmetic_checks(); + validate_operand(operand); + + auto& oracle = state_factory->oracle; + auto& composer = oracle.composer; + + PrivateStateNotePreimage new_note_preimage = PrivateStateNotePreimage{ + .start_slot = start_slot, + .slot_point = slot_point, + .value = operand.value, + .owner_address = operand.owner_address, + .creator_address = operand.creator_address, + .salt = oracle.generate_salt(), + // .input_nullifier = // this will be injected by the state_factory + .memo = operand.memo, + .is_real = plonk::stdlib::types::to_ct(composer, true), + }; + + auto new_note = PrivateStateNote(*this, new_note_preimage); + + state_factory->push_new_note(new_note); +} + +template +void PrivateStateVar::subtract(PrivateStateOperand> const& operand) +{ + arithmetic_checks(); + validate_operand(operand); + + // Terminology: difference = minuend - subtrahend + + auto& oracle = state_factory->oracle; + auto& composer = oracle.composer; + + const fr& subtrahend = operand.value; + + auto [minuend_preimage_1, minuend_preimage_2] = + oracle.get_private_state_note_preimages_for_subtraction(slot_point.x, operand.owner_address, subtrahend); + + (*minuend_preimage_1.start_slot).assert_equal(start_slot); + (*minuend_preimage_1.slot_point).assert_equal(slot_point); + // value enforced through the below subtraction. + (*minuend_preimage_1.owner_address).assert_equal(operand.owner_address); + // other info about notes being spent is irrelevant. + + (*minuend_preimage_2.start_slot).assert_equal(start_slot); + (*minuend_preimage_2.slot_point).assert_equal(slot_point); + // value enforced through the below subtraction. + (*minuend_preimage_2.owner_address).assert_equal(operand.owner_address); + // other info about notes being spent is irrelevant. + + const fr& minuend = *minuend_preimage_1.value + *minuend_preimage_2.value; + + const fr& difference = minuend - subtrahend; /// TODO: prevent underflow + + auto difference_preimage = PrivateStateNotePreimage{ + .start_slot = start_slot, + .slot_point = slot_point, + .value = difference, + .owner_address = operand.owner_address, + .creator_address = operand.creator_address, + .salt = oracle.generate_salt(), + // .input_nullifier = // this will be injected by the state_factory upon `finalise()` + .memo = operand.memo, + .is_real = plonk::stdlib::types::to_ct(composer, true), + }; + + auto minuend_note_1 = PrivateStateNote(*this, minuend_preimage_1, true); + auto minuend_note_2 = PrivateStateNote(*this, minuend_preimage_2, true); + + fr msg_sender_private_key = oracle.get_msg_sender_private_key(); + fr minuend_nullifier_1 = minuend_note_1.compute_nullifier(msg_sender_private_key); + fr minuend_nullifier_2 = minuend_note_2.compute_nullifier(msg_sender_private_key); + + /// TODO: merkle membership proofs for the two minuend notes. + + auto difference_note = PrivateStateNote(*this, difference_preimage); + + state_factory->push_new_note(difference_note); + state_factory->push_new_nullifier(minuend_nullifier_1); + state_factory->push_new_nullifier(minuend_nullifier_2); +} + +// template class PrivateStateVar; + +}; // namespace aztec3::circuits::apps diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/README.md b/circuits/src/aztec3/circuits/apps/test_apps/escrow/README.md new file mode 100644 index 00000000000..85bb977feed --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/README.md @@ -0,0 +1,3 @@ +# test_apps::escrow + +zk-money functionality in an Aztec3 setting. \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/constants.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/constants.hpp new file mode 100644 index 00000000000..7fe35b23a8b --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/constants.hpp @@ -0,0 +1,25 @@ +// #pragma once +// #include "init.hpp" +// #include +// #include + +// namespace aztec3::circuits::apps::test_apps::escrow { + +// using plonk::stdlib::witness_t; +// CT::boolean TRUE; +// CT::boolean FALSE; +// CT::fr ZERO; + +// void init(Composer& composer) +// { +// TRUE = witness_t(&composer, true); +// TRUE.assert_equal(CT::boolean(true)); + +// FALSE = witness_t(&composer, false); +// FALSE.assert_equal(CT::boolean(false)); + +// ZERO = witness_t(&composer, 0); +// ZERO.assert_equal(CT::fr(0)); +// } + +// } // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp new file mode 100644 index 00000000000..3103ed0f944 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp @@ -0,0 +1,33 @@ +#pragma once +#include "init.hpp" +#include +#include + +namespace aztec3::circuits::apps::test_apps::escrow { + +inline ContractFactory init(Composer& composer, OracleWrapper& oracle) +{ + ContractFactory contract(composer, oracle, "Escrow"); + + contract.new_private_state("balances", { "owner", "asset_id" }); + + // Solely used for assigning vk indices. + contract.set_functions({ + { .name = "deposit", .is_private = true }, + { .name = "transfer", .is_private = true }, + { .name = "withdraw", .is_private = true }, + // not needed, but it's helping me figure out success cases: + { .name = "withdraw_success_callback", .is_private = true }, + { .name = "withdraw_failure_callback", .is_private = true }, + }); + + contract.import_l1_function({ + .function_name = "withdraw", + .function_selector = 12345, + .num_params = 3, + }); + + return contract; +} + +} // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp new file mode 100644 index 00000000000..e4102bb4389 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp @@ -0,0 +1,55 @@ +#include "deposit.hpp" +#include "contract.hpp" +#include +#include +// #include + +namespace aztec3::circuits::apps::test_apps::escrow { + +using aztec3::circuits::abis::PrivateCircuitPublicInputs; + +void deposit( + Composer& composer, OracleWrapper& oracle, NT::fr const& _amount, NT::fr const& _asset_id, NT::fr const& _memo) +{ + CT::fr amount = to_ct(composer, _amount); + CT::fr asset_id = to_ct(composer, _asset_id); + CT::fr memo = to_ct(composer, _memo); + + CT::address msg_sender = oracle.get_msg_sender(); + + auto contract = init(composer, oracle); + + auto& balances = contract.get_private_state("balances"); + + balances.at({ msg_sender.to_field(), asset_id }) + .add({ + .value = amount, + .owner_address = msg_sender, + .creator_address = msg_sender, + .memo = memo, + }); + + contract.finalise(); + + // TODO: maybe pass `oracle` to this `create()` function as well? + auto public_inputs = PrivateCircuitPublicInputs::create(); + + public_inputs.call_context = oracle.get_call_context(); /// TODO: can this be abstracted away out of this body? + + public_inputs.custom_public_inputs[0] = amount; + public_inputs.custom_public_inputs[1] = asset_id; + public_inputs.custom_public_inputs[2] = memo; + + public_inputs.set_commitments(contract.private_state_factory.commitments); + public_inputs.set_nullifiers(contract.private_state_factory.nullifiers); + + public_inputs.pay_fee_from_l1 = to_ct(composer, true); + CT::fr(*public_inputs.pay_fee_from_l1) + .assert_equal(1); /// TODO: Ugly way of hard-coding a witness. Is there a nicer way? + + public_inputs.set_public(composer); + + info("public inputs: ", public_inputs); +}; + +} // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.hpp new file mode 100644 index 00000000000..1590176564b --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.hpp @@ -0,0 +1,9 @@ +#pragma once +#include "init.hpp" + +namespace aztec3::circuits::apps::test_apps::escrow { + +void deposit( + Composer& composer, OracleWrapper& oracle, NT::fr const& _amount, NT::fr const& _asset_id, NT::fr const& _memo); + +} // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/escrow.test.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/escrow.test.cpp new file mode 100644 index 00000000000..550d3531653 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/escrow.test.cpp @@ -0,0 +1,112 @@ +#include +#include +// #include +// #include +// #include +// #include +// #include +#include "index.hpp" +// #include "deposit.hpp" +// #include +// #include +// #include + +namespace aztec3::circuits::apps::test_apps::escrow { + +class escrow_tests : public ::testing::Test {}; + +TEST(escrow_tests, test_deposit) +{ + + Composer composer; + DB db; + + const NT::address contract_address = 12345; + const NT::address msg_sender = + NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); + const NT::fr msg_sender_private_key = 123456789; + + NativeOracle oracle = NativeOracle(db, contract_address, msg_sender, msg_sender_private_key); + OracleWrapper oracle_wrapper = OracleWrapper(composer, oracle); + + auto amount = NT::fr(5); + auto asset_id = NT::fr(1); + auto memo = NT::fr(999); + + deposit(composer, oracle_wrapper, amount, asset_id, memo); + + info("computed witness: ", composer.computed_witness); + info("witness: ", composer.witness); + // info("constant variables: ", composer.constant_variables); + // info("variables: ", composer.variables); + info("failed?: ", composer.failed); + info("err: ", composer.err); + info("n: ", composer.n); +} + +TEST(escrow_tests, test_transfer) +{ + + Composer composer; + DB db; + + const NT::address contract_address = 12345; + const NT::address msg_sender = + NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); + const NT::fr msg_sender_private_key = 123456789; + + NativeOracle oracle = NativeOracle(db, contract_address, msg_sender, msg_sender_private_key); + OracleWrapper oracle_wrapper = OracleWrapper(composer, oracle); + + auto amount = NT::fr(5); + auto to = NT::address(657756); + auto asset_id = NT::fr(1); + auto memo = NT::fr(999); + auto reveal_msg_sender_to_recipient = true; + auto fee = NT::fr(2); + auto is_fee_payment = fee > 0; + + transfer(composer, oracle_wrapper, amount, to, asset_id, memo, reveal_msg_sender_to_recipient, fee, is_fee_payment); + + info("computed witness: ", composer.computed_witness); + info("witness: ", composer.witness); + // info("constant variables: ", composer.constant_variables); + // info("variables: ", composer.variables); + info("failed?: ", composer.failed); + info("err: ", composer.err); + info("n: ", composer.n); +} + +TEST(escrow_tests, test_withdraw) +{ + + Composer composer; + DB db; + + const NT::address contract_address = 12345; + const NT::address msg_sender = + NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); + const NT::fr msg_sender_private_key = 123456789; + + NativeOracle oracle = NativeOracle(db, contract_address, msg_sender, msg_sender_private_key); + OracleWrapper oracle_wrapper = OracleWrapper(composer, oracle); + + auto amount = NT::fr(5); + auto asset_id = NT::fr(1); + auto memo = NT::fr(999); + auto l1_withdrawal_address = NT::fr(657756); + auto fee = NT::fr(2); + auto is_fee_payment = fee > 0; + + withdraw(composer, oracle_wrapper, amount, asset_id, memo, l1_withdrawal_address, fee, is_fee_payment); + + info("computed witness: ", composer.computed_witness); + info("witness: ", composer.witness); + // info("constant variables: ", composer.constant_variables); + // info("variables: ", composer.variables); + info("failed?: ", composer.failed); + info("err: ", composer.err); + info("n: ", composer.n); +} + +} // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/events.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/events.hpp new file mode 100644 index 00000000000..05c40a19227 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/events.hpp @@ -0,0 +1,19 @@ +#pragma once +#include "init.hpp" +// #include +// #include + +namespace aztec3::circuits::apps::test_apps::escrow { + +// StateFactory init_events() +// { +// info("\ninit state..."); + +// StateFactory state_factory("Escrow"); + +// state_factory.new_private_state("balances", { "owner", "asset_id" }); + +// return state_factory; +// } + +} // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/index.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/index.hpp new file mode 100644 index 00000000000..35950908084 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/index.hpp @@ -0,0 +1,6 @@ +#include "init.hpp" +#include "states.hpp" +#include "events.hpp" +#include "deposit.hpp" +#include "transfer.hpp" +#include "withdraw.hpp" \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/init.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/init.hpp new file mode 100644 index 00000000000..bf428bb52c2 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/init.hpp @@ -0,0 +1,21 @@ +#pragma once +#include +#include +#include +#include +#include +#include + +namespace aztec3::circuits::apps::test_apps::escrow { + +using Composer = plonk::stdlib::types::turbo::Composer; +using CT = plonk::stdlib::types::CircuitTypes; +using NT = plonk::stdlib::types::NativeTypes; + +using DB = oracle::FakeDB; +using oracle::NativeOracle; +using OracleWrapper = OracleWrapperInterface; + +using plonk::stdlib::types::to_ct; + +} // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/l1_interface.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/l1_interface.hpp new file mode 100644 index 00000000000..2a28064afde --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/l1_interface.hpp @@ -0,0 +1,10 @@ +#pragma once +#include "init.hpp" +// #include +// #include + +namespace aztec3::circuits::apps::test_apps::escrow { + +// Not sure yet. + +} // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/states.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/states.hpp new file mode 100644 index 00000000000..490c398d778 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/states.hpp @@ -0,0 +1,17 @@ +#pragma once +#include "init.hpp" +#include +#include + +namespace aztec3::circuits::apps::test_apps::escrow { + +inline PrivateStateFactory init_states(Composer& composer, OracleWrapper& oracle) +{ + PrivateStateFactory private_state_factory(composer, oracle, "Escrow"); + + private_state_factory.new_private_state("balances", { "owner", "asset_id" }); + + return private_state_factory; +} + +} // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp new file mode 100644 index 00000000000..1122fa9b307 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp @@ -0,0 +1,96 @@ +#include "transfer.hpp" +#include "contract.hpp" +#include +#include +// #include + +namespace aztec3::circuits::apps::test_apps::escrow { + +using aztec3::circuits::abis::PrivateCircuitPublicInputs; + +void transfer(Composer& composer, + OracleWrapper& oracle, + NT::fr const& _amount, + NT::address const& _to, + NT::fr const& _asset_id, + NT::fr const& _memo, + NT::boolean const& _reveal_msg_sender_to_recipient, + NT::fr const& _fee, + NT::boolean const& _is_fee_payment) +{ + info("\n\nin transfer..."); + + // Initialisation *************************************************************** + + CT::fr amount = to_ct(composer, _amount); + CT::address to = to_ct(composer, _to); + CT::fr asset_id = to_ct(composer, _asset_id); + CT::fr memo = to_ct(composer, _memo); + CT::boolean reveal_msg_sender_to_recipient = to_ct(composer, _reveal_msg_sender_to_recipient); + CT::fr fee = to_ct(composer, _fee); + CT::boolean is_fee_payment = to_ct(composer, _is_fee_payment); + + // Get states and globals ******************************************************* + + CT::address msg_sender = oracle.get_msg_sender(); + + auto contract = init(composer, oracle); + + auto& balances = contract.get_private_state("balances"); + + // Circuit-specific logic ******************************************************* + + CT::address creator_address = + CT::address::conditional_assign(reveal_msg_sender_to_recipient, msg_sender, CT::address(0)); + + balances.at({ msg_sender.to_field(), asset_id }) + .subtract({ + .value = amount + fee, + .owner_address = msg_sender, + .creator_address = msg_sender, + .memo = memo, + }); + + balances.at({ to.to_field(), asset_id }) + .add({ + .value = amount, + .owner_address = to, + .creator_address = creator_address, + .memo = memo, + }); + + // Finalise state_factory ******************************************************* + + contract.finalise(); + + // Assign circuit-specific public inputs **************************************** + + auto public_inputs = PrivateCircuitPublicInputs::create(); + + public_inputs.call_context = oracle.get_call_context(); /// TODO: can this be abstracted away out of this body? + + public_inputs.custom_public_inputs[0] = amount; + public_inputs.custom_public_inputs[1] = to.to_field(); + public_inputs.custom_public_inputs[2] = asset_id; + public_inputs.custom_public_inputs[3] = memo; + public_inputs.custom_public_inputs[4] = CT::fr(reveal_msg_sender_to_recipient); + public_inputs.custom_public_inputs[5] = fee; + public_inputs.custom_public_inputs[6] = is_fee_payment; + + public_inputs.emitted_public_inputs[0] = CT::fr::copy_as_new_witness(composer, fee); + public_inputs.emitted_public_inputs[1] = CT::fr::copy_as_new_witness(composer, asset_id); + + public_inputs.set_commitments(contract.private_state_factory.commitments); + public_inputs.set_nullifiers(contract.private_state_factory.nullifiers); + + /// TODO: merkle membership check + // public_inputs.old_private_data_tree_root + + public_inputs.is_fee_payment = CT::boolean(CT::fr::copy_as_new_witness(composer, is_fee_payment)); + + public_inputs.set_public(composer); + + info("public inputs: ", public_inputs); +}; + +} // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.hpp new file mode 100644 index 00000000000..24b89b4a065 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.hpp @@ -0,0 +1,16 @@ +#pragma once +#include "init.hpp" + +namespace aztec3::circuits::apps::test_apps::escrow { + +void transfer(Composer& composer, + OracleWrapper& oracle, + NT::fr const& _amount, + NT::address const& _to, + NT::fr const& _asset_id, + NT::fr const& _memo, + NT::boolean const& _reveal_msg_sender_to_recipient, + NT::fr const& _fee, + NT::boolean const& _is_fee_payment); + +} // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp new file mode 100644 index 00000000000..b324e60f394 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp @@ -0,0 +1,102 @@ +#include "withdraw.hpp" +#include "contract.hpp" +#include +#include +#include +#include +// #include + +namespace aztec3::circuits::apps::test_apps::escrow { + +using aztec3::circuits::abis::PrivateCircuitPublicInputs; + +void withdraw(Composer& composer, + OracleWrapper& oracle, + NT::fr const& _amount, + NT::fr const& _asset_id, + NT::fr const& _memo, + NT::fr const& _l1_withdrawal_address, + NT::fr const& _fee, + NT::boolean const& _is_fee_payment) +{ + info("\n\nin withdraw..."); + + // Initialisation *************************************************************** + + CT::fr amount = to_ct(composer, _amount); + CT::fr asset_id = to_ct(composer, _asset_id); + CT::fr memo = to_ct(composer, _memo); + CT::fr l1_withdrawal_address = to_ct(composer, _l1_withdrawal_address); + CT::fr fee = to_ct(composer, _fee); + CT::boolean is_fee_payment = to_ct(composer, _is_fee_payment); + + // Get states and globals ******************************************************* + + CT::address msg_sender = oracle.get_msg_sender(); + + auto contract = init(composer, oracle); + + auto& balances = contract.get_private_state("balances"); + + // Circuit-specific logic ******************************************************* + + balances.at({ msg_sender.to_field(), asset_id }) + .subtract({ + .value = amount + fee, + .owner_address = msg_sender, + .creator_address = msg_sender, + .memo = memo, + }); + + auto& l1_withdraw_function = contract.get_l1_function("withdraw"); + + auto [l1_promise, l1_result] = l1_withdraw_function.call({ asset_id, amount, msg_sender.to_field() }); + l1_promise.on_success("withdraw_success_callback", + { + l1_result[0], + amount, + msg_sender.to_field(), + }); + l1_promise.on_failure("withdraw_failure_callback", + { + asset_id, + amount, + msg_sender.to_field(), + memo, + }); + + // Finalise state_factory ******************************************************* + + contract.finalise(); + + // Assign circuit-specific public inputs **************************************** + + auto public_inputs = PrivateCircuitPublicInputs::create(); + + public_inputs.call_context = oracle.get_call_context(); /// TODO: can this be abstracted away out of this body? + + public_inputs.custom_public_inputs[0] = amount; + public_inputs.custom_public_inputs[1] = asset_id; + public_inputs.custom_public_inputs[2] = memo; + public_inputs.custom_public_inputs[3] = l1_withdrawal_address; + public_inputs.custom_public_inputs[4] = fee; + public_inputs.custom_public_inputs[5] = is_fee_payment; + + public_inputs.emitted_public_inputs[0] = CT::fr::copy_as_new_witness(composer, l1_withdrawal_address); + public_inputs.emitted_public_inputs[1] = CT::fr::copy_as_new_witness(composer, asset_id); + public_inputs.emitted_public_inputs[2] = CT::fr::copy_as_new_witness(composer, fee); + + public_inputs.set_commitments(contract.private_state_factory.commitments); + public_inputs.set_nullifiers(contract.private_state_factory.nullifiers); + + /// TODO: merkle membership check + // public_inputs.old_private_data_tree_root + + public_inputs.is_fee_payment = CT::boolean(CT::fr::copy_as_new_witness(composer, is_fee_payment)); + + public_inputs.set_public(composer); + + info("public inputs: ", public_inputs); +}; + +} // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.hpp new file mode 100644 index 00000000000..5207b2cd43f --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.hpp @@ -0,0 +1,15 @@ +#pragma once +#include "init.hpp" + +namespace aztec3::circuits::apps::test_apps::escrow { + +void withdraw(Composer& composer, + OracleWrapper& oracle, + NT::fr const& _amount, + NT::fr const& _asset_id, + NT::fr const& _memo, + NT::fr const& _l1_withdrawal_address, + NT::fr const& _fee, + NT::boolean const& _is_fee_payment); + +} // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw_failure_callback.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw_failure_callback.cpp new file mode 100644 index 00000000000..713545cd2a2 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw_failure_callback.cpp @@ -0,0 +1,61 @@ +#include "deposit.hpp" +#include "contract.hpp" +#include +#include +// #include + +namespace aztec3::circuits::apps::test_apps::escrow { + +using aztec3::circuits::abis::PrivateCircuitPublicInputs; + +void withdraw_failure_callback(Composer& composer, + OracleWrapper& oracle, + NT::fr const& _asset_id, + NT::fr const& _amount, + NT::address const& _owner_address, + NT::fr const& _memo) +{ + CT::fr asset_id = to_ct(composer, _asset_id); + CT::fr amount = to_ct(composer, _amount); + CT::address owner_address = to_ct(composer, _owner_address); + CT::fr memo = to_ct(composer, _memo); + + CT::address msg_sender = oracle.get_msg_sender(); + + auto contract = init(composer, oracle); + + auto& balances = contract.get_private_state("balances"); + + balances.at({ owner_address.to_field(), asset_id }) + .add({ + .value = amount, + .owner_address = owner_address, + .creator_address = msg_sender, + .memo = memo, + }); + + contract.finalise(); + + // TODO: maybe pass `oracle` to this `create()` function as well? + auto public_inputs = PrivateCircuitPublicInputs::create(); + + public_inputs.call_context = oracle.get_call_context(); /// TODO: can this be abstracted away out of this body? + + public_inputs.custom_public_inputs[0] = asset_id; + public_inputs.custom_public_inputs[1] = amount; + public_inputs.custom_public_inputs[2] = owner_address.to_field(); + public_inputs.custom_public_inputs[3] = memo; + + public_inputs.set_commitments(contract.private_state_factory.commitments); + public_inputs.set_nullifiers(contract.private_state_factory.nullifiers); + + public_inputs.pay_fee_from_l1 = to_ct(composer, true); + CT::fr(*public_inputs.pay_fee_from_l1) + .assert_equal(1); /// TODO: Ugly way of hard-coding a witness. Is there a nicer way? + + public_inputs.set_public(composer); + + info("public inputs: ", public_inputs); +}; + +} // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw_failure_callback.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw_failure_callback.hpp new file mode 100644 index 00000000000..bfdc6ab42f6 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw_failure_callback.hpp @@ -0,0 +1,13 @@ +#pragma once +#include "init.hpp" + +namespace aztec3::circuits::apps::test_apps::escrow { + +void withdraw_failure_callback(Composer& composer, + OracleWrapper& oracle, + NT::fr const& _asset_id, + NT::fr const& _amount, + NT::address const& _owner_address, + NT::fr const& _memo); + +} // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/type_check.hpp b/circuits/src/aztec3/circuits/apps/type_check.hpp new file mode 100644 index 00000000000..237ea6b0863 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/type_check.hpp @@ -0,0 +1,13 @@ +#pragma once + +namespace aztec3::circuits::apps { + +template struct isMap { + static constexpr bool value = false; +}; + +template struct isMap> { + static constexpr bool value = true; +}; + +} // namespace aztec3::circuits::apps \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/kernel/CMakeLists.txt b/circuits/src/aztec3/circuits/kernel/CMakeLists.txt new file mode 100644 index 00000000000..9cd9a82562d --- /dev/null +++ b/circuits/src/aztec3/circuits/kernel/CMakeLists.txt @@ -0,0 +1,9 @@ +barretenberg_module( + aztec3_circuits_kernel + # Question: why can't I link to these barretenberg modules? + # aztec3_circuits_abis + # stdlib_recursion + stdlib_primitives + stdlib_pedersen + stdlib_blake3s +) \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/kernel/index.hpp b/circuits/src/aztec3/circuits/kernel/index.hpp new file mode 100644 index 00000000000..40b875dd640 --- /dev/null +++ b/circuits/src/aztec3/circuits/kernel/index.hpp @@ -0,0 +1,2 @@ +#include "play_app_circuit.hpp" +#include "play_kernel_circuit.hpp" \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/kernel/play.test.cpp b/circuits/src/aztec3/circuits/kernel/play.test.cpp new file mode 100644 index 00000000000..4109fcef0ee --- /dev/null +++ b/circuits/src/aztec3/circuits/kernel/play.test.cpp @@ -0,0 +1,97 @@ +#include "index.hpp" +#include +// #include +#include + +namespace aztec3::circuits::kernel { + +using namespace plonk::stdlib::types::turbo; +using plonk::stdlib::recursion::recursion_output; + +// namespace { +// std::shared_ptr srs; +// private_kernel::circuit_data private_kernel_cd; +// private_circuit::circuit_data private_circuit_cd; +// } // namespace + +class play_tests : public ::testing::Test { + // protected: + // static void SetUpTestCase() + // { + // std::string CRS_PATH = "../srs_db/ignition"; + // srs = std::make_shared(CRS_PATH); + // private_circuit_cd = join_split::get_circuit_data(srs); + // private_kernel_cd = claim::get_circuit_data(srs); + // } +}; + +TEST(play_tests, test_play_app_circuit) +{ + Composer composer; + play_app_circuit(composer, 1, 2); +} + +TEST(play_tests, test_play_app_proof_gen) +{ + Composer app_composer; + play_app_circuit(app_composer, 1, 2); + + if (app_composer.failed) { + info("Play app circuit logic failed: ", app_composer.err); + } + + UnrolledProver app_prover = app_composer.create_unrolled_prover(); + waffle::plonk_proof app_proof = app_prover.construct_proof(); + info("app_proof: ", app_proof.proof_data); +} + +TEST(play_tests, test_play_kernel_proof_gen) +{ + Composer app_composer; + play_app_circuit(app_composer, 1, 2); + + if (app_composer.failed) { + info("Play app circuit logic failed: ", app_composer.err); + } + + UnrolledProver app_prover = app_composer.create_unrolled_prover(); + waffle::plonk_proof app_proof = app_prover.construct_proof(); + info("app_proof: ", app_proof.proof_data); + + std::shared_ptr app_vk = app_composer.compute_verification_key(); + + Composer kernel_composer; + recursion_output recursion_output = play_kernel_circuit(kernel_composer, app_vk, app_proof); + + if (kernel_composer.failed) { + info("Play kernel circuit logic failed: ", kernel_composer.err); + } +} + +// TEST(play_tests, test_play_kernel_2_proof_gen) +// { +// Composer app_composer; +// play_app_circuit(app_composer, 1, 2); + +// if (app_composer.failed) { +// info("Play app circuit logic failed: ", app_composer.err); +// } + +// UnrolledProver app_prover = app_composer.create_unrolled_prover(); +// waffle::plonk_proof app_proof = app_prover.construct_proof(); +// info("app_proof: ", app_proof.proof_data); + +// std::shared_ptr app_vk = app_composer.compute_verification_key(); + +// Composer mock_kernel_composer = Composer() + +// Composer kernel_composer; +// recursion_output recursion_output = play_kernel_circuit_2( +// kernel_composer, app_vk, app_proof); // test whether the defaults are acceptable. + +// if (kernel_composer.failed) { +// info("Play kernel circuit logic failed: ", kernel_composer.err); +// } +// } + +} // namespace aztec3::circuits::kernel \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/kernel/play_app_circuit.hpp b/circuits/src/aztec3/circuits/kernel/play_app_circuit.hpp new file mode 100644 index 00000000000..3e9c5c07d80 --- /dev/null +++ b/circuits/src/aztec3/circuits/kernel/play_app_circuit.hpp @@ -0,0 +1,20 @@ +#include + +namespace aztec3::circuits::kernel { + +using namespace plonk::stdlib::types::turbo; +// using plonk::stdlib::recursion::recursion_output; + +void play_app_circuit(Composer& composer, barretenberg::fr const& a_in, barretenberg::fr const& b_in) +{ + + field_ct a = witness_ct(&composer, a_in); + field_ct b = witness_ct(&composer, b_in); + field_ct c = a * b; + field_ct d = a + b + c; + + a.set_public(); + d.set_public(); +}; + +} // namespace aztec3::circuits::kernel \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/kernel/play_kernel_circuit.hpp b/circuits/src/aztec3/circuits/kernel/play_kernel_circuit.hpp new file mode 100644 index 00000000000..2679ac85d68 --- /dev/null +++ b/circuits/src/aztec3/circuits/kernel/play_kernel_circuit.hpp @@ -0,0 +1,99 @@ +#include +#include +#include +#include + +namespace aztec3::circuits::kernel { + +using namespace plonk::stdlib::types::turbo; +using plonk::stdlib::recursion::recursion_output; +using plonk::stdlib::recursion::recursive_turbo_verifier_settings; +using plonk::stdlib::recursion::verification_key; +using plonk::stdlib::recursion::verify_proof; +using transcript::Manifest; + +class TurboRecursion { + public: + using AggregationObject = recursion_output; + using Proof = waffle::plonk_proof; + using VK = std::shared_ptr; + static AggregationObject aggregate(Composer* composer, + const VK& vk, + const Proof& proof, + const AggregationObject recursion_output = AggregationObject()) + { + std::shared_ptr> recursive_vk = verification_key::from_witness(composer, vk); + const transcript::Manifest recursive_manifest = Composer::create_unrolled_manifest(vk->num_public_inputs); + + AggregationObject result = verify_proof>( + composer, recursive_vk, recursive_manifest, proof, recursion_output); + + return result; + } +}; + +template +typename Recursion::AggregationObject play_kernel_circuit(Composer& composer, + typename Recursion::VK const& app_vk, + typename Recursion::Proof const& app_proof) +{ + typename Recursion::AggregationObject recursion_output = Recursion::aggregate(&composer, app_vk, app_proof); + + recursion_output.add_proof_outputs_as_public_inputs(); + + return recursion_output; +}; + +// TODO: build an app first. +template +typename Recursion::AggregationObject play_kernel_circuit_2(Composer& composer, + typename Recursion::VK const& app_vk, + typename Recursion::Proof const& app_proof, + typename Recursion::VK const& prev_kernel_vk, + typename Recursion::Proof const& prev_kernel_proof) +{ + typename Recursion::AggregationObject recursion_output = + Recursion::aggregate(&composer, prev_kernel_vk, prev_kernel_proof); + + recursion_output = Recursion::aggregate(&composer, app_vk, app_proof, recursion_output); + + recursion_output.add_proof_outputs_as_public_inputs(); + + return recursion_output; +}; + +// circuit_data get_circuit_data(std::shared_ptr const& srs, bool mock) +// { +// std::cerr << "Getting join-split circuit data..." << std::endl; + +// auto build_circuit = [&](Composer& composer) { +// join_split_tx tx(noop_tx()); +// join_split_circuit(composer, tx); +// }; + +// return proofs::get_circuit_data( +// "join split", "", srs, "", true, false, false, true, true, true, mock, build_circuit); +// } + +// recursion_output play_kernel_circuit(Composer& composer, +// std::shared_ptr const& app_vk, +// waffle::plonk_proof const& app_proof) +// { +// const transcript::Manifest recursive_manifest = Composer::create_unrolled_manifest(app_vk->num_public_inputs); + +// std::shared_ptr> recursive_vk = verification_key::from_witness(&composer, app_vk); + +// recursion_output recursion_output = verify_proof>( +// &composer, recursive_vk, recursive_manifest, app_proof); + +// // recursion_output recursion_output; + +// // recursion_output = verify_proof>( +// // &composer, recursive_vk, recursive_manifest, app_proof, recursion_output); + +// recursion_output.add_proof_outputs_as_public_inputs(); + +// return recursion_output; +// }; + +} // namespace aztec3::circuits::kernel \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/kernel/private_kernel.hpp b/circuits/src/aztec3/circuits/kernel/private_kernel.hpp new file mode 100644 index 00000000000..d5ffa020819 --- /dev/null +++ b/circuits/src/aztec3/circuits/kernel/private_kernel.hpp @@ -0,0 +1,28 @@ +// #include +// #include +// #include + +// namespace aztec3::circuits::kernel::private_kernel { + +// using namespace plonk::stdlib::types::turbo; +// using aztec3::circuits::abis::PrivateCircuitPublicInputs; +// using plonk::stdlib::recursion::recursion_output; + +// // typedef PrivateKernelProof; +// // typedef PrivateKernelPublicInputs; +// // typedef std::pair PrivateKernelProofDatum; +// // typedef PrivateKernelVK; + +// // typedef PrivateCircuitProof; +// // typedef PrivateCircuitPublicInputs; +// // typedef std::pair PrivateCircuitProofDatum; +// // typedef PrivateCircuitVK; + +// recursion_output private_kernel_circuit(Composer& composer, +// PrivateKernelProofDatum const& private_kernel_proof_datum, +// PrivateKernelVK const& private_kernel_vk, +// PrivateCircuitProofDatum const& private_circuit_proof_datum, +// PrivateCircuitVK const& private_circuit_vk) +// {} + +// } // namespace aztec3::circuits::kernel::private_kernel \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/types/address.hpp b/circuits/src/aztec3/circuits/types/address.hpp new file mode 100644 index 00000000000..0c9d97be4af --- /dev/null +++ b/circuits/src/aztec3/circuits/types/address.hpp @@ -0,0 +1,140 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include "../../constants.hpp" + +namespace aztec3::circuits::types { + +using barretenberg::fr; +using plonk::stdlib::bool_t; +using plonk::stdlib::field_t; +using plonk::stdlib::group; +using plonk::stdlib::pedersen; +using plonk::stdlib::point; +using plonk::stdlib::witness_t; + +// Native type +class address { + public: + fr address_; + + address() noexcept { address_ = fr(); } + + address(address const& other) + : address_(other.address_){}; + + address(fr const& address) + : address_(address){}; + + address(int const& address) + : address_(fr(address)){}; + + operator fr() { return address_; } + + operator fr() const { return address_; } + + constexpr bool operator==(address const& other) const { return this->address_ == other.address_; } + + friend std::ostream& operator<<(std::ostream& os, address const& v) { return os << v.address_; } + + fr to_field() const { return address_; } +}; + +template void read(B& it, address& addr) +{ + using serialize::read; + fr address_field; + read(it, address_field); + addr = address_field; +} + +template void write(B& buf, address const& addr) +{ + using serialize::write; + write(buf, addr.address_); +} + +// Circuit type +template class address_t { + public: + field_t address_; + Composer* context_; + + address_t() = default; + + address_t(address_t const& other) + : address_(other.address_) + , context_(other.context_){}; + + address_t(field_t const& address) + : address_(address) + , context_(address.context){}; + + address_t(int const& address) + : address_(address) + , context_(nullptr){}; + + address_t(witness_t const& witness) + { + address_ = field_t(witness); + context_ = witness.context; + } + + address_t& operator=(const address_t& other) + { + address_ = other.address_; + context_ = other.context_; + return *this; + } + + field_t to_field() const { return address_; } + + void assert_equal(const address_t& rhs, std::string const& msg = "address_t::assert_equal") const + { + address_.assert_equal(rhs.address_, msg); + }; + + void assert_is_in_set(const std::vector& set, + std::string const& msg = "address_t::assert_is_in_set") const + { + std::vector> field_set; + for (const auto& e : set) { + field_set.push_back(e.address_); + } + address_.assert_is_in_set(field_set, msg); + } + + static address_t conditional_assign(const bool_t& predicate, const address_t& lhs, const address_t& rhs) + { + return field_t::conditional_assign(predicate, lhs.address_, rhs.address_); + }; + + static address_t derive_from_private_key(field_t const& private_key) + { + // TODO: Dummy logic, for now. Proper derivation undecided. + point public_key = group::template fixed_base_scalar_mul_g1<254>(private_key); + return address_t(public_key.x); + } + + static address_t derive_contract_address(address_t const& deployer_address, + field_t const& salt, + field_t const& vk_root, + field_t const& constructor_hash) + { + std::vector> preimage{ + deployer_address.to_field(), + salt, + vk_root, + constructor_hash, + }; + return address_ct(pedersen::compress(preimage, true, GeneratorIndex::CONTRACT_ADDRESS)); + } + + friend std::ostream& operator<<(std::ostream& os, address_t const& v) { return os << v.address_; } +}; + +} // namespace aztec3::circuits::types \ No newline at end of file diff --git a/circuits/src/aztec3/constants.hpp b/circuits/src/aztec3/constants.hpp new file mode 100644 index 00000000000..01e543ab3d1 --- /dev/null +++ b/circuits/src/aztec3/constants.hpp @@ -0,0 +1,57 @@ +#pragma once +#include + +namespace aztec3 { + +constexpr size_t CUSTOM_PUBLIC_INPUTS_LENGTH = 8; +constexpr size_t CUSTOM_OUTPUTS_LENGTH = 4; +constexpr size_t EMITTED_PUBLIC_INPUTS_LENGTH = 4; +constexpr size_t EMITTED_OUTPUTS_LENGTH = 4; + +constexpr size_t OUTPUT_COMMITMENTS_LENGTH = 4; +constexpr size_t INPUT_NULLIFIERS_LENGTH = 4; + +constexpr size_t STATE_TRANSITIONS_LENGTH = 4; +constexpr size_t STATE_READS_LENGTH = 4; + +constexpr size_t PRIVATE_CALL_STACK_LENGTH = 4; +constexpr size_t PUBLIC_CALL_STACK_LENGTH = 4; +constexpr size_t CONTRACT_DEPLOYMENT_CALL_STACK_LENGTH = 2; +constexpr size_t PARTIAL_L1_CALL_STACK_LENGTH = 2; +constexpr size_t CALLBACK_STACK_LENGTH = PARTIAL_L1_CALL_STACK_LENGTH; + +// Enumerate the hash_indices which are used for pedersen hashing +// Start from 1 to avoid the default generators. +enum GeneratorIndex { + COMMITMENT, + COMMITMENT_PLACEHOLDER, // for omitting some elements of the commitment when partially committing. + OUTER_COMMITMENT, + NULLIFIER_HASHED_PRIVATE_KEY, + NULLIFIER, + OUTER_NULLIFIER, + CONTRACT_ADDRESS, + FUNCTION_SIGNATURE, + CALL_ARGS, + L1_RESULT_PLACEHOLDER, + CALL_CONTEXT, + CALL_STACK_ITEM, + CALLBACK_STACK_ITEM, +}; + +// Enumerate the hash_sub_indices which are used for committing to private state note preimages. +// Start from 1. +enum PrivateStateNoteGeneratorIndex { + MAPPING_SLOT = 1, + MAPPING_SLOT_PLACEHOLDER, // for omitting some mapping key values when partially committing. + VALUE, + OWNER, + CREATOR, + SALT, + INPUT_NULLIFIER, + MEMO, + IS_REAL, +}; + +enum PrivateStateType { PARTITIONED = 1, WHOLE }; + +} // namespace aztec3 \ No newline at end of file diff --git a/circuits/src/aztec3/dbs/CMakeLists.txt b/circuits/src/aztec3/dbs/CMakeLists.txt new file mode 100644 index 00000000000..3138d0baa38 --- /dev/null +++ b/circuits/src/aztec3/dbs/CMakeLists.txt @@ -0,0 +1,36 @@ +if(NOT WASM) + include(FetchContent) + FetchContent_Declare( + leveldb + GIT_REPOSITORY https://github.com/google/leveldb.git + GIT_TAG 1.22 + ) + + FetchContent_GetProperties(leveldb) + if(NOT leveldb_POPULATED) + FetchContent_Populate(leveldb) + set(LEVELDB_BUILD_TESTS OFF CACHE BOOL "LevelDB tests off") + add_subdirectory(${leveldb_SOURCE_DIR} ${leveldb_BINARY_DIR} EXCLUDE_FROM_ALL) + endif() + + target_compile_options( + leveldb + PRIVATE + -Wno-sign-conversion + -Wno-unused-parameter + -Wno-shorten-64-to-32 + -Wno-implicit-int-conversion + -Wno-conversion + -Wno-implicit-fallthrough + ) + + link_libraries(leveldb) +endif() + +barretenberg_module( + aztec3_dbs + stdlib_merkle_tree # for the general db logic + stdlib_primitives + stdlib_pedersen + crypto_pedersen +) \ No newline at end of file diff --git a/circuits/src/aztec3/dbs/private_state_db.hpp b/circuits/src/aztec3/dbs/private_state_db.hpp new file mode 100644 index 00000000000..b01e364439a --- /dev/null +++ b/circuits/src/aztec3/dbs/private_state_db.hpp @@ -0,0 +1,150 @@ +// // TODO: move the leveldb_store to a more neutral module. +// #include +// #include +// #include +// #include "../constants.hpp" + +// namespace aztec3::db { + +// using aztec3::GeneratorIndex; +// using crypto::pedersen::compress_native; + +// char const* PRIVATE_STATE_DB_PATH = "./private_state_var.db"; + +// struct PrivateStateVar { +// bool is_partitioned = false; +// std::vector active_private_state_preimages; +// }; + +// // contract->storageSlots->[current->historic] + +// /** +// * Hmmm... There are multiple active leaves for partitioned states. +// * +// * [contract_Address, storage_slot] -> { +// * is_partitioned, +// * earliest_active_commitment, +// * earliest_commitment, +// * } +// * +// * commitment -> { +// * PrivateStateVar, +// * next_active_commitment, +// * next_commitment, +// * } +// */ + +// template class PrivateStateDb { +// public: +// PrivateStateDb(Store& store, size_t max_state_var_id) +// : store_(store) +// , max_state_var_id_(max_state_var_id) +// {} + +// // we need a linked list through all active commitments, and another linked list through all (active & inactive) +// // commitments. + +// PrivateStateCommitment get_earliest_active_commitment(fr const& contract_address, fr const& state_var_id) +// { +// const fr& storage_slot = state_var_id; +// const fr db_key = +// commit_native(std::vector{ contract_address, storage_slot }, GeneratorIndex::UNIVERSAL_STORAGE_SLOT); +// } + +// PrivateStateCommitment get_earliest_active_commitment(fr const& contract_address, +// fr const& state_var_id, +// fr const& mapping_key) +// { +// const fr storage_slot = +// commit_native(std::vector{ state_var_id, mapping_key }, GeneratorIndex::MAPPING_STORAGE_SLOT); +// const fr db_key = +// commit_native(std::vector{ contract_address, storage_slot }, GeneratorIndex::UNIVERSAL_STORAGE_SLOT); + +// std::vector data; + +// bool success = store_.get(db_key, data); + +// return data; +// } + +// fr get_current_private_state_value(fr const& contract_address, fr const& state_var_id) +// { +// PrivateStateCommitment earliest_active_commitment = +// get_earliest_active_commitment(contract_address, state_var_id); +// } + +// fr get_current_private_state_value(fr const& contract_address, fr const& state_var_id, fr const& mapping_key) {} + +// void write_metadata(std::ostream& os) +// { +// write(os, data_tree_.root()); +// write(os, nullifier_tree_.root()); +// write(os, root_tree_.root()); +// write(os, defi_tree_.root()); +// write(os, data_tree_.size()); +// write(os, nullifier_tree_.size()); +// write(os, root_tree_.size()); +// write(os, defi_tree_.size()); +// } + +// void get(std::istream& is, std::ostream& os) +// { +// GetRequest get_request; +// read(is, get_request); +// // std::cerr << get_request << std::endl; +// auto tree = trees_[get_request.tree_id]; +// auto path = tree->get_hash_path(get_request.index); +// auto leaf = get_request.index & 0x1 ? path[0].second : path[0].first; +// write(os, leaf == fr::neg_one() ? fr(0) : leaf); +// } + +// void get_path(std::istream& is, std::ostream& os) +// { +// GetRequest get_request; +// read(is, get_request); +// // std::cerr << get_request << std::endl; +// auto tree = trees_[get_request.tree_id]; +// auto path = tree->get_hash_path(get_request.index); +// write(os, path); +// } + +// void put(std::istream& is, std::ostream& os) +// { +// PutRequest put_request; +// read(is, put_request); +// // std::cerr << put_request << std::endl; +// PutResponse put_response; +// put_response.root = trees_[put_request.tree_id]->update_element(put_request.index, put_request.value); +// write(os, put_response); +// } + +// void batch_put(std::istream& is, std::ostream& os) +// { +// std::vector put_requests; +// read(is, put_requests); +// for (auto& put_request : put_requests) { +// trees_[put_request.tree_id]->update_element(put_request.index, put_request.value); +// } +// write_metadata(os); +// } + +// void commit(std::ostream& os) +// { +// // std::cerr << "COMMIT" << std::endl; +// store_.commit(); +// write_metadata(os); +// } + +// void rollback(std::ostream& os) +// { +// // std::cerr << "ROLLBACK" << std::endl; +// store_.rollback(); +// write_metadata(os); +// } + +// private: +// Store& store_; +// size_t max_state_var_id_; +// }; + +// } // namespace aztec3::db \ No newline at end of file diff --git a/circuits/src/aztec3/oracle/CMakeLists.txt b/circuits/src/aztec3/oracle/CMakeLists.txt new file mode 100644 index 00000000000..9619b0f5475 --- /dev/null +++ b/circuits/src/aztec3/oracle/CMakeLists.txt @@ -0,0 +1,8 @@ +barretenberg_module( + aztec3_oracle + aztec3_circuits_apps + crypto_pedersen + stdlib_primitives + stdlib_pedersen + stdlib_blake2s +) \ No newline at end of file diff --git a/circuits/src/aztec3/oracle/README.md b/circuits/src/aztec3/oracle/README.md new file mode 100644 index 00000000000..3dbcc37e0fc --- /dev/null +++ b/circuits/src/aztec3/oracle/README.md @@ -0,0 +1,13 @@ +# aztec3::circuits::oracle + +When Aztec3 makes a call to a circuit executor (such as Noir or the test apps in aztec3/circuits/apps/test_apps), we don't pass _all_ public inputs when calling the circuit; only the `custom_public_inputs` inputs are sent initially. + +Why? + +This has two main benefits: + +- We only need one implementation of the circuit's logic: the circuit itself. We don't need to implement a separate native version of the circuit to 'predict' what commitments/nullifiers and other values will need to ultimately become inputs to the circuit. +- There are occasions where it's difficult to predict the inputs required in advance. E.g. if a circuit_1 makes a call to another circuit, circuit_2, at some other contract_address, but that address is calculated within the body of circuit_1. We'd need to independently deduce the address which would be called so that we could grab the correct contract_address, VK, vkIndex, proving key (etc) from the DB. + +Instead, we provide an oracle to the circuit executor when we call it. As the circuit is executed, it'll occasionally reach points where it needs more input data. The circuit executor can query the oracle (the Aztec3 node) for more data. The oracle can grab data from its DB and return it the circuit executor. The circuit executor can then convert the data into witnesses and continue with some more of the circuit's execution. + diff --git a/circuits/src/aztec3/oracle/oracle.hpp b/circuits/src/aztec3/oracle/oracle.hpp new file mode 100644 index 00000000000..15f72659f12 --- /dev/null +++ b/circuits/src/aztec3/oracle/oracle.hpp @@ -0,0 +1,140 @@ +#pragma once +#include +#include +#include + +namespace aztec3::oracle { + +using NT = plonk::stdlib::types::NativeTypes; +using aztec3::circuits::abis::CallContext; +using aztec3::circuits::apps::PrivateStateNotePreimage; +using plonk::stdlib::types::CircuitTypes; + +/// Note: the server will always serve NATIVE types to the circuit, since eventually we'll be passing data to Noir (so +/// won't be handling circuit types at all from the Aztec3 end). +template class NativeOracleInterface { + public: + DB& db; + + NativeOracleInterface(DB& db, NT::fr const& contract_address, NT::address const& msg_sender) + : db(db) + , call_context({ + .msg_sender = msg_sender, + .storage_contract_address = contract_address, + }){}; + + NativeOracleInterface(DB& db, + NT::fr const& contract_address, + NT::address const& msg_sender, + std::optional msg_sender_private_key) + : db(db) + , call_context({ + .msg_sender = msg_sender, + .storage_contract_address = contract_address, + }) + , msg_sender_private_key(msg_sender_private_key){}; + + NT::fr get_msg_sender_private_key() + { + if (!msg_sender_private_key) { + throw_or_abort("no private key stored in memory"); + } + if (msg_sender_private_key_already_got) { + throw_or_abort(already_got_error); + } + msg_sender_private_key_already_got = true; + return *msg_sender_private_key; + }; + + CallContext get_call_context() + { + if (call_context_already_got) { + throw_or_abort(already_got_error); + } + call_context_already_got = true; + return call_context; + }; + + std::pair, PrivateStateNotePreimage> + get_private_state_note_preimages_for_subtraction(NT::fr const& storage_slot, + NT::address const& owner, + NT::fr const& subtrahend) + { + const auto& contract_address = call_context.storage_contract_address; + return db.get_private_state_note_preimages_for_subtraction(contract_address, storage_slot, owner, subtrahend); + } + + NT::fr generate_salt() const { return NT::fr::random_element(); } + + NT::fr generate_random_element() const { return NT::fr::random_element(); } + + private: + // We MUST make these values private, so the circuit isn't able to `get` these values more than once (the getter + // functions can check this). This will help us write secure circuits. If we were to query the same thing twice, an + // untrustworthy oracle could give two different pieces of information. As long as this (trusted) oracle catches + // double-queries, we can ensure the circuit we build doesn't query twice. + + // A circuit doesn't know its own address, so we need to track the address from 'outside'. + CallContext call_context; + std::optional msg_sender_private_key; + + // Ensure functions called only once: + bool call_context_already_got = false; + bool msg_sender_private_key_already_got = false; + std::string already_got_error = "Your circuit has already accessed this value. Don't ask the oracle twice, since " + "it shouldn't be trusted, and could lead to circuit bugs"; +}; + +// A temporary stub, whilst building other things first. +class FakeDB { + public: + FakeDB(){}; + + std::pair, PrivateStateNotePreimage> + get_private_state_note_preimages_for_subtraction(NT::address const& contract_address, + NT::fr const& storage_slot, + NT::address const& owner, + NT::fr const& subtrahend) + { + if (contract_address.address_ != 0) { + // do nothing - just making these variables in-use + } + + NT::grumpkin_point slot_point; + NT::fr x = storage_slot; + NT::fr yy = x.sqr() * x + NT::grumpkin_group::curve_b; + NT::fr y = yy.sqrt(); + NT::fr neg_y = -y; + y = y < neg_y ? y : neg_y; + slot_point = NT::grumpkin_group::affine_element(x, y); + info("derived slot point:", slot_point); + + return std::make_pair( + PrivateStateNotePreimage{ + .start_slot = 0, + .slot_point = slot_point, + .value = uint256_t(subtrahend) / 2 + 1, + .owner_address = owner, + .creator_address = 0, + .salt = 1234, + .input_nullifier = 2345, + .memo = 3456, + .is_real = true, + }, + PrivateStateNotePreimage{ + .start_slot = 0, + .slot_point = slot_point, + .value = uint256_t(subtrahend) / 2 + 3, + .owner_address = owner, + .creator_address = 0, + .salt = 4567, + .input_nullifier = 5678, + .memo = 6789, + .is_real = true, + }); + }; +}; + +typedef NativeOracleInterface NativeOracle; + +} // namespace aztec3::oracle \ No newline at end of file From 9766e83e8b9face375264b6017687d28b76a4124 Mon Sep 17 00:00:00 2001 From: iAmMichaelConnor Date: Wed, 1 Jun 2022 21:12:16 +0000 Subject: [PATCH 004/166] private kernel circuit abi, recursion, basic test --- .../kernel-circuits/private-kernel.md | 6 +- circuits/src/aztec3/circuits/CMakeLists.txt | 4 +- .../src/aztec3/circuits/abis/call_context.hpp | 17 +- .../aztec3/circuits/abis/call_stack_item.hpp | 8 +- .../circuits/abis/callback_stack_item.hpp | 15 ++ ...contract_deployment_call_public_inputs.hpp | 4 +- .../circuits/abis/executed_callback.hpp | 17 +- .../circuits/abis/function_signature.hpp | 11 + .../abis/optionally_revealed_data.hpp | 62 ++++++ .../abis/private_circuit_public_inputs.hpp | 124 +++++++++-- .../abis/private_kernel/accumulated_data.hpp | 95 ++++++++ .../abis/private_kernel/constant_data.hpp | 57 +++++ .../circuits/abis/private_kernel/globals.hpp | 39 ++++ .../abis/private_kernel/old_tree_roots.hpp | 50 +++++ .../private_kernel/previous_kernel_data.hpp | 50 +++++ .../abis/private_kernel/private_call_data.hpp | 55 +++++ .../abis/private_kernel/private_inputs.hpp | 40 ++++ .../abis/private_kernel/public_inputs.hpp | 54 +++++ .../abis/public_circuit_public_inputs.hpp | 4 +- .../aztec3/circuits/apps/contract_factory.hpp | 2 +- .../circuits/apps/private_state_factory.hpp | 12 +- .../apps/test_apps/escrow/deposit.cpp | 7 +- .../apps/test_apps/escrow/deposit.hpp | 5 +- .../circuits/apps/test_apps/escrow/events.hpp | 19 -- .../circuits/apps/test_apps/escrow/index.hpp | 6 +- .../apps/test_apps/escrow/l1_interface.hpp | 10 - .../circuits/apps/test_apps/escrow/states.hpp | 17 -- .../src/aztec3/circuits/kernel/CMakeLists.txt | 1 + circuits/src/aztec3/circuits/kernel/index.hpp | 2 - .../src/aztec3/circuits/kernel/play.test.cpp | 97 --------- .../circuits/kernel/play_kernel_circuit.hpp | 99 --------- .../aztec3/circuits/kernel/private/index.hpp | 2 + .../aztec3/circuits/kernel/private/init.hpp | 31 +++ .../kernel/private/private_kernel.test.cpp | 206 ++++++++++++++++++ .../kernel/private/private_kernel_circuit.cpp | 71 ++++++ .../kernel/private/private_kernel_circuit.hpp | 14 ++ .../aztec3/circuits/kernel/private_kernel.hpp | 28 --- .../src/aztec3/circuits/mock/mock_circuit.hpp | 19 ++ .../aztec3/circuits/mock/mock_circuit_2.hpp | 35 +++ .../aztec3/circuits/recursion/CMakeLists.txt | 9 + .../aztec3/circuits/recursion/aggregator.hpp | 61 ++++++ .../src/aztec3/circuits/recursion/index.hpp | 3 + .../aztec3/circuits/recursion/play.test.cpp | 137 ++++++++++++ .../play_app_circuit.hpp | 4 +- .../recursion/play_recursive_circuit.hpp | 57 +++++ .../src/aztec3/circuits/rollup/CMakeLists.txt | 9 + circuits/src/aztec3/constants.hpp | 14 ++ circuits/src/aztec3/oracle/oracle.hpp | 22 +- 48 files changed, 1385 insertions(+), 326 deletions(-) create mode 100644 circuits/src/aztec3/circuits/abis/optionally_revealed_data.hpp create mode 100644 circuits/src/aztec3/circuits/abis/private_kernel/accumulated_data.hpp create mode 100644 circuits/src/aztec3/circuits/abis/private_kernel/constant_data.hpp create mode 100644 circuits/src/aztec3/circuits/abis/private_kernel/globals.hpp create mode 100644 circuits/src/aztec3/circuits/abis/private_kernel/old_tree_roots.hpp create mode 100644 circuits/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp create mode 100644 circuits/src/aztec3/circuits/abis/private_kernel/private_call_data.hpp create mode 100644 circuits/src/aztec3/circuits/abis/private_kernel/private_inputs.hpp create mode 100644 circuits/src/aztec3/circuits/abis/private_kernel/public_inputs.hpp delete mode 100644 circuits/src/aztec3/circuits/apps/test_apps/escrow/events.hpp delete mode 100644 circuits/src/aztec3/circuits/apps/test_apps/escrow/l1_interface.hpp delete mode 100644 circuits/src/aztec3/circuits/apps/test_apps/escrow/states.hpp delete mode 100644 circuits/src/aztec3/circuits/kernel/index.hpp delete mode 100644 circuits/src/aztec3/circuits/kernel/play.test.cpp delete mode 100644 circuits/src/aztec3/circuits/kernel/play_kernel_circuit.hpp create mode 100644 circuits/src/aztec3/circuits/kernel/private/index.hpp create mode 100644 circuits/src/aztec3/circuits/kernel/private/init.hpp create mode 100644 circuits/src/aztec3/circuits/kernel/private/private_kernel.test.cpp create mode 100644 circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp create mode 100644 circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.hpp delete mode 100644 circuits/src/aztec3/circuits/kernel/private_kernel.hpp create mode 100644 circuits/src/aztec3/circuits/mock/mock_circuit.hpp create mode 100644 circuits/src/aztec3/circuits/mock/mock_circuit_2.hpp create mode 100644 circuits/src/aztec3/circuits/recursion/CMakeLists.txt create mode 100644 circuits/src/aztec3/circuits/recursion/aggregator.hpp create mode 100644 circuits/src/aztec3/circuits/recursion/index.hpp create mode 100644 circuits/src/aztec3/circuits/recursion/play.test.cpp rename circuits/src/aztec3/circuits/{kernel => recursion}/play_app_circuit.hpp (83%) create mode 100644 circuits/src/aztec3/circuits/recursion/play_recursive_circuit.hpp create mode 100644 circuits/src/aztec3/circuits/rollup/CMakeLists.txt diff --git a/circuits/specs/src/architecture/kernel-circuits/private-kernel.md b/circuits/specs/src/architecture/kernel-circuits/private-kernel.md index 7a7d3cb2eba..c9a29302a21 100644 --- a/circuits/specs/src/architecture/kernel-circuits/private-kernel.md +++ b/circuits/specs/src/architecture/kernel-circuits/private-kernel.md @@ -103,16 +103,16 @@ TODO: less nesting! (Or, in practice, we'll modularise this all into neat functi Base case: * if `start.privateCallCount == 0`: - * Require previous kernel data to be empty. + * Require previous kernel data to be empty. Can't do this - the `verify_proof()` function needs a valid dummy proof and vk to verify. * Validate that `start.privateCallStack.length == 1 && start.publicCallStack.length == 0 && start.contractDeploymentCallStack.length == 0 && start.l1CallStack.length == 0` - TBD: to allow the option of a fee payment, we might require `start.privateCallStack.length` to be "1" or "2, where one tx has an `isFeePayment` indicator". We could even allow any number of initial private calls on the stack, but that's a pretty big deviation from the ethereum tx model. - * Pop the only (TBD) `privateCallStackItemHash` off the `start.privateCallStack`. + * Pop the only (TBD) `privateCallHash` off the `start.privateCallStack`. - If `privateCall.functionSignature.isConstructor == true`: - then we don't need a signature from the user, since this entire 'callstack' has been instantiated by a Contract Deployment kernel snark (which itself will have been signed by the user). - Set `constants.isConstructorRecursion := true` - This public input will percolate to, and be checked by. the Contract Deployment Kernel Circuit which calls this constructor. This check is required to prevent a person from circumventing the ECDSA signature check by simply setting `isConstructor = true` when making a private call. If this aggregated kernel snark reaches the rollup circuit without this flag being reset to `false` by the Contract Deployment Kernel Circuit (to say "yes, this kernel was indeed a constructor for a Contract Deployment Kernel Circuit"), then the entire tx will be rejected by the rollup circuit. - Else: - Set `constants.isConstructorRecursion := false` - - Verify the ECDSA `signature`, with `message := privateCallStackItemHash` and `signer := privateCall.callContext.msgSender`. + - Verify the ECDSA `signature`, with `message := privateCallHash` and `signer := privateCall.callContext.msgSender`. - Validate the `callContext`. Usually the correctness of a callContext is checked between the `privateCall` and all the new calls it makes (see later in this logic). That means for this 'Base case', those checks haven't been done for this `privateCall` (since there was no prior iteration of this kernel circuit to make those checks). - If `privateCall.isDelegateCall == true || privateCall.isStaticCall == true`: - Revert - a user cannot make a delegateCall or staticCall. diff --git a/circuits/src/aztec3/circuits/CMakeLists.txt b/circuits/src/aztec3/circuits/CMakeLists.txt index feb12203cad..ae3cfdda297 100644 --- a/circuits/src/aztec3/circuits/CMakeLists.txt +++ b/circuits/src/aztec3/circuits/CMakeLists.txt @@ -1,3 +1,5 @@ add_subdirectory(apps) add_subdirectory(abis) -add_subdirectory(kernel) \ No newline at end of file +add_subdirectory(kernel) +add_subdirectory(rollup) +add_subdirectory(recursion) \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/abis/call_context.hpp b/circuits/src/aztec3/circuits/abis/call_context.hpp index 6d17551c2f7..11ddbbe9c9c 100644 --- a/circuits/src/aztec3/circuits/abis/call_context.hpp +++ b/circuits/src/aztec3/circuits/abis/call_context.hpp @@ -39,6 +39,19 @@ template struct CallContext { return call_context; }; + template CallContext to_native_type() const + { + static_assert(std::is_same, NCT>::value); + auto to_nt = [&](auto& e) { return plonk::stdlib::types::to_nt(e); }; + + CallContext call_context = { + to_nt(msg_sender), + to_nt(storage_contract_address), + }; + + return call_context; + }; + fr hash() { std::vector inputs = { @@ -57,9 +70,9 @@ template struct CallContext { storage_contract_address.to_field().assert_is_zero(); } - template void set_public() + void set_public() { - static_assert((std::is_same, NCT>::value)); + static_assert(!(std::is_same::value)); msg_sender.to_field().set_public(); storage_contract_address.to_field().set_public(); diff --git a/circuits/src/aztec3/circuits/abis/call_stack_item.hpp b/circuits/src/aztec3/circuits/abis/call_stack_item.hpp index 7ddb04018c2..468b2cddf86 100644 --- a/circuits/src/aztec3/circuits/abis/call_stack_item.hpp +++ b/circuits/src/aztec3/circuits/abis/call_stack_item.hpp @@ -1,8 +1,8 @@ #pragma once -#include "./function_signature.hpp" -#include "./call_context.hpp" -#include "./private_circuit_public_inputs.hpp" -#include "./public_circuit_public_inputs.hpp" +#include "function_signature.hpp" +#include "call_context.hpp" +#include "private_circuit_public_inputs.hpp" +#include "public_circuit_public_inputs.hpp" #include #include #include diff --git a/circuits/src/aztec3/circuits/abis/callback_stack_item.hpp b/circuits/src/aztec3/circuits/abis/callback_stack_item.hpp index 158b28eee39..501166d5ff0 100644 --- a/circuits/src/aztec3/circuits/abis/callback_stack_item.hpp +++ b/circuits/src/aztec3/circuits/abis/callback_stack_item.hpp @@ -40,6 +40,21 @@ template struct CallbackStackItem { return callback_stack_item; }; + template CallbackStackItem to_native_type() const + { + static_assert(std::is_same, NCT>::value); + auto to_nt = [&](auto& e) { return plonk::stdlib::types::to_nt(e); }; + + CallbackStackItem callback_stack_item = { + to_nt(callback_public_key), + to_nt(success_callback_call_hash), + to_nt(failure_callback_call_hash), + to_nt(success_result_arg_map_acc), + }; + + return callback_stack_item; + }; + template void assert_is_zero() { static_assert((std::is_same, NCT>::value)); diff --git a/circuits/src/aztec3/circuits/abis/contract_deployment_call_public_inputs.hpp b/circuits/src/aztec3/circuits/abis/contract_deployment_call_public_inputs.hpp index bdaed6f5998..e34563ca316 100644 --- a/circuits/src/aztec3/circuits/abis/contract_deployment_call_public_inputs.hpp +++ b/circuits/src/aztec3/circuits/abis/contract_deployment_call_public_inputs.hpp @@ -6,8 +6,8 @@ #include #include #include "../../constants.hpp" -#include "./executed_callback.hpp" -#include "./callback_stack_item.hpp" +#include "executed_callback.hpp" +#include "callback_stack_item.hpp" namespace aztec3::circuits::abis { diff --git a/circuits/src/aztec3/circuits/abis/executed_callback.hpp b/circuits/src/aztec3/circuits/abis/executed_callback.hpp index 50f9e4730c9..e792bd5d68e 100644 --- a/circuits/src/aztec3/circuits/abis/executed_callback.hpp +++ b/circuits/src/aztec3/circuits/abis/executed_callback.hpp @@ -36,6 +36,19 @@ template struct ExecutedCallback { return executed_callback; }; + template ExecutedCallback to_native_type() const + { + static_assert(std::is_same, NCT>::value); + auto to_nt = [&](auto& e) { return plonk::stdlib::types::to_nt(e); }; + + ExecutedCallback executed_callback = { + to_nt(l1_result_hash), + to_nt(l1_results_tree_leaf_index), + }; + + return executed_callback; + }; + template void assert_is_zero() { static_assert((std::is_same, NCT>::value)); @@ -44,9 +57,9 @@ template struct ExecutedCallback { fr(l1_results_tree_leaf_index).assert_is_zero(); } - template void set_public() + void set_public() { - static_assert((std::is_same, NCT>::value)); + static_assert(!(std::is_same::value)); l1_result_hash.set_public(); fr(l1_results_tree_leaf_index).set_public(); diff --git a/circuits/src/aztec3/circuits/abis/function_signature.hpp b/circuits/src/aztec3/circuits/abis/function_signature.hpp index 50db89fe955..8a6ede4b2b2 100644 --- a/circuits/src/aztec3/circuits/abis/function_signature.hpp +++ b/circuits/src/aztec3/circuits/abis/function_signature.hpp @@ -45,6 +45,17 @@ template struct FunctionSignature { return function_signature; }; + void set_public() + { + static_assert(!(std::is_same::value)); + + contract_address.to_field().set_public(); + fr(vk_index).set_public(); + fr(is_private).set_public(); + fr(is_constructor).set_public(); + fr(is_callback).set_public(); + } + fr hash() { std::vector inputs = { diff --git a/circuits/src/aztec3/circuits/abis/optionally_revealed_data.hpp b/circuits/src/aztec3/circuits/abis/optionally_revealed_data.hpp new file mode 100644 index 00000000000..c77b703567c --- /dev/null +++ b/circuits/src/aztec3/circuits/abis/optionally_revealed_data.hpp @@ -0,0 +1,62 @@ +#pragma once +#include +#include +#include +#include +#include "function_signature.hpp" + +namespace aztec3::circuits::abis { + +using plonk::stdlib::witness_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; + +template struct OptionallyRevealedData { + typedef typename NCT::boolean boolean; + typedef typename NCT::fr fr; + + fr call_stack_item_hash; + FunctionSignature function_signature; + std::array emitted_public_inputs; + fr vk_hash; + fr portal_contract_address; // an ETH address + // BOOLS TOO! + + template + OptionallyRevealedData> to_circuit_type(Composer& composer) const + { + static_assert((std::is_same::value)); + + // Capture the composer: + auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + + OptionallyRevealedData> data = { + to_ct(call_stack_item_hash), function_signature.to_circuit_type(composer), + to_ct(emitted_public_inputs), to_ct(vk_hash), + to_ct(portal_contract_address), + }; + + return data; + }; + + void set_public() + { + static_assert(!(std::is_same::value)); + + call_stack_item_hash.set_public(); + function_signature.set_public(); + set_array_public(emitted_public_inputs); + vk_hash.set_public(); + portal_contract_address.set_public(); + } + + template void set_array_public(std::array& arr) + { + static_assert(!(std::is_same::value)); + for (T& e : arr) { + fr(e).set_public(); + } + } +}; + +} // namespace aztec3::circuits::abis \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp b/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp index 867614f5d3d..8294b645246 100644 --- a/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp +++ b/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp @@ -47,6 +47,48 @@ template class PrivateCircuitPublicInputs { opt_boolean pay_fee_from_public_l2; opt_boolean called_from_l1; + PrivateCircuitPublicInputs(){}; + + PrivateCircuitPublicInputs( + std::optional> const& call_context, + + std::array const& custom_public_inputs, + std::array const& emitted_public_inputs, + + std::optional> const& executed_callback, + + std::array const& output_commitments, + std::array const& input_nullifiers, + + std::array const& private_call_stack, + std::array const& public_call_stack, + std::array const& contract_deployment_call_stack, + std::array const& partial_l1_call_stack, + std::array>, CALLBACK_STACK_LENGTH> const& callback_stack, + + opt_fr const& old_private_data_tree_root, + + opt_boolean const& is_fee_payment, + opt_boolean const& pay_fee_from_l1, + opt_boolean const& pay_fee_from_public_l2, + opt_boolean const& called_from_l1) + : call_context(call_context) + , custom_public_inputs(custom_public_inputs) + , emitted_public_inputs(emitted_public_inputs) + , executed_callback(executed_callback) + , output_commitments(output_commitments) + , input_nullifiers(input_nullifiers) + , private_call_stack(private_call_stack) + , public_call_stack(public_call_stack) + , contract_deployment_call_stack(contract_deployment_call_stack) + , partial_l1_call_stack(partial_l1_call_stack) + , callback_stack(callback_stack) + , old_private_data_tree_root(old_private_data_tree_root) + , is_fee_payment(is_fee_payment) + , pay_fee_from_l1(pay_fee_from_l1) + , pay_fee_from_public_l2(pay_fee_from_public_l2) + , called_from_l1(called_from_l1){}; + bool operator==(PrivateCircuitPublicInputs const&) const = default; static PrivateCircuitPublicInputs create() @@ -127,18 +169,18 @@ template class PrivateCircuitPublicInputs { template void set_public(Composer& composer) { - static_assert((std::is_same, NCT>::value)); + static_assert(!(std::is_same::value)); make_unused_inputs_zero(composer); // Optional members are guaranteed to be nonempty from here. - (*call_context).template set_public(); + (*call_context).set_public(); set_array_public(custom_public_inputs); set_array_public(emitted_public_inputs); - (*executed_callback).template set_public(); + (*executed_callback).set_public(); set_array_public(output_commitments); set_array_public(input_nullifiers); @@ -157,6 +199,7 @@ template class PrivateCircuitPublicInputs { fr(*called_from_l1).set_public(); } + // TODO: can't use designated constructor anymore, so need to copy the to_native_type() function methodology below. template PrivateCircuitPublicInputs> to_circuit_type(Composer& composer) const { @@ -164,29 +207,70 @@ template class PrivateCircuitPublicInputs { // Capture the composer: auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; - auto to_circuit_type = [&](auto& e) { return e.to_circuit_type(composer); }; + auto to_circuit_type = [&](auto& e) { + return e ? std::make_optional((*e).to_circuit_type(composer)) : std::nullopt; + }; PrivateCircuitPublicInputs> pis = { - .call_context = to_circuit_type(call_context), + to_circuit_type(call_context), - .custom_public_inputs = to_ct(custom_public_inputs), - .emitted_public_inputs = to_ct(emitted_public_inputs), + to_ct(custom_public_inputs), + to_ct(emitted_public_inputs), - .executed_callback = to_circuit_type(executed_callback), + to_circuit_type(executed_callback), - .output_commitments = to_ct(output_commitments), - .input_nullifiers = to_ct(input_nullifiers), + to_ct(output_commitments), + to_ct(input_nullifiers), - .private_call_stack = to_ct(private_call_stack), - .public_call_stack = to_ct(public_call_stack), - .contract_deployment_call_stack = to_ct(contract_deployment_call_stack), - .partial_l1_call_stack = to_ct(partial_l1_call_stack), - .callback_stack = map(callback_stack, to_circuit_type), + to_ct(private_call_stack), + to_ct(public_call_stack), + to_ct(contract_deployment_call_stack), + to_ct(partial_l1_call_stack), + map(callback_stack, to_circuit_type), - .is_fee_payment = to_ct(is_fee_payment), - .pay_fee_from_l1 = to_ct(pay_fee_from_l1), - .pay_fee_from_public_l2 = to_ct(pay_fee_from_public_l2), - .called_from_l1 = to_ct(called_from_l1), + to_ct(old_private_data_tree_root), + + to_ct(is_fee_payment), + to_ct(pay_fee_from_l1), + to_ct(pay_fee_from_public_l2), + to_ct(called_from_l1), + }; + + return pis; + }; + + template PrivateCircuitPublicInputs to_native_type() const + { + static_assert(std::is_same, NCT>::value); + auto to_nt = [&](auto& e) { return plonk::stdlib::types::to_nt(e); }; + auto to_native_type = [](const std::optional& e) { + return e ? std::make_optional((*e).template to_native_type()) : std::nullopt; + }; + // auto to_native_type = [&](T& e) { return e.to_native_type(); }; + + PrivateCircuitPublicInputs pis = { + to_native_type(call_context), + + to_nt(custom_public_inputs), + to_nt(emitted_public_inputs), + + to_native_type(executed_callback), + + to_nt(output_commitments), + to_nt(input_nullifiers), + + to_nt(private_call_stack), + to_nt(public_call_stack), + to_nt(contract_deployment_call_stack), + to_nt(partial_l1_call_stack), + map(callback_stack, to_native_type), + + to_nt(old_private_data_tree_root), + + to_nt(is_fee_payment), + to_nt(pay_fee_from_l1), + to_nt(pay_fee_from_public_l2), + to_nt(called_from_l1), }; return pis; @@ -321,7 +405,7 @@ template class PrivateCircuitPublicInputs { (*e).template set_public(); } } -}; +}; // namespace aztec3::circuits::abis template void read(uint8_t const*& it, PrivateCircuitPublicInputs& private_circuit_public_inputs) { diff --git a/circuits/src/aztec3/circuits/abis/private_kernel/accumulated_data.hpp b/circuits/src/aztec3/circuits/abis/private_kernel/accumulated_data.hpp new file mode 100644 index 00000000000..020303a25c7 --- /dev/null +++ b/circuits/src/aztec3/circuits/abis/private_kernel/accumulated_data.hpp @@ -0,0 +1,95 @@ +#pragma once +#include +#include +#include +#include +#include +#include "../optionally_revealed_data.hpp" + +namespace aztec3::circuits::abis::private_kernel { + +using plonk::stdlib::witness_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; +using std::is_same; + +template struct AccumulatedData { + typedef typename NCT::fr fr; + typedef typename NCT::AggregationObject AggregationObject; + + AggregationObject aggregation_object; + fr private_call_count; + std::array private_call_stack; + std::array public_call_stack; + std::array contract_deployment_call_stack; + std::array l1_call_stack; + std::array callback_stack; + std::array, KERNEL_OPTIONALLY_REVEALED_DATA_LENGTH> optionally_revealed_data; + std::array output_commitments; + std::array input_nullifiers; + + template AccumulatedData> to_circuit_type(Composer& composer) const + { + typedef CircuitTypes CT; + static_assert((std::is_same::value)); + + // Capture the composer: + auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + auto to_circuit_type = [&](auto& e) { return e.to_circuit_type(composer); }; + + AccumulatedData acc_data = { + typename CT::AggregationObject{ + to_ct(aggregation_object.P0), + to_ct(aggregation_object.P1), + to_ct(aggregation_object.public_inputs), + aggregation_object.proof_witness_indices, + aggregation_object.has_data, + }, + to_ct(private_call_count), + to_ct(private_call_stack), + to_ct(public_call_stack), + to_ct(contract_deployment_call_stack), + to_ct(l1_call_stack), + to_ct(callback_stack), + map(optionally_revealed_data, to_circuit_type), + to_ct(output_commitments), + to_ct(input_nullifiers), + }; + + return acc_data; + }; + + void set_public() + { + static_assert(!(std::is_same::value)); + + aggregation_object.add_proof_outputs_as_public_inputs(); + private_call_count.set_public(); + set_array_public(private_call_stack); + set_array_public(public_call_stack); + set_array_public(contract_deployment_call_stack); + set_array_public(l1_call_stack); + set_array_public(callback_stack); + set_array_public(optionally_revealed_data); + set_array_public(output_commitments); + set_array_public(input_nullifiers); + } + + template void set_array_public(std::array& arr) + { + static_assert(!(std::is_same::value)); + for (T& e : arr) { + fr(e).set_public(); + } + } + + template void set_array_public(std::array, SIZE>& arr) + { + static_assert(!(std::is_same::value)); + for (auto& e : arr) { + e.set_public(); + } + } +}; + +} // namespace aztec3::circuits::abis::private_kernel \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/abis/private_kernel/constant_data.hpp b/circuits/src/aztec3/circuits/abis/private_kernel/constant_data.hpp new file mode 100644 index 00000000000..92714c0ea1e --- /dev/null +++ b/circuits/src/aztec3/circuits/abis/private_kernel/constant_data.hpp @@ -0,0 +1,57 @@ +#pragma once +#include +#include +#include +#include +#include "../executed_callback.hpp" +#include "old_tree_roots.hpp" +#include "globals.hpp" + +namespace aztec3::circuits::abis::private_kernel { + +using plonk::stdlib::witness_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; +using std::is_same; + +template struct ConstantData { + typedef typename NCT::fr fr; + typedef typename NCT::boolean boolean; + + OldTreeRoots old_tree_roots; + boolean is_constructor_recursion = false; + boolean is_callback_recursion = false; + ExecutedCallback executed_callback; + Globals globals; + + template ConstantData> to_circuit_type(Composer& composer) const + { + static_assert((std::is_same::value)); + + // Capture the composer: + auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + + ConstantData> constant_data = { + old_tree_roots.to_circuit_type(composer), + to_ct(is_constructor_recursion), + to_ct(is_callback_recursion), + executed_callback.to_circuit_type(composer), + globals.to_circuit_type(composer), + }; + + return constant_data; + }; + + void set_public() + { + static_assert(!(std::is_same::value)); + + old_tree_roots.set_public(); + fr(is_constructor_recursion).set_public(); + fr(is_callback_recursion).set_public(); + executed_callback.set_public(); + globals.set_public(); + } +}; + +} // namespace aztec3::circuits::abis::private_kernel \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/abis/private_kernel/globals.hpp b/circuits/src/aztec3/circuits/abis/private_kernel/globals.hpp new file mode 100644 index 00000000000..eb06ab4cb85 --- /dev/null +++ b/circuits/src/aztec3/circuits/abis/private_kernel/globals.hpp @@ -0,0 +1,39 @@ +#pragma once +#include +#include +#include +#include + +namespace aztec3::circuits::abis::private_kernel { + +using plonk::stdlib::witness_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; +using std::is_same; + +template struct Globals { + typedef typename NCT::fr fr; + + fr min_timestamp; + + template Globals> to_circuit_type(Composer& composer) const + { + static_assert((std::is_same::value)); + + // Capture the composer: + auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + + Globals> global_data = { to_ct(min_timestamp) }; + + return global_data; + }; + + void set_public() + { + static_assert(!(std::is_same::value)); + + min_timestamp.set_public(); + } +}; + +} // namespace aztec3::circuits::abis::private_kernel \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/abis/private_kernel/old_tree_roots.hpp b/circuits/src/aztec3/circuits/abis/private_kernel/old_tree_roots.hpp new file mode 100644 index 00000000000..a1eae426b31 --- /dev/null +++ b/circuits/src/aztec3/circuits/abis/private_kernel/old_tree_roots.hpp @@ -0,0 +1,50 @@ +#pragma once +#include +#include +#include +#include + +namespace aztec3::circuits::abis::private_kernel { + +using plonk::stdlib::witness_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; +using std::is_same; + +template struct OldTreeRoots { + typedef typename NCT::fr fr; + + fr private_data_tree_root; + fr contract_tree_root; + fr l1_results_tree_root; + fr private_kernel_vk_tree_root; // TODO: future enhancement + + template OldTreeRoots> to_circuit_type(Composer& composer) const + { + static_assert((std::is_same::value)); + + // Capture the composer: + auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + + OldTreeRoots> data = { + to_ct(private_data_tree_root), + to_ct(contract_tree_root), + to_ct(l1_results_tree_root), + to_ct(private_kernel_vk_tree_root), + }; + + return data; + }; + + void set_public() + { + static_assert(!(std::is_same::value)); + + private_data_tree_root.set_public(); + contract_tree_root.set_public(); + l1_results_tree_root.set_public(); + private_kernel_vk_tree_root.set_public(); + } +}; + +} // namespace aztec3::circuits::abis::private_kernel \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp b/circuits/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp new file mode 100644 index 00000000000..ace4f0fccbf --- /dev/null +++ b/circuits/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp @@ -0,0 +1,50 @@ +#pragma once +#include +#include +#include +#include +#include "public_inputs.hpp" + +namespace aztec3::circuits::abis::private_kernel { + +using plonk::stdlib::witness_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; +using std::is_same; + +template struct PreviousKernelData { + typedef typename NCT::address address; + typedef typename NCT::uint32 uint32; + typedef typename NCT::boolean boolean; + typedef typename NCT::grumpkin_point grumpkin_point; + typedef typename NCT::fr fr; + typedef typename NCT::VK VK; + + PublicInputs public_inputs; + NativeTypes::Proof proof; // TODO: how to express proof as native/circuit type when it gets used as a buffer? + std::shared_ptr vk; + fr vk_index; + std::array vk_path; + + // WARNING: the `proof` does NOT get converted! + template PreviousKernelData> to_circuit_type(Composer& composer) const + { + typedef CircuitTypes CT; + static_assert((std::is_same::value)); + + // Capture the composer: + auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + + PreviousKernelData> data = { + public_inputs.to_circuit_type(composer), + proof, // Notice: not converted! Stays as native. + CT::VK::from_witness(&composer, vk), + to_ct(vk_index), + to_ct(vk_path), + }; + + return data; + }; +}; // namespace aztec3::circuits::abis::private_kernel + +} // namespace aztec3::circuits::abis::private_kernel \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/abis/private_kernel/private_call_data.hpp b/circuits/src/aztec3/circuits/abis/private_kernel/private_call_data.hpp new file mode 100644 index 00000000000..f8489903d82 --- /dev/null +++ b/circuits/src/aztec3/circuits/abis/private_kernel/private_call_data.hpp @@ -0,0 +1,55 @@ +#pragma once +#include +#include +#include +#include +#include "../call_stack_item.hpp" + +namespace aztec3::circuits::abis::private_kernel { + +using plonk::stdlib::witness_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; +using std::is_same; + +template struct PrivateCallData { + typedef typename NCT::address address; + typedef typename NCT::uint32 uint32; + typedef typename NCT::boolean boolean; + typedef typename NCT::grumpkin_point grumpkin_point; + typedef typename NCT::fr fr; + typedef typename NCT::VK VK; + + CallStackItem call_stack_item; + NativeTypes::Proof proof; // TODO: how to express proof as native/circuit type when it gets used as a buffer? + std::shared_ptr vk; + std::array vk_path; + fr portal_contract_address; // an ETH address + fr contract_leaf_index; + std::array contract_path; + // PrivatelyExecutedCallback???? + + // WARNING: the `proof` does NOT get converted! + template PrivateCallData> to_circuit_type(Composer& composer) const + { + typedef CircuitTypes CT; + static_assert((std::is_same::value)); + + // Capture the composer: + auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + + PrivateCallData> data = { + call_stack_item.to_circuit_type(composer), + proof, // Notice: not converted! Stays as native. + CT::VK::from_witness(&composer, vk), + to_ct(vk_path), + to_ct(portal_contract_address), + to_ct(contract_leaf_index), + to_ct(contract_path), + }; + + return data; + }; +}; + +} // namespace aztec3::circuits::abis::private_kernel \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/abis/private_kernel/private_inputs.hpp b/circuits/src/aztec3/circuits/abis/private_kernel/private_inputs.hpp new file mode 100644 index 00000000000..501a7ca420d --- /dev/null +++ b/circuits/src/aztec3/circuits/abis/private_kernel/private_inputs.hpp @@ -0,0 +1,40 @@ +#pragma once +#include +#include +#include +#include +#include "accumulated_data.hpp" +#include "previous_kernel_data.hpp" +#include "private_call_data.hpp" + +namespace aztec3::circuits::abis::private_kernel { + +using plonk::stdlib::witness_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; +using std::is_same; + +template struct PrivateInputs { + typedef typename NCT::fr fr; + + // Signature signature; // TODO! + AccumulatedData start; + PreviousKernelData previous_kernel; + PrivateCallData private_call; + + template PrivateInputs> to_circuit_type(Composer& composer) const + { + static_assert((std::is_same::value)); + + PrivateInputs> private_inputs = { + // signature.to_circuit_type(); + start.to_circuit_type(composer), + previous_kernel.to_circuit_type(composer), + private_call.to_circuit_type(composer), + }; + + return private_inputs; + }; +}; + +} // namespace aztec3::circuits::abis::private_kernel \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/abis/private_kernel/public_inputs.hpp b/circuits/src/aztec3/circuits/abis/private_kernel/public_inputs.hpp new file mode 100644 index 00000000000..d0cec5ccdb6 --- /dev/null +++ b/circuits/src/aztec3/circuits/abis/private_kernel/public_inputs.hpp @@ -0,0 +1,54 @@ +#pragma once +#include +#include +#include +#include +#include "accumulated_data.hpp" +#include "constant_data.hpp" + +namespace aztec3::circuits::abis::private_kernel { + +using plonk::stdlib::witness_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; +using std::is_same; + +template struct PublicInputs { + typedef typename NCT::fr fr; + typedef typename NCT::boolean boolean; + + AccumulatedData end; // Remove, since same as start? Or maybe remove `.start` from PrivateInputs? + ConstantData constants; + boolean is_private = true; // TODO: might need to instantiate from witness! + boolean is_public = false; + boolean is_contract_deployment = false; + + template PublicInputs> to_circuit_type(Composer& composer) const + { + static_assert((std::is_same::value)); + + // Capture the composer: + auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + + PublicInputs> private_inputs = { + end.to_circuit_type(composer), constants.to_circuit_type(composer), to_ct(is_private), to_ct(is_public), + to_ct(is_contract_deployment), + }; + + return private_inputs; + }; + + void set_public() + { + static_assert(!(std::is_same::value)); + + end.set_public(); + constants.set_public(); + + fr(is_private).set_public(); + fr(is_public).set_public(); + fr(is_contract_deployment).set_public(); + } +}; + +} // namespace aztec3::circuits::abis::private_kernel \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp b/circuits/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp index bca058fd82a..abf35d9cdf4 100644 --- a/circuits/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp +++ b/circuits/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp @@ -5,8 +5,8 @@ #include #include #include "../../constants.hpp" -#include "./state_transition.hpp" -#include "./state_read.hpp" +#include "state_transition.hpp" +#include "state_read.hpp" // #include "./executed_callback.hpp" // #include "./callback_stack_item.hpp" diff --git a/circuits/src/aztec3/circuits/apps/contract_factory.hpp b/circuits/src/aztec3/circuits/apps/contract_factory.hpp index e5d10f6cf27..e1acd43ceb6 100644 --- a/circuits/src/aztec3/circuits/apps/contract_factory.hpp +++ b/circuits/src/aztec3/circuits/apps/contract_factory.hpp @@ -48,7 +48,7 @@ template class ContractFactory { .vk_index = uint32(i), .is_private = function.is_private, .is_constructor = function.is_constructor, - }; // TODO: do I need to create witnesses? + }; } }; diff --git a/circuits/src/aztec3/circuits/apps/private_state_factory.hpp b/circuits/src/aztec3/circuits/apps/private_state_factory.hpp index 230ae2b394c..f057cc3a839 100644 --- a/circuits/src/aztec3/circuits/apps/private_state_factory.hpp +++ b/circuits/src/aztec3/circuits/apps/private_state_factory.hpp @@ -7,7 +7,7 @@ namespace aztec3::circuits::apps { -using plonk::stdlib::witness_t; +// using plonk::stdlib::witness_t; using plonk::stdlib::types::CircuitTypes; using NT = plonk::stdlib::types::NativeTypes; @@ -16,10 +16,10 @@ template class PrivateStateFactory { typedef typename CT::fr fr; public: - Composer& composer; + Composer& composer; // TODO: can we remove this? OracleWrapperInterface& oracle; const std::string contract_name; - fr private_state_counter; + fr private_state_counter = 0; std::map> private_state_vars; std::vector> private_state_notes; @@ -31,11 +31,7 @@ template class PrivateStateFactory { std::string contract_name) : composer(composer) , oracle(oracle) - , contract_name(contract_name) - { - private_state_counter = witness_t(&composer, 0); - private_state_counter.assert_is_zero(); - }; + , contract_name(contract_name){}; PrivateStateVar& new_private_state(std::string const& name, PrivateStateType const& private_state_type = PARTITIONED) diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp index e4102bb4389..1a9f44bf3e6 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp @@ -8,7 +8,7 @@ namespace aztec3::circuits::apps::test_apps::escrow { using aztec3::circuits::abis::PrivateCircuitPublicInputs; -void deposit( +PrivateCircuitPublicInputs deposit( Composer& composer, OracleWrapper& oracle, NT::fr const& _amount, NT::fr const& _asset_id, NT::fr const& _memo) { CT::fr amount = to_ct(composer, _amount); @@ -46,10 +46,15 @@ void deposit( public_inputs.pay_fee_from_l1 = to_ct(composer, true); CT::fr(*public_inputs.pay_fee_from_l1) .assert_equal(1); /// TODO: Ugly way of hard-coding a witness. Is there a nicer way? + public_inputs.called_from_l1 = to_ct(composer, true); + CT::fr(*public_inputs.called_from_l1) + .assert_equal(1); /// TODO: Ugly way of hard-coding a witness. Is there a nicer way? public_inputs.set_public(composer); info("public inputs: ", public_inputs); + + return public_inputs.to_native_type(); }; } // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.hpp index 1590176564b..51bbe0adbbb 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.hpp @@ -1,9 +1,12 @@ #pragma once #include "init.hpp" +#include namespace aztec3::circuits::apps::test_apps::escrow { -void deposit( +using aztec3::circuits::abis::PrivateCircuitPublicInputs; + +PrivateCircuitPublicInputs deposit( Composer& composer, OracleWrapper& oracle, NT::fr const& _amount, NT::fr const& _asset_id, NT::fr const& _memo); } // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/events.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/events.hpp deleted file mode 100644 index 05c40a19227..00000000000 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/events.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once -#include "init.hpp" -// #include -// #include - -namespace aztec3::circuits::apps::test_apps::escrow { - -// StateFactory init_events() -// { -// info("\ninit state..."); - -// StateFactory state_factory("Escrow"); - -// state_factory.new_private_state("balances", { "owner", "asset_id" }); - -// return state_factory; -// } - -} // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/index.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/index.hpp index 35950908084..45fe9be7192 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/index.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/index.hpp @@ -1,6 +1,6 @@ #include "init.hpp" -#include "states.hpp" -#include "events.hpp" +#include "contract.hpp" #include "deposit.hpp" #include "transfer.hpp" -#include "withdraw.hpp" \ No newline at end of file +#include "withdraw.hpp" +#include "withdraw_failure_callback.hpp" \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/l1_interface.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/l1_interface.hpp deleted file mode 100644 index 2a28064afde..00000000000 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/l1_interface.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once -#include "init.hpp" -// #include -// #include - -namespace aztec3::circuits::apps::test_apps::escrow { - -// Not sure yet. - -} // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/states.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/states.hpp deleted file mode 100644 index 490c398d778..00000000000 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/states.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once -#include "init.hpp" -#include -#include - -namespace aztec3::circuits::apps::test_apps::escrow { - -inline PrivateStateFactory init_states(Composer& composer, OracleWrapper& oracle) -{ - PrivateStateFactory private_state_factory(composer, oracle, "Escrow"); - - private_state_factory.new_private_state("balances", { "owner", "asset_id" }); - - return private_state_factory; -} - -} // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/kernel/CMakeLists.txt b/circuits/src/aztec3/circuits/kernel/CMakeLists.txt index 9cd9a82562d..80bef670018 100644 --- a/circuits/src/aztec3/circuits/kernel/CMakeLists.txt +++ b/circuits/src/aztec3/circuits/kernel/CMakeLists.txt @@ -2,6 +2,7 @@ barretenberg_module( aztec3_circuits_kernel # Question: why can't I link to these barretenberg modules? # aztec3_circuits_abis + aztec3_circuits_apps # stdlib_recursion stdlib_primitives stdlib_pedersen diff --git a/circuits/src/aztec3/circuits/kernel/index.hpp b/circuits/src/aztec3/circuits/kernel/index.hpp deleted file mode 100644 index 40b875dd640..00000000000 --- a/circuits/src/aztec3/circuits/kernel/index.hpp +++ /dev/null @@ -1,2 +0,0 @@ -#include "play_app_circuit.hpp" -#include "play_kernel_circuit.hpp" \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/kernel/play.test.cpp b/circuits/src/aztec3/circuits/kernel/play.test.cpp deleted file mode 100644 index 4109fcef0ee..00000000000 --- a/circuits/src/aztec3/circuits/kernel/play.test.cpp +++ /dev/null @@ -1,97 +0,0 @@ -#include "index.hpp" -#include -// #include -#include - -namespace aztec3::circuits::kernel { - -using namespace plonk::stdlib::types::turbo; -using plonk::stdlib::recursion::recursion_output; - -// namespace { -// std::shared_ptr srs; -// private_kernel::circuit_data private_kernel_cd; -// private_circuit::circuit_data private_circuit_cd; -// } // namespace - -class play_tests : public ::testing::Test { - // protected: - // static void SetUpTestCase() - // { - // std::string CRS_PATH = "../srs_db/ignition"; - // srs = std::make_shared(CRS_PATH); - // private_circuit_cd = join_split::get_circuit_data(srs); - // private_kernel_cd = claim::get_circuit_data(srs); - // } -}; - -TEST(play_tests, test_play_app_circuit) -{ - Composer composer; - play_app_circuit(composer, 1, 2); -} - -TEST(play_tests, test_play_app_proof_gen) -{ - Composer app_composer; - play_app_circuit(app_composer, 1, 2); - - if (app_composer.failed) { - info("Play app circuit logic failed: ", app_composer.err); - } - - UnrolledProver app_prover = app_composer.create_unrolled_prover(); - waffle::plonk_proof app_proof = app_prover.construct_proof(); - info("app_proof: ", app_proof.proof_data); -} - -TEST(play_tests, test_play_kernel_proof_gen) -{ - Composer app_composer; - play_app_circuit(app_composer, 1, 2); - - if (app_composer.failed) { - info("Play app circuit logic failed: ", app_composer.err); - } - - UnrolledProver app_prover = app_composer.create_unrolled_prover(); - waffle::plonk_proof app_proof = app_prover.construct_proof(); - info("app_proof: ", app_proof.proof_data); - - std::shared_ptr app_vk = app_composer.compute_verification_key(); - - Composer kernel_composer; - recursion_output recursion_output = play_kernel_circuit(kernel_composer, app_vk, app_proof); - - if (kernel_composer.failed) { - info("Play kernel circuit logic failed: ", kernel_composer.err); - } -} - -// TEST(play_tests, test_play_kernel_2_proof_gen) -// { -// Composer app_composer; -// play_app_circuit(app_composer, 1, 2); - -// if (app_composer.failed) { -// info("Play app circuit logic failed: ", app_composer.err); -// } - -// UnrolledProver app_prover = app_composer.create_unrolled_prover(); -// waffle::plonk_proof app_proof = app_prover.construct_proof(); -// info("app_proof: ", app_proof.proof_data); - -// std::shared_ptr app_vk = app_composer.compute_verification_key(); - -// Composer mock_kernel_composer = Composer() - -// Composer kernel_composer; -// recursion_output recursion_output = play_kernel_circuit_2( -// kernel_composer, app_vk, app_proof); // test whether the defaults are acceptable. - -// if (kernel_composer.failed) { -// info("Play kernel circuit logic failed: ", kernel_composer.err); -// } -// } - -} // namespace aztec3::circuits::kernel \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/kernel/play_kernel_circuit.hpp b/circuits/src/aztec3/circuits/kernel/play_kernel_circuit.hpp deleted file mode 100644 index 2679ac85d68..00000000000 --- a/circuits/src/aztec3/circuits/kernel/play_kernel_circuit.hpp +++ /dev/null @@ -1,99 +0,0 @@ -#include -#include -#include -#include - -namespace aztec3::circuits::kernel { - -using namespace plonk::stdlib::types::turbo; -using plonk::stdlib::recursion::recursion_output; -using plonk::stdlib::recursion::recursive_turbo_verifier_settings; -using plonk::stdlib::recursion::verification_key; -using plonk::stdlib::recursion::verify_proof; -using transcript::Manifest; - -class TurboRecursion { - public: - using AggregationObject = recursion_output; - using Proof = waffle::plonk_proof; - using VK = std::shared_ptr; - static AggregationObject aggregate(Composer* composer, - const VK& vk, - const Proof& proof, - const AggregationObject recursion_output = AggregationObject()) - { - std::shared_ptr> recursive_vk = verification_key::from_witness(composer, vk); - const transcript::Manifest recursive_manifest = Composer::create_unrolled_manifest(vk->num_public_inputs); - - AggregationObject result = verify_proof>( - composer, recursive_vk, recursive_manifest, proof, recursion_output); - - return result; - } -}; - -template -typename Recursion::AggregationObject play_kernel_circuit(Composer& composer, - typename Recursion::VK const& app_vk, - typename Recursion::Proof const& app_proof) -{ - typename Recursion::AggregationObject recursion_output = Recursion::aggregate(&composer, app_vk, app_proof); - - recursion_output.add_proof_outputs_as_public_inputs(); - - return recursion_output; -}; - -// TODO: build an app first. -template -typename Recursion::AggregationObject play_kernel_circuit_2(Composer& composer, - typename Recursion::VK const& app_vk, - typename Recursion::Proof const& app_proof, - typename Recursion::VK const& prev_kernel_vk, - typename Recursion::Proof const& prev_kernel_proof) -{ - typename Recursion::AggregationObject recursion_output = - Recursion::aggregate(&composer, prev_kernel_vk, prev_kernel_proof); - - recursion_output = Recursion::aggregate(&composer, app_vk, app_proof, recursion_output); - - recursion_output.add_proof_outputs_as_public_inputs(); - - return recursion_output; -}; - -// circuit_data get_circuit_data(std::shared_ptr const& srs, bool mock) -// { -// std::cerr << "Getting join-split circuit data..." << std::endl; - -// auto build_circuit = [&](Composer& composer) { -// join_split_tx tx(noop_tx()); -// join_split_circuit(composer, tx); -// }; - -// return proofs::get_circuit_data( -// "join split", "", srs, "", true, false, false, true, true, true, mock, build_circuit); -// } - -// recursion_output play_kernel_circuit(Composer& composer, -// std::shared_ptr const& app_vk, -// waffle::plonk_proof const& app_proof) -// { -// const transcript::Manifest recursive_manifest = Composer::create_unrolled_manifest(app_vk->num_public_inputs); - -// std::shared_ptr> recursive_vk = verification_key::from_witness(&composer, app_vk); - -// recursion_output recursion_output = verify_proof>( -// &composer, recursive_vk, recursive_manifest, app_proof); - -// // recursion_output recursion_output; - -// // recursion_output = verify_proof>( -// // &composer, recursive_vk, recursive_manifest, app_proof, recursion_output); - -// recursion_output.add_proof_outputs_as_public_inputs(); - -// return recursion_output; -// }; - -} // namespace aztec3::circuits::kernel \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/kernel/private/index.hpp b/circuits/src/aztec3/circuits/kernel/private/index.hpp new file mode 100644 index 00000000000..f257de72825 --- /dev/null +++ b/circuits/src/aztec3/circuits/kernel/private/index.hpp @@ -0,0 +1,2 @@ +#include "init.hpp" +#include "private_kernel_circuit.hpp" \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/kernel/private/init.hpp b/circuits/src/aztec3/circuits/kernel/private/init.hpp new file mode 100644 index 00000000000..e6da88ac599 --- /dev/null +++ b/circuits/src/aztec3/circuits/kernel/private/init.hpp @@ -0,0 +1,31 @@ +#pragma once +#include +#include +#include +#include + +#include +#include + +#include + +#include + +namespace aztec3::circuits::kernel::private_kernel { + +// Turbo specific, at the moment: +using Composer = plonk::stdlib::types::turbo::Composer; +using plonk::stdlib::types::turbo::UnrolledProver; + +using Aggregator = aztec3::circuits::recursion::TurboAggregator; + +// Generic: +using CT = plonk::stdlib::types::CircuitTypes; +using NT = plonk::stdlib::types::NativeTypes; +using plonk::stdlib::types::to_ct; + +using DB = oracle::FakeDB; +using oracle::NativeOracle; +using OracleWrapper = aztec3::circuits::apps::OracleWrapperInterface; + +} // namespace aztec3::circuits::kernel::private_kernel \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/kernel/private/private_kernel.test.cpp b/circuits/src/aztec3/circuits/kernel/private/private_kernel.test.cpp new file mode 100644 index 00000000000..2d06c7cd448 --- /dev/null +++ b/circuits/src/aztec3/circuits/kernel/private/private_kernel.test.cpp @@ -0,0 +1,206 @@ +#include +#include +// #include +// #include +// #include +// #include +// #include +#include "index.hpp" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// #include +// #include + +// #include +#include + +// #include +// #include +// #include + +namespace { + +using aztec3::circuits::abis::CallContext; +using aztec3::circuits::abis::CallStackItem; +using aztec3::circuits::abis::CallType; +using aztec3::circuits::abis::ExecutedCallback; +using aztec3::circuits::abis::FunctionSignature; +using aztec3::circuits::abis::PrivateCircuitPublicInputs; +using aztec3::circuits::abis::private_kernel::AccumulatedData; +using aztec3::circuits::abis::private_kernel::ConstantData; +using aztec3::circuits::abis::private_kernel::Globals; +using aztec3::circuits::abis::private_kernel::OldTreeRoots; +using aztec3::circuits::abis::private_kernel::PreviousKernelData; +using aztec3::circuits::abis::private_kernel::PrivateCallData; +using aztec3::circuits::abis::private_kernel::PrivateInputs; +using aztec3::circuits::abis::private_kernel::PublicInputs; + +using aztec3::circuits::apps::test_apps::escrow::deposit; + +// using aztec3::circuits::mock::mock_circuit; +using aztec3::circuits::mock::mock_circuit_2; + +} // namespace + +namespace aztec3::circuits::kernel::private_kernel { + +class private_kernel_tests : public ::testing::Test {}; + +TEST(private_kernel_tests, test_deposit) +{ + const NT::address escrow_contract_address = 12345; + const NT::fr escrow_contract_leaf_index = 1; + const NT::fr escrow_portal_contract_address = 23456; + + const NT::address msg_sender = + NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); + const NT::fr msg_sender_private_key = 123456789; + + Composer deposit_composer; + DB db; + + NativeOracle deposit_oracle = NativeOracle(db, escrow_contract_address, msg_sender, msg_sender_private_key); + OracleWrapper deposit_oracle_wrapper = OracleWrapper(deposit_composer, deposit_oracle); + + auto amount = NT::fr(5); + auto asset_id = NT::fr(1); + auto memo = NT::fr(999); + + PrivateCircuitPublicInputs deposit_public_inputs = + deposit(deposit_composer, deposit_oracle_wrapper, amount, asset_id, memo); + + UnrolledProver deposit_prover = deposit_composer.create_unrolled_prover(); + NT::Proof deposit_proof = deposit_prover.construct_proof(); + info("deposit_proof: ", deposit_proof.proof_data); + + std::shared_ptr deposit_vk = deposit_composer.compute_verification_key(); + + //************************************************** + + // MIKE! Need to create a dummy kernel circuit and generate a proof and vk to feed into the below!!! + + Composer mock_composer; + auto mock_public_inputs = PublicInputs{ + .end = AccumulatedData{}, + .constants = + ConstantData{ + .old_tree_roots = + OldTreeRoots{ + // TODO: this needs to be populated from the start, if the roots + // are used in any of the functions being recursed-through. + // .private_data_tree_root = + // .contract_tree_root = + // .l1_results_tree_root = + // .private_kernel_vk_tree_root = + }, + // .is_constructor_recursion = false, + // .is_callback_recursion = false, + .executed_callback = ExecutedCallback{}, + .globals = Globals{}, + }, + .is_private = true, + // .is_public = false, + // .is_contract_deployment = false, + }; + mock_circuit_2(mock_composer, mock_public_inputs); + + UnrolledProver mock_prover = mock_composer.create_unrolled_prover(); + NT::Proof mock_proof = mock_prover.construct_proof(); + info("mock_proof: ", mock_proof.proof_data); + + std::shared_ptr mock_vk = mock_composer.compute_verification_key(); + + //************************************************** + + Composer private_kernel_composer; + + NativeOracle private_kernel_oracle = NativeOracle(db, escrow_contract_address, msg_sender, msg_sender_private_key); + OracleWrapper private_kernel_oracle_wrapper = OracleWrapper(private_kernel_composer, private_kernel_oracle); + + // PrivateInputs private_inputs; + PrivateInputs private_inputs = { + .start = + AccumulatedData{ + .private_call_stack = + std::array{ + 987654321, 0, 0, 0, 0, 0, 0, 0 } }, // AccumulatedData starts out mostly empty, since nothing + // has been accumulated through kernel recursion yet. + .previous_kernel = + PreviousKernelData{ + .public_inputs = + PublicInputs{ + .end = AccumulatedData{}, + .constants = + ConstantData{ + .old_tree_roots = + OldTreeRoots{ + // TODO: this needs to be populated from the start, if the roots + // are used in any of the functions being recursed-through. + // .private_data_tree_root = + // .contract_tree_root = + // .l1_results_tree_root = + // .private_kernel_vk_tree_root = + }, + // .is_constructor_recursion = false, + // .is_callback_recursion = false, + .executed_callback = ExecutedCallback{}, + .globals = Globals{}, + }, + .is_private = true, + // .is_public = false, + // .is_contract_deployment = false, + }, + .proof = mock_proof, + .vk = mock_vk, + }, + .private_call = + PrivateCallData{ + .call_stack_item = + CallStackItem{ + .function_signature = + FunctionSignature{ + .contract_address = escrow_contract_address, + .vk_index = 0, // TODO: deduce this from a NT state_factory. + .is_private = true, + // .is_constructor = false, + // .is_callback = false, + }, + .public_inputs = deposit_public_inputs, + .call_context = + CallContext{ + .msg_sender = msg_sender, + .storage_contract_address = escrow_contract_address, + } }, + .proof = deposit_proof, + .vk = deposit_vk, + // .vk_path TODO + .portal_contract_address = escrow_portal_contract_address, + .contract_leaf_index = escrow_contract_leaf_index, + // .contract_path TODO + }, + }; + + private_kernel_circuit(private_kernel_composer, private_kernel_oracle_wrapper, private_inputs); + + info("computed witness: ", private_kernel_composer.computed_witness); + info("witness: ", private_kernel_composer.witness); + // info("constant variables: ", private_kernel_composer.constant_variables); + // info("variables: ", private_kernel_composer.variables); + info("failed?: ", private_kernel_composer.failed); + info("err: ", private_kernel_composer.err); + info("n: ", private_kernel_composer.n); +} + +} // namespace aztec3::circuits::kernel::private_kernel \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp b/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp new file mode 100644 index 00000000000..4a3642dcce2 --- /dev/null +++ b/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp @@ -0,0 +1,71 @@ +#include "init.hpp" +#include +// #include + +namespace aztec3::circuits::kernel::private_kernel { + +using aztec3::circuits::abis::private_kernel::PrivateInputs; + +/** + * Checks that an array of CT::fr contains `length` contiguous nonzero values, followed by all zeroes. + * Note: this assumes `0` always means 'not used', so be careful. If you actually want `0` counted, you'll need + * something else. + */ +// TODO: move to own file of helper functions. +template CT::boolean array_has_length(std::array const& arr, CT::fr const& length) +{ + CT::fr actual_length = 0; + CT::boolean hit_zero = false; + for (const auto& e : arr) { + hit_zero |= e == 0; + const CT::fr increment = !hit_zero; + actual_length += increment; + } + return actual_length == length; +}; + +/** + * Note: doesn't remove the last element from the array; only returns it! + */ +template CT::fr array_pop(std::array const& arr) +{ + CT::fr popped_value; + CT::boolean already_popped = false; + for (size_t i = arr.size() - 1; i >= 0; --i) { + CT::boolean is_non_zero = arr[i] != 0; + popped_value = CT::fr::conditional_assign(!already_popped && is_non_zero, CT::fr(i), popped_value); + already_popped |= is_non_zero; + } + return popped_value; +}; + +// using abis::private_kernel::PublicInputs; +void base_case(PrivateInputs const& private_inputs) +{ + const auto& start = private_inputs.start; + const CT::boolean is_base_case = start.private_call_count == 0; + + // TODO: Validate empty PreviousKernelData? But then the verify_proof function will error. + // TODO: Can `verify_proof()` fail gracefully and return `false`? + + is_base_case.must_imply( + array_has_length(start.private_call_stack, 1) && array_has_length(start.public_call_stack, 0) && + array_has_length(start.contract_deployment_call_stack, 0) && array_has_length(start.l1_call_stack, 0), + "Invalid arrays for base case."); + + // If we know the length, we can pick an exact index, rather than `pop`: + // const auto& private_call_hash = start.private_call_stack[0]; +}; + +// TODO: decide what to return. +void private_kernel_circuit(Composer& composer, OracleWrapper& oracle, PrivateInputs const& _private_inputs) +{ + const PrivateInputs private_inputs = _private_inputs.to_circuit_type(composer); + + base_case(private_inputs); + + // This line is just to stop the compiler complaining about `oracle` being unused whilst building. + oracle.generate_random_element().assert_is_not_zero(); +}; + +} // namespace aztec3::circuits::kernel::private_kernel \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.hpp b/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.hpp new file mode 100644 index 00000000000..4007d0ca844 --- /dev/null +++ b/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.hpp @@ -0,0 +1,14 @@ +#pragma once +#include "init.hpp" +#include +// #include + +namespace aztec3::circuits::kernel::private_kernel { + +using aztec3::circuits::abis::private_kernel::PrivateInputs; +// using abis::private_kernel::PublicInputs; + +// TODO: decide what to return. +void private_kernel_circuit(Composer& composer, OracleWrapper& oracle, PrivateInputs const& _private_inputs); + +} // namespace aztec3::circuits::kernel::private_kernel \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/kernel/private_kernel.hpp b/circuits/src/aztec3/circuits/kernel/private_kernel.hpp deleted file mode 100644 index d5ffa020819..00000000000 --- a/circuits/src/aztec3/circuits/kernel/private_kernel.hpp +++ /dev/null @@ -1,28 +0,0 @@ -// #include -// #include -// #include - -// namespace aztec3::circuits::kernel::private_kernel { - -// using namespace plonk::stdlib::types::turbo; -// using aztec3::circuits::abis::PrivateCircuitPublicInputs; -// using plonk::stdlib::recursion::recursion_output; - -// // typedef PrivateKernelProof; -// // typedef PrivateKernelPublicInputs; -// // typedef std::pair PrivateKernelProofDatum; -// // typedef PrivateKernelVK; - -// // typedef PrivateCircuitProof; -// // typedef PrivateCircuitPublicInputs; -// // typedef std::pair PrivateCircuitProofDatum; -// // typedef PrivateCircuitVK; - -// recursion_output private_kernel_circuit(Composer& composer, -// PrivateKernelProofDatum const& private_kernel_proof_datum, -// PrivateKernelVK const& private_kernel_vk, -// PrivateCircuitProofDatum const& private_circuit_proof_datum, -// PrivateCircuitVK const& private_circuit_vk) -// {} - -// } // namespace aztec3::circuits::kernel::private_kernel \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/mock/mock_circuit.hpp b/circuits/src/aztec3/circuits/mock/mock_circuit.hpp new file mode 100644 index 00000000000..548f6255b32 --- /dev/null +++ b/circuits/src/aztec3/circuits/mock/mock_circuit.hpp @@ -0,0 +1,19 @@ +#pragma once +#include +#include +#include + +namespace aztec3::circuits::mock { + +using namespace plonk::stdlib; + +template void mock_circuit(Composer& composer, std::vector const& public_inputs_) +{ + const auto public_inputs = map(public_inputs_, [&](auto& i) { return field_t(witness_t(&composer, i)); }); + for (auto& p : public_inputs) { + p.set_public(); + } + plonk::stdlib::pedersen::compress(field_t(witness_t(&composer, 1)), field_t(witness_t(&composer, 1))); +} + +} // namespace aztec3::circuits::mock diff --git a/circuits/src/aztec3/circuits/mock/mock_circuit_2.hpp b/circuits/src/aztec3/circuits/mock/mock_circuit_2.hpp new file mode 100644 index 00000000000..2630a00e0c3 --- /dev/null +++ b/circuits/src/aztec3/circuits/mock/mock_circuit_2.hpp @@ -0,0 +1,35 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +// #include + +namespace aztec3::circuits::mock { + +// ***************************************** + +// MIKE! TODO! This is the wrong PublicInputs class to use! Use the private kernel's PublicINputs!!! + +//******************************************* + +using aztec3::circuits::abis::private_kernel::PublicInputs; +using NT = plonk::stdlib::types::NativeTypes; +using plonk::stdlib::pedersen; +using plonk::stdlib::witness_t; +using plonk::stdlib::types::CircuitTypes; + +template void mock_circuit_2(Composer& composer, PublicInputs const& _public_inputs) +{ + typedef CircuitTypes CT; + auto public_inputs = _public_inputs.to_circuit_type(composer); + public_inputs.set_public(); + + plonk::stdlib::pedersen::compress(typename CT::fr(witness_t(&composer, 1)), + typename CT::fr(witness_t(&composer, 1))); +} + +} // namespace aztec3::circuits::mock diff --git a/circuits/src/aztec3/circuits/recursion/CMakeLists.txt b/circuits/src/aztec3/circuits/recursion/CMakeLists.txt new file mode 100644 index 00000000000..36d5fa3a10e --- /dev/null +++ b/circuits/src/aztec3/circuits/recursion/CMakeLists.txt @@ -0,0 +1,9 @@ +barretenberg_module( + aztec3_circuits_recursion + # Question: why can't I link to these barretenberg modules? + # aztec3_circuits_abis + # stdlib_recursion + stdlib_primitives + stdlib_pedersen + stdlib_blake3s +) \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/recursion/aggregator.hpp b/circuits/src/aztec3/circuits/recursion/aggregator.hpp new file mode 100644 index 00000000000..cb4569afbc2 --- /dev/null +++ b/circuits/src/aztec3/circuits/recursion/aggregator.hpp @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include +#include + +namespace aztec3::circuits::recursion { + +// These are all Circuit Types! +// using plonk::stdlib::recursion::recursion_output; +using plonk::stdlib::recursion::recursive_turbo_verifier_settings; +// using plonk::stdlib::recursion::verification_key; +using plonk::stdlib::recursion::verify_proof; +// using plonk::stdlib::types::turbo::bn254; +using plonk::stdlib::types::turbo::Composer; +using CT = plonk::stdlib::types::CircuitTypes; +using NT = plonk::stdlib::types::NativeTypes; +using transcript::Manifest; + +// class TurboAggregator { +// public: +// // Circuit Types: +// using AggregationObject = recursion_output; + +// // Native Types: +// using Proof = waffle::plonk_proof; +// using VK = std::shared_ptr; + +// static AggregationObject aggregate(Composer* composer, +// const VK& vk, +// const Proof& proof, +// const AggregationObject recursion_output = AggregationObject()) +// { +// std::shared_ptr> recursive_vk = verification_key::from_witness(composer, vk); +// const transcript::Manifest recursive_manifest = Composer::create_unrolled_manifest(vk->num_public_inputs); + +// AggregationObject result = verify_proof>( +// composer, recursive_vk, recursive_manifest, proof, recursion_output); + +// return result; +// } +// }; + +class TurboAggregator { + public: + static CT::AggregationObject aggregate(Composer* composer, + const std::shared_ptr& vk, + const NT::Proof& proof, + const size_t& num_public_inputs, + const CT::AggregationObject recursion_output = CT::AggregationObject()) + { + const Manifest recursive_manifest = Composer::create_unrolled_manifest(num_public_inputs); + + CT::AggregationObject result = verify_proof>( + composer, vk, recursive_manifest, proof, recursion_output); + + return result; + } +}; +} // namespace aztec3::circuits::recursion \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/recursion/index.hpp b/circuits/src/aztec3/circuits/recursion/index.hpp new file mode 100644 index 00000000000..6395d6aace3 --- /dev/null +++ b/circuits/src/aztec3/circuits/recursion/index.hpp @@ -0,0 +1,3 @@ +#include "aggregator.hpp" +#include "play_app_circuit.hpp" +#include "play_recursive_circuit.hpp" \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/recursion/play.test.cpp b/circuits/src/aztec3/circuits/recursion/play.test.cpp new file mode 100644 index 00000000000..5a02eb9a58c --- /dev/null +++ b/circuits/src/aztec3/circuits/recursion/play.test.cpp @@ -0,0 +1,137 @@ +#include "index.hpp" +#include +// #include +#include + +namespace aztec3::circuits::recursion { + +using namespace plonk::stdlib::types::turbo; +using plonk::stdlib::recursion::recursion_output; + +// namespace { +// std::shared_ptr srs; +// private_kernel::circuit_data private_kernel_cd; +// private_circuit::circuit_data private_circuit_cd; +// } // namespace + +class play_tests : public ::testing::Test { + // protected: + // static void SetUpTestCase() + // { + // std::string CRS_PATH = "../srs_db/ignition"; + // srs = std::make_shared(CRS_PATH); + // private_circuit_cd = join_split::get_circuit_data(srs); + // private_kernel_cd = claim::get_circuit_data(srs); + // } +}; + +TEST(play_tests, test_play_app_circuit) +{ + Composer composer; + play_app_circuit(composer, 1, 2); +} + +TEST(play_tests, test_play_app_proof_gen) +{ + Composer app_composer; + play_app_circuit(app_composer, 100, 200); + + if (app_composer.failed) { + info("Play app circuit logic failed: ", app_composer.err); + } + + UnrolledProver app_prover = app_composer.create_unrolled_prover(); + waffle::plonk_proof app_proof = app_prover.construct_proof(); + info("app_proof: ", app_proof.proof_data); +} + +TEST(play_tests, test_play_recursive_proof_gen) +{ + Composer app_composer; + play_app_circuit(app_composer, 1, 2); + + if (app_composer.failed) { + info("Play app circuit logic failed: ", app_composer.err); + } + + UnrolledProver app_prover = app_composer.create_unrolled_prover(); + waffle::plonk_proof app_proof = app_prover.construct_proof(); + info("app_proof: ", app_proof.proof_data); + + std::shared_ptr app_vk = app_composer.compute_verification_key(); + + Composer recursive_composer; + recursion_output recursion_output = play_recursive_circuit(recursive_composer, app_vk, app_proof); + + if (recursive_composer.failed) { + info("Play recursive circuit logic failed: ", recursive_composer.err); + } +} + +TEST(play_tests, test_play_recursive_2_proof_gen) +{ + Composer app_composer; + play_app_circuit(app_composer, 1, 2); + + if (app_composer.failed) { + info("Play app circuit logic failed: ", app_composer.err); + } + + UnrolledProver app_prover = app_composer.create_unrolled_prover(); + waffle::plonk_proof app_proof = app_prover.construct_proof(); + std::shared_ptr app_vk = app_composer.compute_verification_key(); + + info("Hi 1"); + + //******************************************************************************* + + Composer dummy_circuit_composer; + dummy_circuit(dummy_circuit_composer, 1, 2); + + if (dummy_circuit_composer.failed) { + info("dummy_circuit logic failed: ", dummy_circuit_composer.err); + } + + UnrolledProver dummy_circuit_prover = dummy_circuit_composer.create_unrolled_prover(); + waffle::plonk_proof dummy_circuit_proof = dummy_circuit_prover.construct_proof(); + std::shared_ptr dummy_circuit_vk = dummy_circuit_composer.compute_verification_key(); + + info("Hi 2"); + + //******************************************************************************* + + Composer recursion_1_composer = Composer("../srs_db/ignition", 0); + recursion_output recursion_1_output = + play_recursive_circuit_2(recursion_1_composer, app_vk, app_proof, dummy_circuit_vk, dummy_circuit_proof); + + info("Hi 3"); + info("recursion 1 composer gates: ", recursion_1_composer.n); + + if (recursion_1_composer.failed) { + info("recursion_1 circuit logic failed: ", recursion_1_composer.err); + } + + UnrolledProver recursion_1_prover = recursion_1_composer.create_unrolled_prover(); + info("Hi 4"); + + waffle::plonk_proof recursion_1_proof = recursion_1_prover.construct_proof(); + info("Hi 5"); + + std::shared_ptr recursion_1_vk = recursion_1_composer.compute_verification_key(); + + //******************************************************************************* + + // Composer recursion_2_composer; + // recursion_output recursion_2_output = play_recursive_circuit_2( + // recursion_2_composer, app_vk, app_proof, recursion_1_vk, recursion_1_proof); + + // if (recursion_2_composer.failed) { + // info("recursion_2 circuit logic failed: ", recursion_2_composer.err); + // } + + // UnrolledProver recursion_2_prover = recursion_2_composer.create_unrolled_prover(); + // waffle::plonk_proof recursion_2_proof = recursion_2_prover.construct_proof(); + // std::shared_ptr recursion_2_vk = recursion_2_composer.compute_verification_key(); +} + +} // namespace aztec3::circuits::recursion \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/kernel/play_app_circuit.hpp b/circuits/src/aztec3/circuits/recursion/play_app_circuit.hpp similarity index 83% rename from circuits/src/aztec3/circuits/kernel/play_app_circuit.hpp rename to circuits/src/aztec3/circuits/recursion/play_app_circuit.hpp index 3e9c5c07d80..b8108266da9 100644 --- a/circuits/src/aztec3/circuits/kernel/play_app_circuit.hpp +++ b/circuits/src/aztec3/circuits/recursion/play_app_circuit.hpp @@ -1,6 +1,6 @@ #include -namespace aztec3::circuits::kernel { +namespace aztec3::circuits::recursion { using namespace plonk::stdlib::types::turbo; // using plonk::stdlib::recursion::recursion_output; @@ -17,4 +17,4 @@ void play_app_circuit(Composer& composer, barretenberg::fr const& a_in, barreten d.set_public(); }; -} // namespace aztec3::circuits::kernel \ No newline at end of file +} // namespace aztec3::circuits::recursion \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/recursion/play_recursive_circuit.hpp b/circuits/src/aztec3/circuits/recursion/play_recursive_circuit.hpp new file mode 100644 index 00000000000..0273a54f902 --- /dev/null +++ b/circuits/src/aztec3/circuits/recursion/play_recursive_circuit.hpp @@ -0,0 +1,57 @@ +// #include +// #include +// #include +// #include + +namespace aztec3::circuits::recursion { + +using Aggregator = TurboAggregator; +using plonk::stdlib::types::turbo::Composer; +using CT = plonk::stdlib::types::CircuitTypes; +using NT = plonk::stdlib::types::NativeTypes; + +CT::AggregationObject play_recursive_circuit(Composer& composer, + std::shared_ptr const& app_vk, + NT::Proof const& app_proof) +{ + std::shared_ptr app_vk_ct = CT::VK::from_witness(&composer, app_vk); + + CT::AggregationObject recursion_output = + Aggregator::aggregate(&composer, app_vk_ct, app_proof, app_vk->num_public_inputs); + + recursion_output.add_proof_outputs_as_public_inputs(); + + return recursion_output; +}; + +void dummy_circuit(Composer& composer, barretenberg::fr const& a_in, barretenberg::fr const& b_in) +{ + + field_ct a = witness_ct(&composer, a_in); + field_ct b = witness_ct(&composer, b_in); + field_ct c = a * b; + + c.set_public(); +}; + +CT::AggregationObject play_recursive_circuit_2(Composer& composer, + std::shared_ptr const& app_vk, + NT::Proof const& app_proof, + std::shared_ptr const& prev_recursive_vk, + NT::Proof const& prev_recursive_proof) +{ + std::shared_ptr app_vk_ct = CT::VK::from_witness(&composer, app_vk); + std::shared_ptr prev_recursive_vk_ct = CT::VK::from_witness(&composer, prev_recursive_vk); + + CT::AggregationObject aggregation_object = Aggregator::aggregate( + &composer, prev_recursive_vk_ct, prev_recursive_proof, prev_recursive_vk->num_public_inputs); + + aggregation_object = + Aggregator::aggregate(&composer, app_vk_ct, app_proof, app_vk->num_public_inputs, aggregation_object); + + aggregation_object.add_proof_outputs_as_public_inputs(); + + return aggregation_object; +}; + +} // namespace aztec3::circuits::recursion \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/rollup/CMakeLists.txt b/circuits/src/aztec3/circuits/rollup/CMakeLists.txt new file mode 100644 index 00000000000..94089cca0e0 --- /dev/null +++ b/circuits/src/aztec3/circuits/rollup/CMakeLists.txt @@ -0,0 +1,9 @@ +barretenberg_module( + aztec3_circuits_rollup + # Question: why can't I link to these barretenberg modules? + # aztec3_circuits_abis + # stdlib_recursion + stdlib_primitives + stdlib_pedersen + stdlib_blake3s +) \ No newline at end of file diff --git a/circuits/src/aztec3/constants.hpp b/circuits/src/aztec3/constants.hpp index 01e543ab3d1..a73181ae002 100644 --- a/circuits/src/aztec3/constants.hpp +++ b/circuits/src/aztec3/constants.hpp @@ -20,6 +20,20 @@ constexpr size_t CONTRACT_DEPLOYMENT_CALL_STACK_LENGTH = 2; constexpr size_t PARTIAL_L1_CALL_STACK_LENGTH = 2; constexpr size_t CALLBACK_STACK_LENGTH = PARTIAL_L1_CALL_STACK_LENGTH; +constexpr size_t KERNEL_OUTPUT_COMMITMENTS_LENGTH = 16; +constexpr size_t KERNEL_INPUT_NULLIFIERS_LENGTH = 16; +constexpr size_t KERNEL_PRIVATE_CALL_STACK_LENGTH = 8; +constexpr size_t KERNEL_PUBLIC_CALL_STACK_LENGTH = 8; +constexpr size_t KERNEL_CONTRACT_DEPLOYMENT_CALL_STACK_LENGTH = 4; +constexpr size_t KERNEL_L1_CALL_STACK_LENGTH = 4; +constexpr size_t KERNEL_CALLBACK_STACK_LENGTH = KERNEL_L1_CALL_STACK_LENGTH; +constexpr size_t KERNEL_OPTIONALLY_REVEALED_DATA_LENGTH = 4; + +constexpr size_t VK_TREE_HEIGHT = 3; +constexpr size_t CONTRACT_TREE_HEIGHT = 4; +constexpr size_t PRIVATE_DATA_TREE_HEIGHT = 8; +constexpr size_t NULLIFIER_TREE_HEIGHT = 8; + // Enumerate the hash_indices which are used for pedersen hashing // Start from 1 to avoid the default generators. enum GeneratorIndex { diff --git a/circuits/src/aztec3/oracle/oracle.hpp b/circuits/src/aztec3/oracle/oracle.hpp index 15f72659f12..e9d480d96f0 100644 --- a/circuits/src/aztec3/oracle/oracle.hpp +++ b/circuits/src/aztec3/oracle/oracle.hpp @@ -16,15 +16,21 @@ template class NativeOracleInterface { public: DB& db; - NativeOracleInterface(DB& db, NT::fr const& contract_address, NT::address const& msg_sender) + NativeOracleInterface(DB& db, + NT::fr const& contract_address, + // NT::fr const& portal_contract_address, + NT::address const& msg_sender) : db(db) , call_context({ .msg_sender = msg_sender, .storage_contract_address = contract_address, - }){}; + }) + // , portal_contract_address(portal_contract_address) + {}; NativeOracleInterface(DB& db, NT::fr const& contract_address, + // NT::fr const& portal_contract_address, NT::address const& msg_sender, std::optional msg_sender_private_key) : db(db) @@ -32,6 +38,7 @@ template class NativeOracleInterface { .msg_sender = msg_sender, .storage_contract_address = contract_address, }) + // , portal_contract_address(portal_contract_address) , msg_sender_private_key(msg_sender_private_key){}; NT::fr get_msg_sender_private_key() @@ -46,6 +53,15 @@ template class NativeOracleInterface { return *msg_sender_private_key; }; + // NT::fr get_portal_contract_address() + // { + // if (portal_contract_address_already_got) { + // throw_or_abort(already_got_error); + // } + // portal_contract_address_already_got = true; + // return portal_contract_address; + // }; + CallContext get_call_context() { if (call_context_already_got) { @@ -76,10 +92,12 @@ template class NativeOracleInterface { // A circuit doesn't know its own address, so we need to track the address from 'outside'. CallContext call_context; + // NT::fr portal_contract_address; std::optional msg_sender_private_key; // Ensure functions called only once: bool call_context_already_got = false; + // bool portal_contract_address_already_got = false; bool msg_sender_private_key_already_got = false; std::string already_got_error = "Your circuit has already accessed this value. Don't ask the oracle twice, since " "it shouldn't be trusted, and could lead to circuit bugs"; From 3a4707c70783669c6a39392c42ae5c445ef45ac7 Mon Sep 17 00:00:00 2001 From: iAmMichaelConnor Date: Mon, 6 Jun 2022 19:14:25 +0000 Subject: [PATCH 005/166] private kernel circuit recursive verification --- .../src/aztec3/circuits/abis/call_context.hpp | 2 +- .../aztec3/circuits/abis/call_stack_item.hpp | 11 +++ .../circuits/abis/callback_stack_item.hpp | 12 +++ .../circuits/abis/executed_callback.hpp | 10 ++ .../circuits/abis/function_signature.hpp | 2 +- .../abis/private_circuit_public_inputs.hpp | 61 +++++++++++- .../abis/private_kernel/public_inputs.hpp | 2 +- .../kernel/private/private_kernel.test.cpp | 46 ++++----- .../kernel/private/private_kernel_circuit.cpp | 98 +++++++++++++++++-- .../aztec3/circuits/mock/mock_circuit_2.hpp | 17 +++- .../aztec3/circuits/recursion/play.test.cpp | 9 -- .../recursion/play_recursive_circuit.hpp | 14 +++ .../src/aztec3/circuits/types/address.hpp | 2 + circuits/src/aztec3/constants.hpp | 3 + 14 files changed, 241 insertions(+), 48 deletions(-) diff --git a/circuits/src/aztec3/circuits/abis/call_context.hpp b/circuits/src/aztec3/circuits/abis/call_context.hpp index 11ddbbe9c9c..9b3a1c0f780 100644 --- a/circuits/src/aztec3/circuits/abis/call_context.hpp +++ b/circuits/src/aztec3/circuits/abis/call_context.hpp @@ -52,7 +52,7 @@ template struct CallContext { return call_context; }; - fr hash() + fr hash() const { std::vector inputs = { msg_sender.to_field(), diff --git a/circuits/src/aztec3/circuits/abis/call_stack_item.hpp b/circuits/src/aztec3/circuits/abis/call_stack_item.hpp index 468b2cddf86..823abfc854b 100644 --- a/circuits/src/aztec3/circuits/abis/call_stack_item.hpp +++ b/circuits/src/aztec3/circuits/abis/call_stack_item.hpp @@ -23,6 +23,7 @@ enum class CallType { template struct CallStackItem { typedef typename NCT::boolean boolean; + typedef typename NCT::fr fr; template using PublicInputs = typename std:: @@ -59,6 +60,16 @@ template struct CallStackItem { return call_stack_item; }; + + fr hash() const + { + std::vector inputs = { + function_signature.hash(), public_inputs.hash(), call_context.hash(), + fr(is_delegate_call), fr(is_static_call), + }; + + return NCT::compress(inputs, GeneratorIndex::CALL_STACK_ITEM); + } }; template diff --git a/circuits/src/aztec3/circuits/abis/callback_stack_item.hpp b/circuits/src/aztec3/circuits/abis/callback_stack_item.hpp index 501166d5ff0..110edaac2bf 100644 --- a/circuits/src/aztec3/circuits/abis/callback_stack_item.hpp +++ b/circuits/src/aztec3/circuits/abis/callback_stack_item.hpp @@ -74,6 +74,18 @@ template struct CallbackStackItem { failure_callback_call_hash.set_public(); success_result_arg_map_acc.set_public(); } + + fr hash() const + { + std::vector inputs = { + callback_public_key.to_field(), + success_callback_call_hash, + failure_callback_call_hash, + success_result_arg_map_acc, + }; + + return NCT::compress(inputs, GeneratorIndex::CALLBACK_STACK_ITEM); + } }; template void read(uint8_t const*& it, CallbackStackItem& callback_stack_item) diff --git a/circuits/src/aztec3/circuits/abis/executed_callback.hpp b/circuits/src/aztec3/circuits/abis/executed_callback.hpp index e792bd5d68e..c7af4217da1 100644 --- a/circuits/src/aztec3/circuits/abis/executed_callback.hpp +++ b/circuits/src/aztec3/circuits/abis/executed_callback.hpp @@ -49,6 +49,16 @@ template struct ExecutedCallback { return executed_callback; }; + fr hash() const + { + std::vector inputs = { + l1_result_hash, + fr(l1_results_tree_leaf_index), + }; + + return NCT::compress(inputs, GeneratorIndex::EXECUTED_CALLBACK); + } + template void assert_is_zero() { static_assert((std::is_same, NCT>::value)); diff --git a/circuits/src/aztec3/circuits/abis/function_signature.hpp b/circuits/src/aztec3/circuits/abis/function_signature.hpp index 8a6ede4b2b2..f6d3931100d 100644 --- a/circuits/src/aztec3/circuits/abis/function_signature.hpp +++ b/circuits/src/aztec3/circuits/abis/function_signature.hpp @@ -56,7 +56,7 @@ template struct FunctionSignature { fr(is_callback).set_public(); } - fr hash() + fr hash() const { std::vector inputs = { contract_address.to_field(), fr(vk_index), fr(is_private), fr(is_constructor), fr(is_callback), diff --git a/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp b/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp index 8294b645246..065d79a3d9a 100644 --- a/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp +++ b/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp @@ -9,7 +9,8 @@ #include "call_context.hpp" #include "executed_callback.hpp" #include "callback_stack_item.hpp" - +#include +#include namespace aztec3::circuits::abis { using plonk::stdlib::witness_t; @@ -276,9 +277,67 @@ template class PrivateCircuitPublicInputs { return pis; }; + fr hash() const + { + auto to_hashes = [](const std::optional& e) { + if (!e) { + throw_or_abort("Value is nullopt"); + } + return (*e).hash(); + }; + + std::vector inputs; + + inputs.push_back((*call_context).hash()); + + spread_arr_opt_into_vec(custom_public_inputs, inputs); + spread_arr_opt_into_vec(emitted_public_inputs, inputs); + + inputs.push_back((*executed_callback).hash()); + + spread_arr_opt_into_vec(output_commitments, inputs); + spread_arr_opt_into_vec(input_nullifiers, inputs); + + spread_arr_opt_into_vec(private_call_stack, inputs); + spread_arr_opt_into_vec(public_call_stack, inputs); + spread_arr_opt_into_vec(contract_deployment_call_stack, inputs); + spread_arr_opt_into_vec(partial_l1_call_stack, inputs); + spread_arr_into_vec(map(callback_stack, to_hashes), inputs); + + inputs.push_back(*old_private_data_tree_root); + + inputs.push_back(fr(*is_fee_payment)); + inputs.push_back(fr(*pay_fee_from_l1)); + inputs.push_back(fr(*pay_fee_from_public_l2)); + inputs.push_back(fr(*called_from_l1)); + + return NCT::compress(inputs, GeneratorIndex::PRIVATE_CIRCUIT_PUBLIC_INPUTS); + } + private: bool all_elements_populated = false; + template + void spread_arr_opt_into_vec(std::array, SIZE> const& arr, std::vector& vec) const + { + auto get_opt_value = [](const std::optional& e) { + if (!e) { + throw_or_abort("Value is nullopt"); + } + return *e; + }; + + std::array arr_values = map(arr, get_opt_value); + const auto arr_size = sizeof(arr_values) / sizeof(fr); + vec.insert(vec.end(), &arr_values[0], &arr_values[0] + arr_size); + } + + template void spread_arr_into_vec(std::array const& arr, std::vector& vec) const + { + const auto arr_size = sizeof(arr) / sizeof(fr); + vec.insert(vec.end(), &arr[0], &arr[0] + arr_size); + } + /// TODO: unused? // template bool check_all_elements_populated() // { diff --git a/circuits/src/aztec3/circuits/abis/private_kernel/public_inputs.hpp b/circuits/src/aztec3/circuits/abis/private_kernel/public_inputs.hpp index d0cec5ccdb6..d6295224ca6 100644 --- a/circuits/src/aztec3/circuits/abis/private_kernel/public_inputs.hpp +++ b/circuits/src/aztec3/circuits/abis/private_kernel/public_inputs.hpp @@ -17,7 +17,7 @@ template struct PublicInputs { typedef typename NCT::fr fr; typedef typename NCT::boolean boolean; - AccumulatedData end; // Remove, since same as start? Or maybe remove `.start` from PrivateInputs? + AccumulatedData end; ConstantData constants; boolean is_private = true; // TODO: might need to instantiate from witness! boolean is_public = false; diff --git a/circuits/src/aztec3/circuits/kernel/private/private_kernel.test.cpp b/circuits/src/aztec3/circuits/kernel/private/private_kernel.test.cpp index 2d06c7cd448..dfac3d22769 100644 --- a/circuits/src/aztec3/circuits/kernel/private/private_kernel.test.cpp +++ b/circuits/src/aztec3/circuits/kernel/private/private_kernel.test.cpp @@ -83,7 +83,7 @@ TEST(private_kernel_tests, test_deposit) UnrolledProver deposit_prover = deposit_composer.create_unrolled_prover(); NT::Proof deposit_proof = deposit_prover.construct_proof(); - info("deposit_proof: ", deposit_proof.proof_data); + // info("\ndeposit_proof: ", deposit_proof.proof_data); std::shared_ptr deposit_vk = deposit_composer.compute_verification_key(); @@ -118,7 +118,7 @@ TEST(private_kernel_tests, test_deposit) UnrolledProver mock_prover = mock_composer.create_unrolled_prover(); NT::Proof mock_proof = mock_prover.construct_proof(); - info("mock_proof: ", mock_proof.proof_data); + // info("\nmock_proof: ", mock_proof.proof_data); std::shared_ptr mock_vk = mock_composer.compute_verification_key(); @@ -129,14 +129,31 @@ TEST(private_kernel_tests, test_deposit) NativeOracle private_kernel_oracle = NativeOracle(db, escrow_contract_address, msg_sender, msg_sender_private_key); OracleWrapper private_kernel_oracle_wrapper = OracleWrapper(private_kernel_composer, private_kernel_oracle); + const CallStackItem deposit_call_stack_item{ + .function_signature = + FunctionSignature{ + .contract_address = escrow_contract_address, + .vk_index = 0, // TODO: deduce this from a NT state_factory. + .is_private = true, + // .is_constructor = false, + // .is_callback = false, + }, + .public_inputs = deposit_public_inputs, + .call_context = *deposit_public_inputs.call_context, + // .is_delegate_call = false, + // .is_static_call = false, + }; + // PrivateInputs private_inputs; PrivateInputs private_inputs = { .start = AccumulatedData{ .private_call_stack = std::array{ - 987654321, 0, 0, 0, 0, 0, 0, 0 } }, // AccumulatedData starts out mostly empty, since nothing - // has been accumulated through kernel recursion yet. + deposit_call_stack_item.hash(), 0, 0, 0, 0, 0, 0, 0 } }, // AccumulatedData starts out mostly + // empty, since nothing has been + // accumulated through kernel recursion + // yet. .previous_kernel = PreviousKernelData{ .public_inputs = @@ -146,8 +163,6 @@ TEST(private_kernel_tests, test_deposit) ConstantData{ .old_tree_roots = OldTreeRoots{ - // TODO: this needs to be populated from the start, if the roots - // are used in any of the functions being recursed-through. // .private_data_tree_root = // .contract_tree_root = // .l1_results_tree_root = @@ -158,7 +173,7 @@ TEST(private_kernel_tests, test_deposit) .executed_callback = ExecutedCallback{}, .globals = Globals{}, }, - .is_private = true, + // .is_private = true, // .is_public = false, // .is_contract_deployment = false, }, @@ -167,22 +182,7 @@ TEST(private_kernel_tests, test_deposit) }, .private_call = PrivateCallData{ - .call_stack_item = - CallStackItem{ - .function_signature = - FunctionSignature{ - .contract_address = escrow_contract_address, - .vk_index = 0, // TODO: deduce this from a NT state_factory. - .is_private = true, - // .is_constructor = false, - // .is_callback = false, - }, - .public_inputs = deposit_public_inputs, - .call_context = - CallContext{ - .msg_sender = msg_sender, - .storage_contract_address = escrow_contract_address, - } }, + .call_stack_item = deposit_call_stack_item, .proof = deposit_proof, .vk = deposit_vk, // .vk_path TODO diff --git a/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp b/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp index 4a3642dcce2..623681e6740 100644 --- a/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp +++ b/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp @@ -1,14 +1,15 @@ #include "init.hpp" #include -// #include +#include namespace aztec3::circuits::kernel::private_kernel { using aztec3::circuits::abis::private_kernel::PrivateInputs; +using aztec3::circuits::abis::private_kernel::PublicInputs; /** * Checks that an array of CT::fr contains `length` contiguous nonzero values, followed by all zeroes. - * Note: this assumes `0` always means 'not used', so be careful. If you actually want `0` counted, you'll need + * Note: this assumes `0` always means 'not used', so be careful. If you actually want `0` to be counted, you'll need * something else. */ // TODO: move to own file of helper functions. @@ -26,46 +27,123 @@ template CT::boolean array_has_length(std::array CT::fr array_pop(std::array const& arr) { CT::fr popped_value; CT::boolean already_popped = false; - for (size_t i = arr.size() - 1; i >= 0; --i) { + for (size_t i = arr.size() - 1; i != (size_t)-1; i--) { CT::boolean is_non_zero = arr[i] != 0; - popped_value = CT::fr::conditional_assign(!already_popped && is_non_zero, CT::fr(i), popped_value); + popped_value = CT::fr::conditional_assign(!already_popped && is_non_zero, arr[i], popped_value); + already_popped |= is_non_zero; } return popped_value; }; +CT::AggregationObject verify_proofs(Composer& composer, + PrivateInputs const& private_inputs, + size_t const& num_private_call_public_inputs, + size_t const& num_private_kernel_public_inputs) +{ + CT::AggregationObject aggregation_object = Aggregator::aggregate( + &composer, private_inputs.private_call.vk, private_inputs.private_call.proof, num_private_call_public_inputs); + + Aggregator::aggregate(&composer, + private_inputs.previous_kernel.vk, + private_inputs.previous_kernel.proof, + num_private_kernel_public_inputs); + + return aggregation_object; +} + +void validate_private_call_hash(PrivateInputs const& private_inputs) +{ + const auto private_call_hash = array_pop(private_inputs.start.private_call_stack); + const auto calculated_private_call_hash = private_inputs.private_call.call_stack_item.hash(); + + private_call_hash.assert_equal(calculated_private_call_hash, "private_call_hash does not reconcile"); +}; + // using abis::private_kernel::PublicInputs; -void base_case(PrivateInputs const& private_inputs) +CT::boolean base_case(PrivateInputs const& private_inputs, PublicInputs& public_inputs) { const auto& start = private_inputs.start; const CT::boolean is_base_case = start.private_call_count == 0; - // TODO: Validate empty PreviousKernelData? But then the verify_proof function will error. - // TODO: Can `verify_proof()` fail gracefully and return `false`? - is_base_case.must_imply( - array_has_length(start.private_call_stack, 1) && array_has_length(start.public_call_stack, 0) && + array_has_length(start.private_call_stack, 1) // TODO: might change to allow 2, so a fee can be paid. + && array_has_length(start.public_call_stack, 0) && array_has_length(start.contract_deployment_call_stack, 0) && array_has_length(start.l1_call_stack, 0), "Invalid arrays for base case."); // If we know the length, we can pick an exact index, rather than `pop`: // const auto& private_call_hash = start.private_call_stack[0]; + const auto& private_call = private_inputs.private_call; + + public_inputs.constants.is_constructor_recursion = CT::boolean::conditional_assign( + is_base_case, + private_inputs.private_call.call_stack_item.function_signature.is_constructor, + private_inputs.previous_kernel.public_inputs.constants.is_constructor_recursion); + + public_inputs.constants.is_callback_recursion = + CT::boolean::conditional_assign(is_base_case, + private_inputs.private_call.call_stack_item.function_signature.is_callback, + private_inputs.previous_kernel.public_inputs.constants.is_callback_recursion); + + // TODO: Verify the ECDSA signature! + + is_base_case.must_imply(private_call.call_stack_item.is_delegate_call == false && + private_call.call_stack_item.is_static_call == false, + "A user cannot make a delegatecall or staticcall"); + + // The below also prevents delegatecall/staticcall + is_base_case.must_imply(private_call.call_stack_item.call_context.storage_contract_address == + private_call.call_stack_item.function_signature.contract_address, + "Storage contract address must be that of the called contract in the base case"); + + // TODO: privatelyExecutedCallback logic and checks + + return is_base_case; }; // TODO: decide what to return. void private_kernel_circuit(Composer& composer, OracleWrapper& oracle, PrivateInputs const& _private_inputs) { const PrivateInputs private_inputs = _private_inputs.to_circuit_type(composer); + PublicInputs public_inputs; + + private_inputs.private_call.call_stack_item.function_signature.is_private.assert_equal( + true, "Cannot execute a non-private function with the private kernel circuit"); + + auto aggregation_object = verify_proofs(composer, + private_inputs, + _private_inputs.private_call.vk->num_public_inputs, + _private_inputs.previous_kernel.vk->num_public_inputs); - base_case(private_inputs); + validate_private_call_hash(private_inputs); + + const CT::boolean is_base_case = base_case(private_inputs, public_inputs); + + const CT::boolean is_recursive_case = !is_base_case; + + is_recursive_case.must_imply(private_inputs.previous_kernel.public_inputs.is_private == true, + "Cannot verify a non-private kernel snark in the private kernel circuit"); + is_recursive_case.must_imply(private_inputs.private_call.call_stack_item.function_signature.is_callback == false, + "A callback must be executed as the first tx in the recursion"); + is_recursive_case.must_imply(private_inputs.private_call.call_stack_item.function_signature.is_constructor == false, + "A constructor must be executed as the first tx in the recursion"); + + // TODO: kernel vk membership check! // This line is just to stop the compiler complaining about `oracle` being unused whilst building. oracle.generate_random_element().assert_is_not_zero(); + + public_inputs.end.aggregation_object = aggregation_object; + + // public_inputs.set_public(); }; } // namespace aztec3::circuits::kernel::private_kernel \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/mock/mock_circuit_2.hpp b/circuits/src/aztec3/circuits/mock/mock_circuit_2.hpp index 2630a00e0c3..07a89898b57 100644 --- a/circuits/src/aztec3/circuits/mock/mock_circuit_2.hpp +++ b/circuits/src/aztec3/circuits/mock/mock_circuit_2.hpp @@ -25,11 +25,24 @@ using plonk::stdlib::types::CircuitTypes; template void mock_circuit_2(Composer& composer, PublicInputs const& _public_inputs) { typedef CircuitTypes CT; + typedef typename CT::fr fr; + auto public_inputs = _public_inputs.to_circuit_type(composer); + + { + std::vector dummy_witness_indices; + // 16 is the number of values added to `proof_witness_indices` at the end of `verify_proof`. + for (size_t i = 0; i < 16; ++i) { + fr witness = fr(witness_t(&composer, 0)); + uint32_t witness_index = witness.get_witness_index(); + dummy_witness_indices.push_back(witness_index); + } + public_inputs.end.aggregation_object.proof_witness_indices = dummy_witness_indices; + } + public_inputs.set_public(); - plonk::stdlib::pedersen::compress(typename CT::fr(witness_t(&composer, 1)), - typename CT::fr(witness_t(&composer, 1))); + plonk::stdlib::pedersen::compress(fr(witness_t(&composer, 1)), fr(witness_t(&composer, 1))); } } // namespace aztec3::circuits::mock diff --git a/circuits/src/aztec3/circuits/recursion/play.test.cpp b/circuits/src/aztec3/circuits/recursion/play.test.cpp index 5a02eb9a58c..2ecf23cee4c 100644 --- a/circuits/src/aztec3/circuits/recursion/play.test.cpp +++ b/circuits/src/aztec3/circuits/recursion/play.test.cpp @@ -81,8 +81,6 @@ TEST(play_tests, test_play_recursive_2_proof_gen) waffle::plonk_proof app_proof = app_prover.construct_proof(); std::shared_ptr app_vk = app_composer.compute_verification_key(); - info("Hi 1"); - //******************************************************************************* Composer dummy_circuit_composer; @@ -96,26 +94,19 @@ TEST(play_tests, test_play_recursive_2_proof_gen) waffle::plonk_proof dummy_circuit_proof = dummy_circuit_prover.construct_proof(); std::shared_ptr dummy_circuit_vk = dummy_circuit_composer.compute_verification_key(); - info("Hi 2"); - //******************************************************************************* Composer recursion_1_composer = Composer("../srs_db/ignition", 0); recursion_output recursion_1_output = play_recursive_circuit_2(recursion_1_composer, app_vk, app_proof, dummy_circuit_vk, dummy_circuit_proof); - info("Hi 3"); - info("recursion 1 composer gates: ", recursion_1_composer.n); - if (recursion_1_composer.failed) { info("recursion_1 circuit logic failed: ", recursion_1_composer.err); } UnrolledProver recursion_1_prover = recursion_1_composer.create_unrolled_prover(); - info("Hi 4"); waffle::plonk_proof recursion_1_proof = recursion_1_prover.construct_proof(); - info("Hi 5"); std::shared_ptr recursion_1_vk = recursion_1_composer.compute_verification_key(); diff --git a/circuits/src/aztec3/circuits/recursion/play_recursive_circuit.hpp b/circuits/src/aztec3/circuits/recursion/play_recursive_circuit.hpp index 0273a54f902..6dfc80f88e1 100644 --- a/circuits/src/aztec3/circuits/recursion/play_recursive_circuit.hpp +++ b/circuits/src/aztec3/circuits/recursion/play_recursive_circuit.hpp @@ -43,14 +43,28 @@ CT::AggregationObject play_recursive_circuit_2(Composer& composer, std::shared_ptr app_vk_ct = CT::VK::from_witness(&composer, app_vk); std::shared_ptr prev_recursive_vk_ct = CT::VK::from_witness(&composer, prev_recursive_vk); + info("composer failed 1? ", composer.failed); + CT::AggregationObject aggregation_object = Aggregator::aggregate( &composer, prev_recursive_vk_ct, prev_recursive_proof, prev_recursive_vk->num_public_inputs); + info("composer failed 2? ", composer.failed); + + info("\npublic inputs before: ", composer.public_inputs.size()); aggregation_object = Aggregator::aggregate(&composer, app_vk_ct, app_proof, app_vk->num_public_inputs, aggregation_object); + info("\npublic inputs after: ", composer.public_inputs.size()); + + info("composer failed 3? ", composer.failed); aggregation_object.add_proof_outputs_as_public_inputs(); + info("composer failed 4? ", composer.failed); + + info("\npublic inputs after after: ", composer.public_inputs.size()); + + info("composer failed 5? ", composer.failed); + return aggregation_object; }; diff --git a/circuits/src/aztec3/circuits/types/address.hpp b/circuits/src/aztec3/circuits/types/address.hpp index 0c9d97be4af..4de48cbf879 100644 --- a/circuits/src/aztec3/circuits/types/address.hpp +++ b/circuits/src/aztec3/circuits/types/address.hpp @@ -91,6 +91,8 @@ template class address_t { return *this; } + bool_t operator==(const address_t& other) const { return this->to_field() == other.to_field(); } + field_t to_field() const { return address_; } void assert_equal(const address_t& rhs, std::string const& msg = "address_t::assert_equal") const diff --git a/circuits/src/aztec3/constants.hpp b/circuits/src/aztec3/constants.hpp index a73181ae002..019fa721c32 100644 --- a/circuits/src/aztec3/constants.hpp +++ b/circuits/src/aztec3/constants.hpp @@ -46,10 +46,13 @@ enum GeneratorIndex { CONTRACT_ADDRESS, FUNCTION_SIGNATURE, CALL_ARGS, + EXECUTED_CALLBACK, L1_RESULT_PLACEHOLDER, CALL_CONTEXT, CALL_STACK_ITEM, CALLBACK_STACK_ITEM, + PRIVATE_CIRCUIT_PUBLIC_INPUTS, + PUBLIC_CIRCUIT_PUBLIC_INPUTS, }; // Enumerate the hash_sub_indices which are used for committing to private state note preimages. From d1e9379c1b7347b5b491eb28f7bf4d74ba3f3424 Mon Sep 17 00:00:00 2001 From: iAmMichaelConnor Date: Wed, 8 Jun 2022 10:21:26 +0000 Subject: [PATCH 006/166] more private kernel circuit logic --- .../src/aztec3/circuits/abis/call_context.hpp | 6 +- .../abis/private_circuit_public_inputs.hpp | 172 ++++++++++-- .../abis/private_kernel/accumulated_data.hpp | 8 + .../abis/private_kernel/constant_data.hpp | 6 + .../private_kernel/previous_kernel_data.hpp | 4 +- .../abis/private_kernel/private_inputs.hpp | 4 +- .../apps/test_apps/escrow/deposit.cpp | 6 +- .../apps/test_apps/escrow/deposit.hpp | 4 +- .../apps/test_apps/escrow/transfer.cpp | 4 +- .../apps/test_apps/escrow/withdraw.cpp | 4 +- .../escrow/withdraw_failure_callback.cpp | 4 +- .../kernel/private/private_kernel.test.cpp | 34 ++- .../kernel/private/private_kernel_circuit.cpp | 250 ++++++++++++++---- circuits/src/aztec3/constants.hpp | 4 +- 14 files changed, 413 insertions(+), 97 deletions(-) diff --git a/circuits/src/aztec3/circuits/abis/call_context.hpp b/circuits/src/aztec3/circuits/abis/call_context.hpp index 9b3a1c0f780..ba4fb1c38a1 100644 --- a/circuits/src/aztec3/circuits/abis/call_context.hpp +++ b/circuits/src/aztec3/circuits/abis/call_context.hpp @@ -16,11 +16,15 @@ template struct CallContext { typedef typename NCT::address address; typedef typename NCT::grumpkin_point grumpkin_point; typedef typename NCT::fr fr; + typedef typename NCT::boolean boolean; address msg_sender; address storage_contract_address; - bool operator==(CallContext const&) const = default; + boolean operator==(CallContext const& other) const + { + return msg_sender == other.msg_sender && storage_contract_address == other.storage_contract_address; + }; static CallContext empty() { return { 0, 0 }; }; diff --git a/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp b/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp index 065d79a3d9a..a388bbaaf31 100644 --- a/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp +++ b/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp @@ -18,7 +18,114 @@ using plonk::stdlib::types::CircuitTypes; using plonk::stdlib::types::NativeTypes; template class PrivateCircuitPublicInputs { - typedef typename NCT::address address; + typedef typename NCT::fr fr; + typedef typename NCT::boolean boolean; + + public: + CallContext call_context; + + std::array custom_public_inputs; + std::array emitted_public_inputs; + + ExecutedCallback executed_callback; + + std::array output_commitments; + std::array input_nullifiers; + + std::array private_call_stack; + std::array public_call_stack; + std::array contract_deployment_call_stack; + std::array partial_l1_call_stack; + std::array, CALLBACK_STACK_LENGTH> callback_stack; + + fr old_private_data_tree_root; + + boolean is_fee_payment; + boolean pay_fee_from_l1; + boolean pay_fee_from_public_l2; + boolean called_from_l1; + + template + PrivateCircuitPublicInputs> to_circuit_type(Composer& composer) const + { + static_assert((std::is_same::value)); + + // Capture the composer: + auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + auto to_circuit_type = [&](auto& e) { return e.to_circuit_type(composer); }; + + PrivateCircuitPublicInputs> pis = { + to_circuit_type(call_context), + + to_ct(custom_public_inputs), + to_ct(emitted_public_inputs), + + to_circuit_type(executed_callback), + + to_ct(output_commitments), + to_ct(input_nullifiers), + + to_ct(private_call_stack), + to_ct(public_call_stack), + to_ct(contract_deployment_call_stack), + to_ct(partial_l1_call_stack), + map(callback_stack, to_circuit_type), + + to_ct(old_private_data_tree_root), + + to_ct(is_fee_payment), + to_ct(pay_fee_from_l1), + to_ct(pay_fee_from_public_l2), + to_ct(called_from_l1), + }; + + return pis; + }; + + fr hash() const + { + auto to_hashes = [](const T& e) { return e.hash(); }; + + std::vector inputs; + + inputs.push_back(call_context.hash()); + + spread_arr_into_vec(custom_public_inputs, inputs); + spread_arr_into_vec(emitted_public_inputs, inputs); + + inputs.push_back(executed_callback.hash()); + + spread_arr_into_vec(output_commitments, inputs); + spread_arr_into_vec(input_nullifiers, inputs); + + spread_arr_into_vec(private_call_stack, inputs); + spread_arr_into_vec(public_call_stack, inputs); + spread_arr_into_vec(contract_deployment_call_stack, inputs); + spread_arr_into_vec(partial_l1_call_stack, inputs); + spread_arr_into_vec(map(callback_stack, to_hashes), inputs); + + inputs.push_back(old_private_data_tree_root); + + inputs.push_back(fr(is_fee_payment)); + inputs.push_back(fr(pay_fee_from_l1)); + inputs.push_back(fr(pay_fee_from_public_l2)); + inputs.push_back(fr(called_from_l1)); + + return NCT::compress(inputs, GeneratorIndex::PRIVATE_CIRCUIT_PUBLIC_INPUTS); + } + + template void spread_arr_into_vec(std::array const& arr, std::vector& vec) const + { + const auto arr_size = sizeof(arr) / sizeof(fr); + vec.insert(vec.end(), &arr[0], &arr[0] + arr_size); + } +}; + +// It's been extremely useful for all members here to be std::optional. It allows test app circuits to be very +// quickly drafted without worrying about any of the public inputs which aren't relevant to that circuit. Any values +// which aren't set by the circuit can then be safely set to zero when calling `set_public` (by checking for +// std::nullopt) +template class OptionalPrivateCircuitPublicInputs { typedef typename NCT::fr fr; typedef typename NCT::boolean boolean; typedef typename std::optional opt_fr; @@ -48,9 +155,9 @@ template class PrivateCircuitPublicInputs { opt_boolean pay_fee_from_public_l2; opt_boolean called_from_l1; - PrivateCircuitPublicInputs(){}; + OptionalPrivateCircuitPublicInputs(){}; - PrivateCircuitPublicInputs( + OptionalPrivateCircuitPublicInputs( std::optional> const& call_context, std::array const& custom_public_inputs, @@ -90,12 +197,12 @@ template class PrivateCircuitPublicInputs { , pay_fee_from_public_l2(pay_fee_from_public_l2) , called_from_l1(called_from_l1){}; - bool operator==(PrivateCircuitPublicInputs const&) const = default; + bool operator==(OptionalPrivateCircuitPublicInputs const&) const = default; - static PrivateCircuitPublicInputs create() + static OptionalPrivateCircuitPublicInputs create() { - auto new_inputs = PrivateCircuitPublicInputs(); + auto new_inputs = OptionalPrivateCircuitPublicInputs(); new_inputs.call_context = std::nullopt; @@ -200,9 +307,8 @@ template class PrivateCircuitPublicInputs { fr(*called_from_l1).set_public(); } - // TODO: can't use designated constructor anymore, so need to copy the to_native_type() function methodology below. template - PrivateCircuitPublicInputs> to_circuit_type(Composer& composer) const + OptionalPrivateCircuitPublicInputs> to_circuit_type(Composer& composer) const { static_assert((std::is_same::value)); @@ -212,7 +318,7 @@ template class PrivateCircuitPublicInputs { return e ? std::make_optional((*e).to_circuit_type(composer)) : std::nullopt; }; - PrivateCircuitPublicInputs> pis = { + OptionalPrivateCircuitPublicInputs> pis = { to_circuit_type(call_context), to_ct(custom_public_inputs), @@ -240,7 +346,7 @@ template class PrivateCircuitPublicInputs { return pis; }; - template PrivateCircuitPublicInputs to_native_type() const + template OptionalPrivateCircuitPublicInputs to_native_type() const { static_assert(std::is_same, NCT>::value); auto to_nt = [&](auto& e) { return plonk::stdlib::types::to_nt(e); }; @@ -249,7 +355,7 @@ template class PrivateCircuitPublicInputs { }; // auto to_native_type = [&](T& e) { return e.to_native_type(); }; - PrivateCircuitPublicInputs pis = { + OptionalPrivateCircuitPublicInputs pis = { to_native_type(call_context), to_nt(custom_public_inputs), @@ -314,6 +420,37 @@ template class PrivateCircuitPublicInputs { return NCT::compress(inputs, GeneratorIndex::PRIVATE_CIRCUIT_PUBLIC_INPUTS); } + // We can remove optionality when using the inputs in a kernel or rollup circuit, for ease of use. + PrivateCircuitPublicInputs remove_optionality() const + { + auto get_value = [&](auto& e) { return e.value(); }; + + return PrivateCircuitPublicInputs{ + .call_context = call_context.value(), + + .custom_public_inputs = map(custom_public_inputs, get_value), + .emitted_public_inputs = map(emitted_public_inputs, get_value), + + .executed_callback = executed_callback.value(), + + .output_commitments = map(output_commitments, get_value), + .input_nullifiers = map(input_nullifiers, get_value), + + .private_call_stack = map(private_call_stack, get_value), + .public_call_stack = map(public_call_stack, get_value), + .contract_deployment_call_stack = map(contract_deployment_call_stack, get_value), + .partial_l1_call_stack = map(partial_l1_call_stack, get_value), + .callback_stack = map(callback_stack, get_value), + + .old_private_data_tree_root = old_private_data_tree_root.value(), + + .is_fee_payment = is_fee_payment.value(), + .pay_fee_from_l1 = pay_fee_from_l1.value(), + .pay_fee_from_public_l2 = pay_fee_from_public_l2.value(), + .called_from_l1 = called_from_l1.value(), + }; + } + private: bool all_elements_populated = false; @@ -466,11 +603,12 @@ template class PrivateCircuitPublicInputs { } }; // namespace aztec3::circuits::abis -template void read(uint8_t const*& it, PrivateCircuitPublicInputs& private_circuit_public_inputs) +template +void read(uint8_t const*& it, OptionalPrivateCircuitPublicInputs& private_circuit_public_inputs) { using serialize::read; - PrivateCircuitPublicInputs& pis = private_circuit_public_inputs; + OptionalPrivateCircuitPublicInputs& pis = private_circuit_public_inputs; read(it, pis.call_context); read(it, pis.custom_public_inputs); read(it, pis.emitted_public_inputs); @@ -490,11 +628,11 @@ template void read(uint8_t const*& it, PrivateCircuitPublicInputs }; template -void write(std::vector& buf, PrivateCircuitPublicInputs const& private_circuit_public_inputs) +void write(std::vector& buf, OptionalPrivateCircuitPublicInputs const& private_circuit_public_inputs) { using serialize::write; - PrivateCircuitPublicInputs const& pis = private_circuit_public_inputs; + OptionalPrivateCircuitPublicInputs const& pis = private_circuit_public_inputs; write(buf, pis.call_context); write(buf, pis.custom_public_inputs); @@ -515,10 +653,10 @@ void write(std::vector& buf, PrivateCircuitPublicInputs const& pri }; template -std::ostream& operator<<(std::ostream& os, PrivateCircuitPublicInputs const& private_circuit_public_inputs) +std::ostream& operator<<(std::ostream& os, OptionalPrivateCircuitPublicInputs const& private_circuit_public_inputs) { - PrivateCircuitPublicInputs const& pis = private_circuit_public_inputs; + OptionalPrivateCircuitPublicInputs const& pis = private_circuit_public_inputs; return os << "call_context: " << pis.call_context << "\n" << "custom_public_inputs: " << pis.custom_public_inputs << "\n" << "emitted_public_inputs: " << pis.emitted_public_inputs << "\n" diff --git a/circuits/src/aztec3/circuits/abis/private_kernel/accumulated_data.hpp b/circuits/src/aztec3/circuits/abis/private_kernel/accumulated_data.hpp index 020303a25c7..1d3703cf1a0 100644 --- a/circuits/src/aztec3/circuits/abis/private_kernel/accumulated_data.hpp +++ b/circuits/src/aztec3/circuits/abis/private_kernel/accumulated_data.hpp @@ -28,6 +28,14 @@ template struct AccumulatedData { std::array output_commitments; std::array input_nullifiers; + // template + // typename CircuitTypes::boolean operator==(const AccumulatedData>& other) const { + // //AggregationObject + // { + + // } + // } + template AccumulatedData> to_circuit_type(Composer& composer) const { typedef CircuitTypes CT; diff --git a/circuits/src/aztec3/circuits/abis/private_kernel/constant_data.hpp b/circuits/src/aztec3/circuits/abis/private_kernel/constant_data.hpp index 92714c0ea1e..6ccceb19971 100644 --- a/circuits/src/aztec3/circuits/abis/private_kernel/constant_data.hpp +++ b/circuits/src/aztec3/circuits/abis/private_kernel/constant_data.hpp @@ -52,6 +52,12 @@ template struct ConstantData { executed_callback.set_public(); globals.set_public(); } + + // template void set_private_data_tree_root(typename CircuitTypes::fr const& value) + // { + // old_tree_roots.private_data_tree_root.assert_equal(0, "Cannot edit a nonzero constant."); + // old_tree_roots.private_data_tree_root = value; + // } }; } // namespace aztec3::circuits::abis::private_kernel \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp b/circuits/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp index ace4f0fccbf..f56dceb5b52 100644 --- a/circuits/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp +++ b/circuits/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp @@ -20,8 +20,8 @@ template struct PreviousKernelData { typedef typename NCT::fr fr; typedef typename NCT::VK VK; - PublicInputs public_inputs; - NativeTypes::Proof proof; // TODO: how to express proof as native/circuit type when it gets used as a buffer? + PublicInputs public_inputs; // TODO: not needed as already contained in proof? + NativeTypes::Proof proof; // TODO: how to express proof as native/circuit type when it gets used as a buffer? std::shared_ptr vk; fr vk_index; std::array vk_path; diff --git a/circuits/src/aztec3/circuits/abis/private_kernel/private_inputs.hpp b/circuits/src/aztec3/circuits/abis/private_kernel/private_inputs.hpp index 501a7ca420d..ac531c1ef00 100644 --- a/circuits/src/aztec3/circuits/abis/private_kernel/private_inputs.hpp +++ b/circuits/src/aztec3/circuits/abis/private_kernel/private_inputs.hpp @@ -18,7 +18,7 @@ template struct PrivateInputs { typedef typename NCT::fr fr; // Signature signature; // TODO! - AccumulatedData start; + // AccumulatedData start; PreviousKernelData previous_kernel; PrivateCallData private_call; @@ -28,7 +28,7 @@ template struct PrivateInputs { PrivateInputs> private_inputs = { // signature.to_circuit_type(); - start.to_circuit_type(composer), + // start.to_circuit_type(composer), previous_kernel.to_circuit_type(composer), private_call.to_circuit_type(composer), }; diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp index 1a9f44bf3e6..d18c56af18a 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp @@ -6,9 +6,9 @@ namespace aztec3::circuits::apps::test_apps::escrow { -using aztec3::circuits::abis::PrivateCircuitPublicInputs; +using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; -PrivateCircuitPublicInputs deposit( +OptionalPrivateCircuitPublicInputs deposit( Composer& composer, OracleWrapper& oracle, NT::fr const& _amount, NT::fr const& _asset_id, NT::fr const& _memo) { CT::fr amount = to_ct(composer, _amount); @@ -32,7 +32,7 @@ PrivateCircuitPublicInputs deposit( contract.finalise(); // TODO: maybe pass `oracle` to this `create()` function as well? - auto public_inputs = PrivateCircuitPublicInputs::create(); + auto public_inputs = OptionalPrivateCircuitPublicInputs::create(); public_inputs.call_context = oracle.get_call_context(); /// TODO: can this be abstracted away out of this body? diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.hpp index 51bbe0adbbb..5ed6ad05495 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.hpp @@ -4,9 +4,9 @@ namespace aztec3::circuits::apps::test_apps::escrow { -using aztec3::circuits::abis::PrivateCircuitPublicInputs; +using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; -PrivateCircuitPublicInputs deposit( +OptionalPrivateCircuitPublicInputs deposit( Composer& composer, OracleWrapper& oracle, NT::fr const& _amount, NT::fr const& _asset_id, NT::fr const& _memo); } // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp index 1122fa9b307..d5457efb5a5 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp @@ -6,7 +6,7 @@ namespace aztec3::circuits::apps::test_apps::escrow { -using aztec3::circuits::abis::PrivateCircuitPublicInputs; +using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; void transfer(Composer& composer, OracleWrapper& oracle, @@ -65,7 +65,7 @@ void transfer(Composer& composer, // Assign circuit-specific public inputs **************************************** - auto public_inputs = PrivateCircuitPublicInputs::create(); + auto public_inputs = OptionalPrivateCircuitPublicInputs::create(); public_inputs.call_context = oracle.get_call_context(); /// TODO: can this be abstracted away out of this body? diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp index b324e60f394..4e79021b178 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp @@ -8,7 +8,7 @@ namespace aztec3::circuits::apps::test_apps::escrow { -using aztec3::circuits::abis::PrivateCircuitPublicInputs; +using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; void withdraw(Composer& composer, OracleWrapper& oracle, @@ -71,7 +71,7 @@ void withdraw(Composer& composer, // Assign circuit-specific public inputs **************************************** - auto public_inputs = PrivateCircuitPublicInputs::create(); + auto public_inputs = OptionalPrivateCircuitPublicInputs::create(); public_inputs.call_context = oracle.get_call_context(); /// TODO: can this be abstracted away out of this body? diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw_failure_callback.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw_failure_callback.cpp index 713545cd2a2..1c1868df161 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw_failure_callback.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw_failure_callback.cpp @@ -6,7 +6,7 @@ namespace aztec3::circuits::apps::test_apps::escrow { -using aztec3::circuits::abis::PrivateCircuitPublicInputs; +using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; void withdraw_failure_callback(Composer& composer, OracleWrapper& oracle, @@ -37,7 +37,7 @@ void withdraw_failure_callback(Composer& composer, contract.finalise(); // TODO: maybe pass `oracle` to this `create()` function as well? - auto public_inputs = PrivateCircuitPublicInputs::create(); + auto public_inputs = OptionalPrivateCircuitPublicInputs::create(); public_inputs.call_context = oracle.get_call_context(); /// TODO: can this be abstracted away out of this body? diff --git a/circuits/src/aztec3/circuits/kernel/private/private_kernel.test.cpp b/circuits/src/aztec3/circuits/kernel/private/private_kernel.test.cpp index dfac3d22769..d24a6a0b66c 100644 --- a/circuits/src/aztec3/circuits/kernel/private/private_kernel.test.cpp +++ b/circuits/src/aztec3/circuits/kernel/private/private_kernel.test.cpp @@ -37,7 +37,7 @@ using aztec3::circuits::abis::CallStackItem; using aztec3::circuits::abis::CallType; using aztec3::circuits::abis::ExecutedCallback; using aztec3::circuits::abis::FunctionSignature; -using aztec3::circuits::abis::PrivateCircuitPublicInputs; +using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; using aztec3::circuits::abis::private_kernel::AccumulatedData; using aztec3::circuits::abis::private_kernel::ConstantData; using aztec3::circuits::abis::private_kernel::Globals; @@ -78,7 +78,7 @@ TEST(private_kernel_tests, test_deposit) auto asset_id = NT::fr(1); auto memo = NT::fr(999); - PrivateCircuitPublicInputs deposit_public_inputs = + OptionalPrivateCircuitPublicInputs deposit_public_inputs = deposit(deposit_composer, deposit_oracle_wrapper, amount, asset_id, memo); UnrolledProver deposit_prover = deposit_composer.create_unrolled_prover(); @@ -138,7 +138,7 @@ TEST(private_kernel_tests, test_deposit) // .is_constructor = false, // .is_callback = false, }, - .public_inputs = deposit_public_inputs, + .public_inputs = deposit_public_inputs.remove_optionality(), .call_context = *deposit_public_inputs.call_context, // .is_delegate_call = false, // .is_static_call = false, @@ -146,19 +146,29 @@ TEST(private_kernel_tests, test_deposit) // PrivateInputs private_inputs; PrivateInputs private_inputs = { - .start = - AccumulatedData{ - .private_call_stack = - std::array{ - deposit_call_stack_item.hash(), 0, 0, 0, 0, 0, 0, 0 } }, // AccumulatedData starts out mostly - // empty, since nothing has been - // accumulated through kernel recursion - // yet. + // .start = + // AccumulatedData{ + // .private_call_stack = + // std::array{ + // deposit_call_stack_item.hash(), 0, 0, 0, 0, 0, 0, 0 } }, // AccumulatedData starts out mostly + // // empty, since nothing has been + // // accumulated through kernel + // recursion + // // yet. .previous_kernel = PreviousKernelData{ .public_inputs = PublicInputs{ - .end = AccumulatedData{}, + .end = + AccumulatedData{ + .private_call_stack = + std::array{ + deposit_call_stack_item.hash(), 0, 0, 0, 0, 0, 0, 0 } }, // AccumulatedData + // starts out mostly + // empty, since nothing + // has been accumulated + // through kernel + // recursion yet. .constants = ConstantData{ .old_tree_roots = diff --git a/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp b/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp index 623681e6740..5f28d377546 100644 --- a/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp +++ b/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp @@ -8,27 +8,28 @@ using aztec3::circuits::abis::private_kernel::PrivateInputs; using aztec3::circuits::abis::private_kernel::PublicInputs; /** - * Checks that an array of CT::fr contains `length` contiguous nonzero values, followed by all zeroes. + * Gets the number of contiguous nonzero values of an array. * Note: this assumes `0` always means 'not used', so be careful. If you actually want `0` to be counted, you'll need * something else. */ // TODO: move to own file of helper functions. -template CT::boolean array_has_length(std::array const& arr, CT::fr const& length) +template CT::fr array_length(std::array const& arr) { - CT::fr actual_length = 0; + CT::fr length = 0; CT::boolean hit_zero = false; for (const auto& e : arr) { hit_zero |= e == 0; const CT::fr increment = !hit_zero; - actual_length += increment; + length += increment; } - return actual_length == length; + return length; }; /** * Note: doesn't remove the last element from the array; only returns it! * Note: this assumes `0` always means 'not used', so be careful. If you actually want `0` to be counted, you'll need * something else. + * If it returns `0`, the array is considered 'empty'. */ template CT::fr array_pop(std::array const& arr) { @@ -43,6 +44,22 @@ template CT::fr array_pop(std::array const& arr return popped_value; }; +/** + * Note: this assumes `0` always means 'not used', so be careful. If you actually want `0` to be counted, you'll need + * something else. + */ +template CT::boolean is_array_empty(std::array const& arr) +{ + CT::boolean nonzero_found = false; + for (size_t i = arr.size() - 1; i != (size_t)-1; i--) { + CT::boolean is_non_zero = arr[i] != 0; + nonzero_found |= is_non_zero; + } + return !nonzero_found; +}; + +// TODO: NEED TO RECONCILE THE `proof`'s public inputs (which are uint8's) with the +// private_call.call_stack_item.public_inputs! CT::AggregationObject verify_proofs(Composer& composer, PrivateInputs const& private_inputs, size_t const& num_private_call_public_inputs, @@ -61,53 +78,183 @@ CT::AggregationObject verify_proofs(Composer& composer, void validate_private_call_hash(PrivateInputs const& private_inputs) { - const auto private_call_hash = array_pop(private_inputs.start.private_call_stack); + const auto& start = private_inputs.previous_kernel.public_inputs.end; + const auto private_call_hash = array_pop(start.private_call_stack); const auto calculated_private_call_hash = private_inputs.private_call.call_stack_item.hash(); private_call_hash.assert_equal(calculated_private_call_hash, "private_call_hash does not reconcile"); }; -// using abis::private_kernel::PublicInputs; -CT::boolean base_case(PrivateInputs const& private_inputs, PublicInputs& public_inputs) +void ensure_consistency_between_kernels(PrivateInputs const& private_inputs, PublicInputs& public_inputs) +{ + public_inputs.constants = private_inputs.previous_kernel.public_inputs.constants; + + // Ensure the arrays are the same as previously, before we start pushing more data onto them: + auto& end = public_inputs.end; + const auto& start = private_inputs.previous_kernel.public_inputs.end; + + end.private_call_stack = start.private_call_stack; + end.public_call_stack = start.public_call_stack; + end.contract_deployment_call_stack = start.contract_deployment_call_stack; + end.l1_call_stack = start.l1_call_stack; + end.callback_stack = start.callback_stack; + end.optionally_revealed_data = start.optionally_revealed_data; + end.output_commitments = start.output_commitments; + end.input_nullifiers = start.input_nullifiers; +} + +void validate_inputs(PrivateInputs const& private_inputs, PublicInputs& public_inputs) { - const auto& start = private_inputs.start; + private_inputs.private_call.call_stack_item.function_signature.is_private.assert_equal( + true, "Cannot execute a non-private function with the private kernel circuit"); + + const auto& start = private_inputs.previous_kernel.public_inputs.end; + const CT::boolean is_base_case = start.private_call_count == 0; + const CT::boolean is_recursive_case = !is_base_case; - is_base_case.must_imply( - array_has_length(start.private_call_stack, 1) // TODO: might change to allow 2, so a fee can be paid. - && array_has_length(start.public_call_stack, 0) && - array_has_length(start.contract_deployment_call_stack, 0) && array_has_length(start.l1_call_stack, 0), - "Invalid arrays for base case."); + CT::fr start_private_call_stack_length = array_length(start.private_call_stack); + CT::fr start_public_call_stack_length = array_length(start.public_call_stack); + CT::fr start_contract_deployment_call_stack_length = array_length(start.contract_deployment_call_stack); + CT::fr start_l1_call_stack_length = array_length(start.l1_call_stack); - // If we know the length, we can pick an exact index, rather than `pop`: - // const auto& private_call_hash = start.private_call_stack[0]; - const auto& private_call = private_inputs.private_call; + { + is_base_case.must_imply(start_private_call_stack_length == + 1 // TODO: might change to allow 2, so a fee can be paid. + && start_public_call_stack_length == 0 && + start_contract_deployment_call_stack_length == 0 && start_l1_call_stack_length == 0, + "Invalid arrays for base case."); - public_inputs.constants.is_constructor_recursion = CT::boolean::conditional_assign( - is_base_case, - private_inputs.private_call.call_stack_item.function_signature.is_constructor, - private_inputs.previous_kernel.public_inputs.constants.is_constructor_recursion); + is_base_case.must_imply(private_inputs.private_call.call_stack_item.is_delegate_call == false && + private_inputs.private_call.call_stack_item.is_static_call == false, + "A user cannot make a delegatecall or staticcall"); - public_inputs.constants.is_callback_recursion = - CT::boolean::conditional_assign(is_base_case, - private_inputs.private_call.call_stack_item.function_signature.is_callback, - private_inputs.previous_kernel.public_inputs.constants.is_callback_recursion); + // The below also prevents delegatecall/staticcall + is_base_case.must_imply(private_inputs.private_call.call_stack_item.call_context.storage_contract_address == + private_inputs.private_call.call_stack_item.function_signature.contract_address, + "Storage contract address must be that of the called contract in the base case"); - // TODO: Verify the ECDSA signature! + // TODO: privatelyExecutedCallback logic and checks + } - is_base_case.must_imply(private_call.call_stack_item.is_delegate_call == false && - private_call.call_stack_item.is_static_call == false, - "A user cannot make a delegatecall or staticcall"); + { + is_recursive_case.must_imply(private_inputs.previous_kernel.public_inputs.is_private == true, + "Cannot verify a non-private kernel snark in the private kernel circuit"); + is_recursive_case.must_imply(private_inputs.private_call.call_stack_item.function_signature.is_callback == + false, + "A callback must be executed as the first tx in the recursion"); + is_recursive_case.must_imply(private_inputs.private_call.call_stack_item.function_signature.is_constructor == + false, + "A constructor must be executed as the first tx in the recursion"); + is_recursive_case.must_imply(start_private_call_stack_length != 0); + } - // The below also prevents delegatecall/staticcall - is_base_case.must_imply(private_call.call_stack_item.call_context.storage_contract_address == - private_call.call_stack_item.function_signature.contract_address, - "Storage contract address must be that of the called contract in the base case"); + ensure_consistency_between_kernels(private_inputs, public_inputs); + validate_private_call_hash(private_inputs); - // TODO: privatelyExecutedCallback logic and checks + // TODO: need to make this assertion somewhere, or only have call_context exist in one of these places (it _has_ to + // be in the private_inputs.private_call.call_stack_item.public_inputs... and actually, when making a call, I think + // it has to be in the call_stack_item, since the public inputs of the thing being called aren't known yet... so it + // has to be in both places!!!)! - return is_base_case; -}; + (private_inputs.private_call.call_stack_item.call_context == + private_inputs.private_call.call_stack_item.public_inputs.call_context) + .assert_equal(true, "Call context mismatches"); +} + +/** + * Inserts the `source` array at the first zero-valued index of the `target` array. + * Fails if the `source` array is too large vs the remaining capacity of the `target` array. + */ +template +void push_array_to_array(std::array const& source, std::array& target) +{ + CT::fr target_length = array_length(target); + CT::fr source_length = array_length(source); + + CT::fr target_capacity = CT::fr(target.size()); + // TODO: using safe_fr for an underflow check, do: + // remaining_target_capacity = target_capacity.subtract(target_length + source_length); + + CT::fr t_i = 0; + CT::fr next_index = target_length; + for (const auto& s : source) { + for (auto& t : target) { + next_index.assert_not_equal(target_capacity, "Target array capacity exceeded"); + CT::boolean at_index = t_i == next_index; + t = CT::fr::conditional_assign(at_index, s, t); + next_index = CT::fr::conditional_assign(at_index, next_index + 1, next_index); + ++t_i; + } + } +} + +void update_end_values(PrivateInputs const& private_inputs, PublicInputs& public_inputs) +{ + const auto private_call_public_inputs = private_inputs.private_call.call_stack_item.public_inputs; + + const auto& output_commitments = private_call_public_inputs.output_commitments; + const auto& input_nullifiers = private_call_public_inputs.input_nullifiers; + + const auto& is_static_call = private_inputs.private_call.call_stack_item.is_static_call; + + // No state changes are allowed for static calls: + is_static_call.must_imply(is_array_empty(output_commitments) == true); + is_static_call.must_imply(is_array_empty(input_nullifiers) == true); + + const auto& storage_contract_address = + private_inputs.private_call.call_stack_item.call_context.storage_contract_address; + + { // commitments & nullifiers + std::array siloed_output_commitments; + for (size_t i = 0; i < output_commitments.size(); ++i) { + siloed_output_commitments[i] = + CT::fr::conditional_assign(output_commitments[i] == 0, + 0, + CT::compress({ storage_contract_address.to_field(), output_commitments[i] }, + GeneratorIndex::OUTER_COMMITMENT)); + } + std::array siloed_input_nullifiers; + for (size_t i = 0; i < input_nullifiers.size(); ++i) { + siloed_input_nullifiers[i] = + CT::fr::conditional_assign(input_nullifiers[i] == 0, + 0, + CT::compress({ storage_contract_address.to_field(), input_nullifiers[i] }, + GeneratorIndex::OUTER_NULLIFIER)); + } + + push_array_to_array(siloed_output_commitments, public_inputs.end.output_commitments); + push_array_to_array(siloed_input_nullifiers, public_inputs.end.input_nullifiers); + } + + { + // TODO: we need to pass in UNPACKED stack data. I.e. the preimages of the call_stack_item hashes, so that data + // in the stack can be validated as being correct. (e.g. call_contexts of calls made by the public_call + // currently being validated). + + // So we'll need to ensure our test_apps return not only a PrivateCircuitPublicInputs object, but also an object + // containing a TONNE of preimage data. Stuff like: + // - Stack item preimages + // - Commitment and nullifier preimages + // - Hash paths and leaf indices + // - Any and all preimage data derived by the circuit or through oracle calls. + } + + const auto& portal_contract_address = private_inputs.private_call.portal_contract_address; + + { + const auto& partial_l1_call_stack = private_call_public_inputs.partial_l1_call_stack; + std::array l1_call_stack; + + for (size_t i = 0; i < partial_l1_call_stack.size(); ++i) { + l1_call_stack[i] = + CT::fr::conditional_assign(partial_l1_call_stack[i] == 0, + 0, + CT::compress({ portal_contract_address, partial_l1_call_stack[i] }, + GeneratorIndex::L1_CALL_STACK_ITEM)); + } + } +} // TODO: decide what to return. void private_kernel_circuit(Composer& composer, OracleWrapper& oracle, PrivateInputs const& _private_inputs) @@ -115,32 +262,33 @@ void private_kernel_circuit(Composer& composer, OracleWrapper& oracle, PrivateIn const PrivateInputs private_inputs = _private_inputs.to_circuit_type(composer); PublicInputs public_inputs; - private_inputs.private_call.call_stack_item.function_signature.is_private.assert_equal( - true, "Cannot execute a non-private function with the private kernel circuit"); + const auto& start = private_inputs.previous_kernel.public_inputs.end; + + const CT::boolean is_base_case = start.private_call_count == 0; + // const CT::boolean is_recursive_case = !is_base_case; + + validate_inputs(private_inputs, public_inputs); auto aggregation_object = verify_proofs(composer, private_inputs, _private_inputs.private_call.vk->num_public_inputs, _private_inputs.previous_kernel.vk->num_public_inputs); - validate_private_call_hash(private_inputs); - - const CT::boolean is_base_case = base_case(private_inputs, public_inputs); - - const CT::boolean is_recursive_case = !is_base_case; - - is_recursive_case.must_imply(private_inputs.previous_kernel.public_inputs.is_private == true, - "Cannot verify a non-private kernel snark in the private kernel circuit"); - is_recursive_case.must_imply(private_inputs.private_call.call_stack_item.function_signature.is_callback == false, - "A callback must be executed as the first tx in the recursion"); - is_recursive_case.must_imply(private_inputs.private_call.call_stack_item.function_signature.is_constructor == false, - "A constructor must be executed as the first tx in the recursion"); - // TODO: kernel vk membership check! // This line is just to stop the compiler complaining about `oracle` being unused whilst building. oracle.generate_random_element().assert_is_not_zero(); + public_inputs.constants.is_constructor_recursion = CT::boolean::conditional_assign( + is_base_case, + private_inputs.private_call.call_stack_item.function_signature.is_constructor, + private_inputs.previous_kernel.public_inputs.constants.is_constructor_recursion); + + public_inputs.constants.is_callback_recursion = + CT::boolean::conditional_assign(is_base_case, + private_inputs.private_call.call_stack_item.function_signature.is_callback, + private_inputs.previous_kernel.public_inputs.constants.is_callback_recursion); + public_inputs.end.aggregation_object = aggregation_object; // public_inputs.set_public(); diff --git a/circuits/src/aztec3/constants.hpp b/circuits/src/aztec3/constants.hpp index 019fa721c32..80df2420321 100644 --- a/circuits/src/aztec3/constants.hpp +++ b/circuits/src/aztec3/constants.hpp @@ -47,10 +47,12 @@ enum GeneratorIndex { FUNCTION_SIGNATURE, CALL_ARGS, EXECUTED_CALLBACK, - L1_RESULT_PLACEHOLDER, CALL_CONTEXT, CALL_STACK_ITEM, CALLBACK_STACK_ITEM, + PARTIAL_L1_CALL_STACK_ITEM, + L1_CALL_STACK_ITEM, + L1_RESULT_PLACEHOLDER, PRIVATE_CIRCUIT_PUBLIC_INPUTS, PUBLIC_CIRCUIT_PUBLIC_INPUTS, }; From 4ccd33c2070ab532bb9f6d7ca930fb1221b12f24 Mon Sep 17 00:00:00 2001 From: iAmMichaelConnor Date: Tue, 14 Jun 2022 10:36:52 +0000 Subject: [PATCH 007/166] move more bools to call_context --- .../src/aztec3/circuits/abis/abis.test.cpp | 4 - .../src/aztec3/circuits/abis/call_context.hpp | 78 ++++++++++++++-- .../circuits/abis/function_signature.hpp | 18 ++-- .../abis/optionally_revealed_data.hpp | 9 +- .../abis/private_circuit_public_inputs.hpp | 88 +------------------ .../abis/private_kernel/accumulated_data.hpp | 8 -- circuits/src/aztec3/circuits/apps/README.md | 55 ++++++------ .../aztec3/circuits/apps/contract_factory.hpp | 4 - .../src/aztec3/circuits/apps/l1_promise.tpp | 27 +++--- .../aztec3/circuits/apps/oracle_wrapper.hpp | 8 +- .../circuits/apps/private_state_var.hpp | 7 +- .../apps/test_apps/escrow/constants.hpp | 25 ------ .../apps/test_apps/escrow/contract.hpp | 2 +- .../apps/test_apps/escrow/deposit.cpp | 7 -- .../apps/test_apps/escrow/escrow.test.cpp | 22 +++-- .../apps/test_apps/escrow/transfer.cpp | 7 +- .../apps/test_apps/escrow/transfer.hpp | 3 +- .../apps/test_apps/escrow/withdraw.cpp | 7 +- .../apps/test_apps/escrow/withdraw.hpp | 3 +- .../escrow/withdraw_failure_callback.cpp | 4 - .../kernel/private/private_kernel_circuit.cpp | 5 +- circuits/src/aztec3/oracle/oracle.hpp | 40 ++++++++- 22 files changed, 198 insertions(+), 233 deletions(-) delete mode 100644 circuits/src/aztec3/circuits/apps/test_apps/escrow/constants.hpp diff --git a/circuits/src/aztec3/circuits/abis/abis.test.cpp b/circuits/src/aztec3/circuits/abis/abis.test.cpp index da25c526960..c219b9246d2 100644 --- a/circuits/src/aztec3/circuits/abis/abis.test.cpp +++ b/circuits/src/aztec3/circuits/abis/abis.test.cpp @@ -20,7 +20,6 @@ TEST(abi_tests, test_native_function_signature) .vk_index = 11, .is_private = false, .is_constructor = false, - .is_callback = false, }; info("function signature: ", function_signature); @@ -38,7 +37,6 @@ TEST(abi_tests, test_native_to_circuit_function_signature) .vk_index = 11, .is_private = false, .is_constructor = false, - .is_callback = false, }; info("function signature: ", native_function_signature); @@ -142,7 +140,6 @@ TEST(abi_tests, test_native_call_stack_item) .vk_index = 11, .is_private = false, .is_constructor = false, - .is_callback = false, }, .public_inputs = public_inputs, .call_context = { @@ -179,7 +176,6 @@ TEST(abi_tests, test_native_to_circuit_call_stack_item) .vk_index = 11, .is_private = false, .is_constructor = false, - .is_callback = false, }, .public_inputs = public_inputs, .call_context = { diff --git a/circuits/src/aztec3/circuits/abis/call_context.hpp b/circuits/src/aztec3/circuits/abis/call_context.hpp index ba4fb1c38a1..db4f95a2329 100644 --- a/circuits/src/aztec3/circuits/abis/call_context.hpp +++ b/circuits/src/aztec3/circuits/abis/call_context.hpp @@ -21,12 +21,23 @@ template struct CallContext { address msg_sender; address storage_contract_address; + boolean is_delegate_call; + boolean is_static_call; + + boolean is_callback; + + boolean is_fee_payment; + boolean pay_fee_from_l1; + boolean pay_fee_from_public_l2; + boolean called_from_l1; + boolean called_from_public_l2; + boolean operator==(CallContext const& other) const { return msg_sender == other.msg_sender && storage_contract_address == other.storage_contract_address; }; - static CallContext empty() { return { 0, 0 }; }; + static CallContext empty() { return { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; }; template CallContext> to_circuit_type(Composer& composer) const { @@ -36,8 +47,12 @@ template struct CallContext { auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; CallContext> call_context = { - to_ct(msg_sender), - to_ct(storage_contract_address), + to_ct(msg_sender), to_ct(storage_contract_address), + to_ct(is_delegate_call), to_ct(is_static_call), + to_ct(is_callback), to_ct(is_fee_payment), + to_ct(pay_fee_from_l1), to_ct(pay_fee_from_public_l2), + to_ct(called_from_l1), to_ct(called_from_public_l2), + }; return call_context; @@ -49,8 +64,11 @@ template struct CallContext { auto to_nt = [&](auto& e) { return plonk::stdlib::types::to_nt(e); }; CallContext call_context = { - to_nt(msg_sender), - to_nt(storage_contract_address), + to_nt(msg_sender), to_nt(storage_contract_address), + to_nt(is_delegate_call), to_nt(is_static_call), + to_nt(is_callback), to_nt(is_fee_payment), + to_nt(pay_fee_from_l1), to_nt(pay_fee_from_public_l2), + to_nt(called_from_l1), to_nt(called_from_public_l2), }; return call_context; @@ -59,8 +77,11 @@ template struct CallContext { fr hash() const { std::vector inputs = { - msg_sender.to_field(), - storage_contract_address.to_field(), + msg_sender.to_field(), storage_contract_address.to_field(), + fr(is_delegate_call), fr(is_static_call), + fr(is_callback), fr(is_fee_payment), + fr(pay_fee_from_l1), fr(pay_fee_from_public_l2), + fr(called_from_l1), fr(called_from_public_l2), }; return NCT::compress(inputs, GeneratorIndex::CALL_CONTEXT); @@ -72,6 +93,14 @@ template struct CallContext { msg_sender.to_field().assert_is_zero(); storage_contract_address.to_field().assert_is_zero(); + fr(is_delegate_call).assert_is_zero(); + fr(is_static_call).assert_is_zero(); + fr(is_callback).assert_is_zero(); + fr(is_fee_payment).assert_is_zero(); + fr(pay_fee_from_l1).assert_is_zero(); + fr(pay_fee_from_public_l2).assert_is_zero(); + fr(called_from_l1).assert_is_zero(); + fr(called_from_public_l2).assert_is_zero(); } void set_public() @@ -80,6 +109,14 @@ template struct CallContext { msg_sender.to_field().set_public(); storage_contract_address.to_field().set_public(); + fr(is_delegate_call).set_public(); + fr(is_static_call).set_public(); + fr(is_callback).set_public(); + fr(is_fee_payment).set_public(); + fr(pay_fee_from_l1).set_public(); + fr(pay_fee_from_public_l2).set_public(); + fr(called_from_l1).set_public(); + fr(called_from_public_l2).set_public(); } }; @@ -89,6 +126,14 @@ template void read(uint8_t const*& it, CallContext& call_con read(it, call_context.msg_sender); read(it, call_context.storage_contract_address); + read(it, call_context.is_delegate_call); + read(it, call_context.is_static_call); + read(it, call_context.is_callback); + read(it, call_context.is_fee_payment); + read(it, call_context.pay_fee_from_l1); + read(it, call_context.pay_fee_from_public_l2); + read(it, call_context.called_from_l1); + read(it, call_context.called_from_public_l2); }; template void write(std::vector& buf, CallContext const& call_context) @@ -97,12 +142,29 @@ template void write(std::vector& buf, CallContext c write(buf, call_context.msg_sender); write(buf, call_context.storage_contract_address); + write(buf, call_context.is_delegate_call); + write(buf, call_context.is_static_call); + write(buf, call_context.is_callback); + write(buf, call_context.is_fee_payment); + write(buf, call_context.pay_fee_from_l1); + write(buf, call_context.pay_fee_from_public_l2); + write(buf, call_context.called_from_l1); + write(buf, call_context.called_from_public_l2); }; template std::ostream& operator<<(std::ostream& os, CallContext const& call_context) { return os << "msg_sender: " << call_context.msg_sender << "\n" - << "storage_contract_address: " << call_context.storage_contract_address << "\n"; + << "storage_contract_address: " << call_context.storage_contract_address << "\n" + << "storage_contract_address: " << call_context.storage_contract_address << "\n" + << "is_delegate_call: " << call_context.is_delegate_call << "\n" + << "is_static_call: " << call_context.is_static_call << "\n" + << "is_callback: " << call_context.is_callback << "\n" + << "is_fee_payment: " << call_context.is_fee_payment << "\n" + << "pay_fee_from_l1: " << call_context.pay_fee_from_l1 << "\n" + << "pay_fee_from_public_l2: " << call_context.pay_fee_from_public_l2 << "\n" + << "called_from_l1: " << call_context.called_from_l1 << "\n" + << "called_from_public_l2: " << call_context.called_from_public_l2 << "\n"; } } // namespace aztec3::circuits::abis \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/abis/function_signature.hpp b/circuits/src/aztec3/circuits/abis/function_signature.hpp index f6d3931100d..e8621487dac 100644 --- a/circuits/src/aztec3/circuits/abis/function_signature.hpp +++ b/circuits/src/aztec3/circuits/abis/function_signature.hpp @@ -24,8 +24,6 @@ template struct FunctionSignature { uint32 vk_index; boolean is_private = false; boolean is_constructor = false; - boolean is_callback = false; // TODO: move this to be with is_delegate_call and is_static_call, since it's a runtime - // bool, rather than a constant property of the function. bool operator==(FunctionSignature const&) const = default; @@ -39,7 +37,10 @@ template struct FunctionSignature { auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; FunctionSignature> function_signature = { - to_ct(contract_address), to_ct(vk_index), to_ct(is_private), to_ct(is_constructor), to_ct(is_callback), + to_ct(contract_address), + to_ct(vk_index), + to_ct(is_private), + to_ct(is_constructor), }; return function_signature; @@ -53,13 +54,15 @@ template struct FunctionSignature { fr(vk_index).set_public(); fr(is_private).set_public(); fr(is_constructor).set_public(); - fr(is_callback).set_public(); } fr hash() const { std::vector inputs = { - contract_address.to_field(), fr(vk_index), fr(is_private), fr(is_constructor), fr(is_callback), + contract_address.to_field(), + fr(vk_index), + fr(is_private), + fr(is_constructor), }; return NCT::compress(inputs, GeneratorIndex::FUNCTION_SIGNATURE); @@ -74,7 +77,6 @@ template void read(uint8_t const*& it, FunctionSignature& fu read(it, function_signature.vk_index); read(it, function_signature.is_private); read(it, function_signature.is_constructor); - read(it, function_signature.is_callback); }; template void write(std::vector& buf, FunctionSignature const& function_signature) @@ -85,7 +87,6 @@ template void write(std::vector& buf, FunctionSignature< write(buf, function_signature.vk_index); write(buf, function_signature.is_private); write(buf, function_signature.is_constructor); - write(buf, function_signature.is_callback); }; template std::ostream& operator<<(std::ostream& os, FunctionSignature const& function_signature) @@ -93,8 +94,7 @@ template std::ostream& operator<<(std::ostream& os, FunctionSigna return os << "contract_address: " << function_signature.contract_address << "\n" << "vk_index: " << function_signature.vk_index << "\n" << "is_private: " << function_signature.is_private << "\n" - << "is_constructor: " << function_signature.is_constructor << "\n" - << "is_callback: " << function_signature.is_callback << "\n"; + << "is_constructor: " << function_signature.is_constructor << "\n"; } } // namespace aztec3::circuits::abis \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/abis/optionally_revealed_data.hpp b/circuits/src/aztec3/circuits/abis/optionally_revealed_data.hpp index c77b703567c..350b0438c23 100644 --- a/circuits/src/aztec3/circuits/abis/optionally_revealed_data.hpp +++ b/circuits/src/aztec3/circuits/abis/optionally_revealed_data.hpp @@ -20,7 +20,10 @@ template struct OptionallyRevealedData { std::array emitted_public_inputs; fr vk_hash; fr portal_contract_address; // an ETH address - // BOOLS TOO! + boolean pay_fee_from_l1; + boolean pay_fee_from_public_l2; + boolean called_from_l1; + boolean called_from_public_l2; template OptionallyRevealedData> to_circuit_type(Composer& composer) const @@ -33,7 +36,9 @@ template struct OptionallyRevealedData { OptionallyRevealedData> data = { to_ct(call_stack_item_hash), function_signature.to_circuit_type(composer), to_ct(emitted_public_inputs), to_ct(vk_hash), - to_ct(portal_contract_address), + to_ct(portal_contract_address), to_ct(pay_fee_from_l1), + to_ct(pay_fee_from_public_l2), to_ct(called_from_l1), + to_ct(called_from_public_l2), }; return data; diff --git a/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp b/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp index a388bbaaf31..77fb22bfaf9 100644 --- a/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp +++ b/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp @@ -40,11 +40,6 @@ template class PrivateCircuitPublicInputs { fr old_private_data_tree_root; - boolean is_fee_payment; - boolean pay_fee_from_l1; - boolean pay_fee_from_public_l2; - boolean called_from_l1; - template PrivateCircuitPublicInputs> to_circuit_type(Composer& composer) const { @@ -72,11 +67,6 @@ template class PrivateCircuitPublicInputs { map(callback_stack, to_circuit_type), to_ct(old_private_data_tree_root), - - to_ct(is_fee_payment), - to_ct(pay_fee_from_l1), - to_ct(pay_fee_from_public_l2), - to_ct(called_from_l1), }; return pis; @@ -106,11 +96,6 @@ template class PrivateCircuitPublicInputs { inputs.push_back(old_private_data_tree_root); - inputs.push_back(fr(is_fee_payment)); - inputs.push_back(fr(pay_fee_from_l1)); - inputs.push_back(fr(pay_fee_from_public_l2)); - inputs.push_back(fr(called_from_l1)); - return NCT::compress(inputs, GeneratorIndex::PRIVATE_CIRCUIT_PUBLIC_INPUTS); } @@ -150,11 +135,6 @@ template class OptionalPrivateCircuitPublicInputs { opt_fr old_private_data_tree_root; - opt_boolean is_fee_payment; - opt_boolean pay_fee_from_l1; - opt_boolean pay_fee_from_public_l2; - opt_boolean called_from_l1; - OptionalPrivateCircuitPublicInputs(){}; OptionalPrivateCircuitPublicInputs( @@ -174,12 +154,7 @@ template class OptionalPrivateCircuitPublicInputs { std::array const& partial_l1_call_stack, std::array>, CALLBACK_STACK_LENGTH> const& callback_stack, - opt_fr const& old_private_data_tree_root, - - opt_boolean const& is_fee_payment, - opt_boolean const& pay_fee_from_l1, - opt_boolean const& pay_fee_from_public_l2, - opt_boolean const& called_from_l1) + opt_fr const& old_private_data_tree_root) : call_context(call_context) , custom_public_inputs(custom_public_inputs) , emitted_public_inputs(emitted_public_inputs) @@ -191,11 +166,7 @@ template class OptionalPrivateCircuitPublicInputs { , contract_deployment_call_stack(contract_deployment_call_stack) , partial_l1_call_stack(partial_l1_call_stack) , callback_stack(callback_stack) - , old_private_data_tree_root(old_private_data_tree_root) - , is_fee_payment(is_fee_payment) - , pay_fee_from_l1(pay_fee_from_l1) - , pay_fee_from_public_l2(pay_fee_from_public_l2) - , called_from_l1(called_from_l1){}; + , old_private_data_tree_root(old_private_data_tree_root){}; bool operator==(OptionalPrivateCircuitPublicInputs const&) const = default; @@ -267,11 +238,6 @@ template class OptionalPrivateCircuitPublicInputs { make_unused_element_zero(composer, old_private_data_tree_root); - make_unused_element_zero(composer, is_fee_payment); - make_unused_element_zero(composer, pay_fee_from_l1); - make_unused_element_zero(composer, pay_fee_from_public_l2); - make_unused_element_zero(composer, called_from_l1); - all_elements_populated = true; } @@ -300,11 +266,6 @@ template class OptionalPrivateCircuitPublicInputs { set_array_public(callback_stack); (*old_private_data_tree_root).set_public(); - - fr(*is_fee_payment).set_public(); - fr(*pay_fee_from_l1).set_public(); - fr(*pay_fee_from_public_l2).set_public(); - fr(*called_from_l1).set_public(); } template @@ -336,11 +297,6 @@ template class OptionalPrivateCircuitPublicInputs { map(callback_stack, to_circuit_type), to_ct(old_private_data_tree_root), - - to_ct(is_fee_payment), - to_ct(pay_fee_from_l1), - to_ct(pay_fee_from_public_l2), - to_ct(called_from_l1), }; return pis; @@ -373,11 +329,6 @@ template class OptionalPrivateCircuitPublicInputs { map(callback_stack, to_native_type), to_nt(old_private_data_tree_root), - - to_nt(is_fee_payment), - to_nt(pay_fee_from_l1), - to_nt(pay_fee_from_public_l2), - to_nt(called_from_l1), }; return pis; @@ -412,11 +363,6 @@ template class OptionalPrivateCircuitPublicInputs { inputs.push_back(*old_private_data_tree_root); - inputs.push_back(fr(*is_fee_payment)); - inputs.push_back(fr(*pay_fee_from_l1)); - inputs.push_back(fr(*pay_fee_from_public_l2)); - inputs.push_back(fr(*called_from_l1)); - return NCT::compress(inputs, GeneratorIndex::PRIVATE_CIRCUIT_PUBLIC_INPUTS); } @@ -443,11 +389,6 @@ template class OptionalPrivateCircuitPublicInputs { .callback_stack = map(callback_stack, get_value), .old_private_data_tree_root = old_private_data_tree_root.value(), - - .is_fee_payment = is_fee_payment.value(), - .pay_fee_from_l1 = pay_fee_from_l1.value(), - .pay_fee_from_public_l2 = pay_fee_from_public_l2.value(), - .called_from_l1 = called_from_l1.value(), }; } @@ -575,17 +516,6 @@ template class OptionalPrivateCircuitPublicInputs { } } - // template - // void make_unused_element_zero(Composer& composer, std::optional>>& element) - // { - // static_assert((std::is_same, NCT>::value)); - - // if (!element) { - // element = CallContext::empty().to_circuit_type(composer); - // (*element).template assert_is_zero(); - // } - // } - // Make sure this is only called by functions which have implemented a "CT only" check. template void set_array_public(std::array, SIZE>& arr) { @@ -621,10 +551,6 @@ void read(uint8_t const*& it, OptionalPrivateCircuitPublicInputs& private_c read(it, pis.partial_l1_call_stack); read(it, pis.callback_stack); read(it, pis.old_private_data_tree_root); - read(it, pis.is_fee_payment); - read(it, pis.pay_fee_from_l1); - read(it, pis.pay_fee_from_public_l2); - read(it, pis.called_from_l1); }; template @@ -646,10 +572,6 @@ void write(std::vector& buf, OptionalPrivateCircuitPublicInputs co write(buf, pis.partial_l1_call_stack); write(buf, pis.callback_stack); write(buf, pis.old_private_data_tree_root); - write(buf, pis.is_fee_payment); - write(buf, pis.pay_fee_from_l1); - write(buf, pis.pay_fee_from_public_l2); - write(buf, pis.called_from_l1); }; template @@ -668,11 +590,7 @@ std::ostream& operator<<(std::ostream& os, OptionalPrivateCircuitPublicInputs struct AccumulatedData { std::array output_commitments; std::array input_nullifiers; - // template - // typename CircuitTypes::boolean operator==(const AccumulatedData>& other) const { - // //AggregationObject - // { - - // } - // } - template AccumulatedData> to_circuit_type(Composer& composer) const { typedef CircuitTypes CT; diff --git a/circuits/src/aztec3/circuits/apps/README.md b/circuits/src/aztec3/circuits/apps/README.md index b03139ecb08..c7120db64c5 100644 --- a/circuits/src/aztec3/circuits/apps/README.md +++ b/circuits/src/aztec3/circuits/apps/README.md @@ -14,31 +14,32 @@ All code in this dir is for: This is some complex code, which attempts to abstract-away stuff to do with creating commitments, nullifiers, and Aztec3 public input ABIs. All that, so that test app circuits can be mocked-up without too much faff. Some explanation is needed: ``` -private_state_factory - |___private_state_vars - | |___private_state_var (fr state) - | |___private_state_var (mapping state) - | |___private_state_var (fr state) - | |... - | |___private_state_var (fr state) - | ___________________| - | | fr states can creates notes - | v - |___private_state_notes - | |___private_state_note - | |___private_state_note_preimage - | | - | |___ preimage members are std::optional - | so that partial commitments can be - | created in one tx, and completed in - | a later tx. - | - |___commitments - |___nullifiers once all notes have been created by the circuit, we can - `finalise()` the state_factory. This will figure out whether - we need more: - - dummy nullifiers (to use as input_nullifiers to - commitments). - Only at this stage are the commitments (and partial commitments) - and nullifiers computed. +contract_factory + |___private_state_factory + |___private_state_vars + | |___private_state_var (fr state) + | |___private_state_var (mapping state) + | |___private_state_var (fr state) + | |... + | |___private_state_var (fr state) + | ___________________| + | | fr states can creates notes + | v + |___private_state_notes + | |___private_state_note + | |___private_state_note_preimage + | | + | |___ preimage members are std::optional + | so that partial commitments can be + | created in one tx, and completed in + | a later tx. + | + |___commitments + |___nullifiers once all notes have been created by the circuit, we can + `finalise()` the state_factory. This will figure out whether + we need more: + - dummy nullifiers (to use as input_nullifiers to + commitments). + Only at this stage are the commitments (and partial commitments) + and nullifiers computed. ``` \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/contract_factory.hpp b/circuits/src/aztec3/circuits/apps/contract_factory.hpp index e1acd43ceb6..367766fbb4c 100644 --- a/circuits/src/aztec3/circuits/apps/contract_factory.hpp +++ b/circuits/src/aztec3/circuits/apps/contract_factory.hpp @@ -60,10 +60,6 @@ template class ContractFactory { return function_signatures[name]; } - // FunctionSignature> get_function_signature_by_name(std::string const& name) { - - // } - void import_l1_function(L1FunctionStruct const& l1_function_struct) { L1Function l1_function = L1Function(this, l1_function_struct); diff --git a/circuits/src/aztec3/circuits/apps/l1_promise.tpp b/circuits/src/aztec3/circuits/apps/l1_promise.tpp index 818ed7c3686..6a62ab2fa4f 100644 --- a/circuits/src/aztec3/circuits/apps/l1_promise.tpp +++ b/circuits/src/aztec3/circuits/apps/l1_promise.tpp @@ -21,10 +21,7 @@ void L1Promise::on_success(std::string const& function_name, std::vector> const& args) { // construct success_callback_call_hash and success_result_arg_map_acc - auto& oracle = contract_factory.oracle; - - auto function_signature = contract_factory.get_function_signature_by_name(function_name); - function_signature.is_callback = true; + // auto& oracle = contract_factory.oracle; std::vector> arg_input_pairs; @@ -43,14 +40,15 @@ void L1Promise::on_success(std::string const& function_name, // TODO: do this calc in the CallStackItem struct instead, once we know whether we can simply hash args instead of // the whole set of public inputs. + + auto function_signature = contract_factory.get_function_signature_by_name(function_name); + fr function_signature_hash = function_signature.hash(); fr arg_hash = CT::compress(arg_input_pairs); - fr call_context_hash = oracle.get_call_context().hash(); - boolean is_delegate_call = false; - boolean is_static_call = false; std::vector success_callback_call_hash_inputs = { - function_signature_hash, arg_hash, call_context_hash, fr(is_delegate_call), fr(is_static_call), + function_signature_hash, + arg_hash, }; callback_stack_item.success_callback_call_hash = @@ -61,10 +59,7 @@ template void L1Promise::on_failure(std::string const& function_name, std::vector const& args) { // construct failure_callback_call_hash - auto& oracle = contract_factory.oracle; - - auto function_signature = contract_factory.get_function_signature_by_name(function_name); - function_signature.is_callback = true; + // auto& oracle = contract_factory.oracle; std::vector> arg_input_pairs; @@ -74,14 +69,14 @@ void L1Promise::on_failure(std::string const& function_name, std::vect // TODO: do this calc in the CallStackItem struct instead, once we know whether we can simply hash args instead of // the whole set of public inputs. + auto function_signature = contract_factory.get_function_signature_by_name(function_name); + fr function_signature_hash = function_signature.hash(); fr arg_hash = CT::compress(arg_input_pairs); - fr call_context_hash = oracle.get_call_context().hash(); - boolean is_delegate_call = false; - boolean is_static_call = false; std::vector failure_callback_call_hash_inputs = { - function_signature_hash, arg_hash, call_context_hash, fr(is_delegate_call), fr(is_static_call), + function_signature_hash, + arg_hash, }; callback_stack_item.failure_callback_call_hash = diff --git a/circuits/src/aztec3/circuits/apps/oracle_wrapper.hpp b/circuits/src/aztec3/circuits/apps/oracle_wrapper.hpp index 3a097db9257..3aa1055512d 100644 --- a/circuits/src/aztec3/circuits/apps/oracle_wrapper.hpp +++ b/circuits/src/aztec3/circuits/apps/oracle_wrapper.hpp @@ -30,7 +30,7 @@ template class OracleWrapperInterface { : composer(composer) , oracle(oracle){}; - fr get_msg_sender_private_key() + fr& get_msg_sender_private_key() { if (msg_sender_private_key) { return *msg_sender_private_key; @@ -40,7 +40,7 @@ template class OracleWrapperInterface { return *msg_sender_private_key; }; - CallContext get_call_context() + CallContext& get_call_context() { if (call_context) { return *call_context; @@ -49,9 +49,9 @@ template class OracleWrapperInterface { return *call_context; }; - address get_msg_sender() { return get_call_context().msg_sender; }; + address& get_msg_sender() { return get_call_context().msg_sender; }; - address get_this_contract_address() { return get_call_context().storage_contract_address; }; + address& get_this_contract_address() { return get_call_context().storage_contract_address; }; fr generate_salt() const { return plonk::stdlib::types::to_ct(composer, oracle.generate_salt()); } diff --git a/circuits/src/aztec3/circuits/apps/private_state_var.hpp b/circuits/src/aztec3/circuits/apps/private_state_var.hpp index 07d70b1a252..25bfb025931 100644 --- a/circuits/src/aztec3/circuits/apps/private_state_var.hpp +++ b/circuits/src/aztec3/circuits/apps/private_state_var.hpp @@ -20,11 +20,14 @@ template class PrivateStateVar { typedef typename CT::address address; typedef typename CT::grumpkin_point grumpkin_point; - PrivateStateFactory* state_factory; + PrivateStateFactory* + state_factory; // Pointer, because PrivateStateVar can't hold a reference (because it gets initialised as a + // member of a map within PrivateStateFactory, so might not be passed data upon initialisation) PrivateStateType private_state_type; std::string name; fr start_slot; - grumpkin_point slot_point; /// TODO: make this std::optional (since mappings won't have this) + grumpkin_point slot_point; /// TODO: make this std::optional (since mapping vars won't have this (only specific + /// mapping values will))? // A mapping var (in particular) can point to many private_states: std::map> private_states; diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/constants.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/constants.hpp deleted file mode 100644 index 7fe35b23a8b..00000000000 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/constants.hpp +++ /dev/null @@ -1,25 +0,0 @@ -// #pragma once -// #include "init.hpp" -// #include -// #include - -// namespace aztec3::circuits::apps::test_apps::escrow { - -// using plonk::stdlib::witness_t; -// CT::boolean TRUE; -// CT::boolean FALSE; -// CT::fr ZERO; - -// void init(Composer& composer) -// { -// TRUE = witness_t(&composer, true); -// TRUE.assert_equal(CT::boolean(true)); - -// FALSE = witness_t(&composer, false); -// FALSE.assert_equal(CT::boolean(false)); - -// ZERO = witness_t(&composer, 0); -// ZERO.assert_equal(CT::fr(0)); -// } - -// } // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp index 3103ed0f944..7020a2e6d7b 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp @@ -16,7 +16,7 @@ inline ContractFactory init(Composer& composer, OracleWrapper& oracle) { .name = "deposit", .is_private = true }, { .name = "transfer", .is_private = true }, { .name = "withdraw", .is_private = true }, - // not needed, but it's helping me figure out success cases: + // success case not needed in this app, but it's helping me figure out success cases: { .name = "withdraw_success_callback", .is_private = true }, { .name = "withdraw_failure_callback", .is_private = true }, }); diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp index d18c56af18a..232040eb468 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp @@ -43,13 +43,6 @@ OptionalPrivateCircuitPublicInputs deposit( public_inputs.set_commitments(contract.private_state_factory.commitments); public_inputs.set_nullifiers(contract.private_state_factory.nullifiers); - public_inputs.pay_fee_from_l1 = to_ct(composer, true); - CT::fr(*public_inputs.pay_fee_from_l1) - .assert_equal(1); /// TODO: Ugly way of hard-coding a witness. Is there a nicer way? - public_inputs.called_from_l1 = to_ct(composer, true); - CT::fr(*public_inputs.called_from_l1) - .assert_equal(1); /// TODO: Ugly way of hard-coding a witness. Is there a nicer way? - public_inputs.set_public(composer); info("public inputs: ", public_inputs); diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/escrow.test.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/escrow.test.cpp index 550d3531653..44a0acdaa13 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/escrow.test.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/escrow.test.cpp @@ -55,7 +55,13 @@ TEST(escrow_tests, test_transfer) NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); const NT::fr msg_sender_private_key = 123456789; - NativeOracle oracle = NativeOracle(db, contract_address, msg_sender, msg_sender_private_key); + CallContext call_context = { + .msg_sender = msg_sender, + .storage_contract_address = contract_address, + .is_fee_payment = true, + }; + + NativeOracle oracle = NativeOracle(db, call_context, msg_sender_private_key); OracleWrapper oracle_wrapper = OracleWrapper(composer, oracle); auto amount = NT::fr(5); @@ -64,9 +70,8 @@ TEST(escrow_tests, test_transfer) auto memo = NT::fr(999); auto reveal_msg_sender_to_recipient = true; auto fee = NT::fr(2); - auto is_fee_payment = fee > 0; - transfer(composer, oracle_wrapper, amount, to, asset_id, memo, reveal_msg_sender_to_recipient, fee, is_fee_payment); + transfer(composer, oracle_wrapper, amount, to, asset_id, memo, reveal_msg_sender_to_recipient, fee); info("computed witness: ", composer.computed_witness); info("witness: ", composer.witness); @@ -88,7 +93,13 @@ TEST(escrow_tests, test_withdraw) NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); const NT::fr msg_sender_private_key = 123456789; - NativeOracle oracle = NativeOracle(db, contract_address, msg_sender, msg_sender_private_key); + CallContext call_context = { + .msg_sender = msg_sender, + .storage_contract_address = contract_address, + .is_fee_payment = true, + }; + + NativeOracle oracle = NativeOracle(db, call_context, msg_sender_private_key); OracleWrapper oracle_wrapper = OracleWrapper(composer, oracle); auto amount = NT::fr(5); @@ -96,9 +107,8 @@ TEST(escrow_tests, test_withdraw) auto memo = NT::fr(999); auto l1_withdrawal_address = NT::fr(657756); auto fee = NT::fr(2); - auto is_fee_payment = fee > 0; - withdraw(composer, oracle_wrapper, amount, asset_id, memo, l1_withdrawal_address, fee, is_fee_payment); + withdraw(composer, oracle_wrapper, amount, asset_id, memo, l1_withdrawal_address, fee); info("computed witness: ", composer.computed_witness); info("witness: ", composer.witness); diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp index d5457efb5a5..9f9d082cf79 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp @@ -15,8 +15,7 @@ void transfer(Composer& composer, NT::fr const& _asset_id, NT::fr const& _memo, NT::boolean const& _reveal_msg_sender_to_recipient, - NT::fr const& _fee, - NT::boolean const& _is_fee_payment) + NT::fr const& _fee) { info("\n\nin transfer..."); @@ -28,7 +27,6 @@ void transfer(Composer& composer, CT::fr memo = to_ct(composer, _memo); CT::boolean reveal_msg_sender_to_recipient = to_ct(composer, _reveal_msg_sender_to_recipient); CT::fr fee = to_ct(composer, _fee); - CT::boolean is_fee_payment = to_ct(composer, _is_fee_payment); // Get states and globals ******************************************************* @@ -75,7 +73,6 @@ void transfer(Composer& composer, public_inputs.custom_public_inputs[3] = memo; public_inputs.custom_public_inputs[4] = CT::fr(reveal_msg_sender_to_recipient); public_inputs.custom_public_inputs[5] = fee; - public_inputs.custom_public_inputs[6] = is_fee_payment; public_inputs.emitted_public_inputs[0] = CT::fr::copy_as_new_witness(composer, fee); public_inputs.emitted_public_inputs[1] = CT::fr::copy_as_new_witness(composer, asset_id); @@ -86,8 +83,6 @@ void transfer(Composer& composer, /// TODO: merkle membership check // public_inputs.old_private_data_tree_root - public_inputs.is_fee_payment = CT::boolean(CT::fr::copy_as_new_witness(composer, is_fee_payment)); - public_inputs.set_public(composer); info("public inputs: ", public_inputs); diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.hpp index 24b89b4a065..42f6cbae8d5 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.hpp @@ -10,7 +10,6 @@ void transfer(Composer& composer, NT::fr const& _asset_id, NT::fr const& _memo, NT::boolean const& _reveal_msg_sender_to_recipient, - NT::fr const& _fee, - NT::boolean const& _is_fee_payment); + NT::fr const& _fee); } // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp index 4e79021b178..3f1c0a23c0e 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp @@ -16,8 +16,7 @@ void withdraw(Composer& composer, NT::fr const& _asset_id, NT::fr const& _memo, NT::fr const& _l1_withdrawal_address, - NT::fr const& _fee, - NT::boolean const& _is_fee_payment) + NT::fr const& _fee) { info("\n\nin withdraw..."); @@ -28,7 +27,6 @@ void withdraw(Composer& composer, CT::fr memo = to_ct(composer, _memo); CT::fr l1_withdrawal_address = to_ct(composer, _l1_withdrawal_address); CT::fr fee = to_ct(composer, _fee); - CT::boolean is_fee_payment = to_ct(composer, _is_fee_payment); // Get states and globals ******************************************************* @@ -80,7 +78,6 @@ void withdraw(Composer& composer, public_inputs.custom_public_inputs[2] = memo; public_inputs.custom_public_inputs[3] = l1_withdrawal_address; public_inputs.custom_public_inputs[4] = fee; - public_inputs.custom_public_inputs[5] = is_fee_payment; public_inputs.emitted_public_inputs[0] = CT::fr::copy_as_new_witness(composer, l1_withdrawal_address); public_inputs.emitted_public_inputs[1] = CT::fr::copy_as_new_witness(composer, asset_id); @@ -92,8 +89,6 @@ void withdraw(Composer& composer, /// TODO: merkle membership check // public_inputs.old_private_data_tree_root - public_inputs.is_fee_payment = CT::boolean(CT::fr::copy_as_new_witness(composer, is_fee_payment)); - public_inputs.set_public(composer); info("public inputs: ", public_inputs); diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.hpp index 5207b2cd43f..9a4e89941f3 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.hpp @@ -9,7 +9,6 @@ void withdraw(Composer& composer, NT::fr const& _asset_id, NT::fr const& _memo, NT::fr const& _l1_withdrawal_address, - NT::fr const& _fee, - NT::boolean const& _is_fee_payment); + NT::fr const& _fee); } // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw_failure_callback.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw_failure_callback.cpp index 1c1868df161..c1bd7a011f1 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw_failure_callback.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw_failure_callback.cpp @@ -49,10 +49,6 @@ void withdraw_failure_callback(Composer& composer, public_inputs.set_commitments(contract.private_state_factory.commitments); public_inputs.set_nullifiers(contract.private_state_factory.nullifiers); - public_inputs.pay_fee_from_l1 = to_ct(composer, true); - CT::fr(*public_inputs.pay_fee_from_l1) - .assert_equal(1); /// TODO: Ugly way of hard-coding a witness. Is there a nicer way? - public_inputs.set_public(composer); info("public inputs: ", public_inputs); diff --git a/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp b/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp index 5f28d377546..6834c1cf8d2 100644 --- a/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp +++ b/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp @@ -140,8 +140,7 @@ void validate_inputs(PrivateInputs const& private_inputs, PublicInputs& { is_recursive_case.must_imply(private_inputs.previous_kernel.public_inputs.is_private == true, "Cannot verify a non-private kernel snark in the private kernel circuit"); - is_recursive_case.must_imply(private_inputs.private_call.call_stack_item.function_signature.is_callback == - false, + is_recursive_case.must_imply(private_inputs.private_call.call_stack_item.call_context.is_callback == false, "A callback must be executed as the first tx in the recursion"); is_recursive_case.must_imply(private_inputs.private_call.call_stack_item.function_signature.is_constructor == false, @@ -286,7 +285,7 @@ void private_kernel_circuit(Composer& composer, OracleWrapper& oracle, PrivateIn public_inputs.constants.is_callback_recursion = CT::boolean::conditional_assign(is_base_case, - private_inputs.private_call.call_stack_item.function_signature.is_callback, + private_inputs.private_call.call_stack_item.call_context.is_callback, private_inputs.previous_kernel.public_inputs.constants.is_callback_recursion); public_inputs.end.aggregation_object = aggregation_object; diff --git a/circuits/src/aztec3/oracle/oracle.hpp b/circuits/src/aztec3/oracle/oracle.hpp index e9d480d96f0..807fb48d9ce 100644 --- a/circuits/src/aztec3/oracle/oracle.hpp +++ b/circuits/src/aztec3/oracle/oracle.hpp @@ -19,28 +19,64 @@ template class NativeOracleInterface { NativeOracleInterface(DB& db, NT::fr const& contract_address, // NT::fr const& portal_contract_address, - NT::address const& msg_sender) + NT::address const& msg_sender, + NT::boolean const& is_delegate_call = false, + NT::boolean const& is_static_call = false, + NT::boolean const& is_fee_payment = false, + NT::boolean const& pay_fee_from_l1 = false, + NT::boolean const& pay_fee_from_public_l2 = false, + NT::boolean const& called_from_l1 = false, + NT::boolean const& called_from_public_l2 = false) : db(db) , call_context({ .msg_sender = msg_sender, .storage_contract_address = contract_address, + .is_delegate_call = is_delegate_call, + .is_static_call = is_static_call, + .is_fee_payment = is_fee_payment, + .pay_fee_from_l1 = pay_fee_from_l1, + .pay_fee_from_public_l2 = pay_fee_from_public_l2, + .called_from_l1 = called_from_l1, + .called_from_public_l2 = called_from_public_l2, }) // , portal_contract_address(portal_contract_address) {}; + // Include the msg_sender_private_key NativeOracleInterface(DB& db, NT::fr const& contract_address, // NT::fr const& portal_contract_address, NT::address const& msg_sender, - std::optional msg_sender_private_key) + std::optional msg_sender_private_key, + NT::boolean const& is_delegate_call = false, + NT::boolean const& is_static_call = false, + NT::boolean const& is_fee_payment = false, + NT::boolean const& pay_fee_from_l1 = false, + NT::boolean const& pay_fee_from_public_l2 = false, + NT::boolean const& called_from_l1 = false, + NT::boolean const& called_from_public_l2 = false) : db(db) , call_context({ .msg_sender = msg_sender, .storage_contract_address = contract_address, + .is_delegate_call = is_delegate_call, + .is_static_call = is_static_call, + .is_fee_payment = is_fee_payment, + .pay_fee_from_l1 = pay_fee_from_l1, + .pay_fee_from_public_l2 = pay_fee_from_public_l2, + .called_from_l1 = called_from_l1, + .called_from_public_l2 = called_from_public_l2, }) // , portal_contract_address(portal_contract_address) , msg_sender_private_key(msg_sender_private_key){}; + // CallContext as struct + NativeOracleInterface(DB& db, CallContext call_context, std::optional msg_sender_private_key) + : db(db) + , call_context(call_context) + // , portal_contract_address(portal_contract_address) + , msg_sender_private_key(msg_sender_private_key){}; + NT::fr get_msg_sender_private_key() { if (!msg_sender_private_key) { From c8de4e8c7013e4bbbab554a2314ffb79c80bbf26 Mon Sep 17 00:00:00 2001 From: iAmMichaelConnor Date: Mon, 20 Jun 2022 11:55:19 +0000 Subject: [PATCH 008/166] tweak ABIs and return preimages --- .../src/aztec3/circuits/abis/call_context.hpp | 1 - .../aztec3/circuits/abis/call_stack_item.hpp | 2 +- .../abis/optionally_revealed_data.hpp | 4 ++ .../abis/private_kernel/private_inputs.hpp | 5 +- circuits/src/aztec3/circuits/apps/README.md | 35 +++++++++- .../aztec3/circuits/apps/contract_factory.hpp | 32 ++++++--- .../circuits/apps/function_executor.hpp | 52 ++++++++++++++ circuits/src/aztec3/circuits/apps/l1_call.hpp | 6 +- ...function.hpp => l1_function_interface.hpp} | 13 ++-- ...function.tpp => l1_function_interface.tpp} | 3 +- .../circuits/apps/nullifier_preimage.hpp | 67 +++++++++++++++++++ .../circuits/apps/private_state_factory.hpp | 45 ++++++++----- .../circuits/apps/private_state_note.hpp | 7 +- .../circuits/apps/private_state_note.tpp | 16 +++-- .../apps/private_state_note_preimage.hpp | 2 +- .../circuits/apps/private_state_var.tpp | 8 +-- .../apps/test_apps/escrow/deposit.cpp | 18 ++--- .../apps/test_apps/escrow/escrow.test.cpp | 3 +- .../apps/test_apps/escrow/transfer.cpp | 38 +++++------ .../apps/test_apps/escrow/transfer.hpp | 19 +++--- .../apps/test_apps/escrow/withdraw.cpp | 35 ++++------ .../apps/test_apps/escrow/withdraw.hpp | 17 +++-- .../escrow/withdraw_failure_callback.cpp | 16 ++--- .../kernel/private/private_kernel_circuit.cpp | 3 +- .../aztec3/circuits/mock/mock_circuit_2.hpp | 6 -- 25 files changed, 313 insertions(+), 140 deletions(-) create mode 100644 circuits/src/aztec3/circuits/apps/function_executor.hpp rename circuits/src/aztec3/circuits/apps/{l1_function.hpp => l1_function_interface.hpp} (78%) rename circuits/src/aztec3/circuits/apps/{l1_function.tpp => l1_function_interface.tpp} (84%) create mode 100644 circuits/src/aztec3/circuits/apps/nullifier_preimage.hpp diff --git a/circuits/src/aztec3/circuits/abis/call_context.hpp b/circuits/src/aztec3/circuits/abis/call_context.hpp index db4f95a2329..0cb9d91a801 100644 --- a/circuits/src/aztec3/circuits/abis/call_context.hpp +++ b/circuits/src/aztec3/circuits/abis/call_context.hpp @@ -155,7 +155,6 @@ template void write(std::vector& buf, CallContext c template std::ostream& operator<<(std::ostream& os, CallContext const& call_context) { return os << "msg_sender: " << call_context.msg_sender << "\n" - << "storage_contract_address: " << call_context.storage_contract_address << "\n" << "storage_contract_address: " << call_context.storage_contract_address << "\n" << "is_delegate_call: " << call_context.is_delegate_call << "\n" << "is_static_call: " << call_context.is_static_call << "\n" diff --git a/circuits/src/aztec3/circuits/abis/call_stack_item.hpp b/circuits/src/aztec3/circuits/abis/call_stack_item.hpp index 823abfc854b..0a0926c6cf7 100644 --- a/circuits/src/aztec3/circuits/abis/call_stack_item.hpp +++ b/circuits/src/aztec3/circuits/abis/call_stack_item.hpp @@ -30,7 +30,7 @@ template struct CallStackItem { conditional, PrivateCircuitPublicInputs>::type; FunctionSignature function_signature; - PublicInputs public_inputs; // TODO: can we just do args? + PublicInputs public_inputs; CallContext call_context; boolean is_delegate_call = false; boolean is_static_call = false; diff --git a/circuits/src/aztec3/circuits/abis/optionally_revealed_data.hpp b/circuits/src/aztec3/circuits/abis/optionally_revealed_data.hpp index 350b0438c23..be6ccb2c76c 100644 --- a/circuits/src/aztec3/circuits/abis/optionally_revealed_data.hpp +++ b/circuits/src/aztec3/circuits/abis/optionally_revealed_data.hpp @@ -53,6 +53,10 @@ template struct OptionallyRevealedData { set_array_public(emitted_public_inputs); vk_hash.set_public(); portal_contract_address.set_public(); + fr(pay_fee_from_l1).set_public(); + fr(pay_fee_from_public_l2).set_public(); + fr(called_from_l1).set_public(); + fr(called_from_public_l2).set_public(); } template void set_array_public(std::array& arr) diff --git a/circuits/src/aztec3/circuits/abis/private_kernel/private_inputs.hpp b/circuits/src/aztec3/circuits/abis/private_kernel/private_inputs.hpp index ac531c1ef00..0f432167631 100644 --- a/circuits/src/aztec3/circuits/abis/private_kernel/private_inputs.hpp +++ b/circuits/src/aztec3/circuits/abis/private_kernel/private_inputs.hpp @@ -16,8 +16,9 @@ using std::is_same; template struct PrivateInputs { typedef typename NCT::fr fr; + // typedef typename NCT::signature Signature; - // Signature signature; // TODO! + // Signature signature; // AccumulatedData start; PreviousKernelData previous_kernel; PrivateCallData private_call; @@ -27,7 +28,7 @@ template struct PrivateInputs { static_assert((std::is_same::value)); PrivateInputs> private_inputs = { - // signature.to_circuit_type(); + // plonk::stdlib::schnorr::convert_signature(&composer, signature), // start.to_circuit_type(composer), previous_kernel.to_circuit_type(composer), private_call.to_circuit_type(composer), diff --git a/circuits/src/aztec3/circuits/apps/README.md b/circuits/src/aztec3/circuits/apps/README.md index c7120db64c5..9d966334fa8 100644 --- a/circuits/src/aztec3/circuits/apps/README.md +++ b/circuits/src/aztec3/circuits/apps/README.md @@ -42,4 +42,37 @@ contract_factory commitments). Only at this stage are the commitments (and partial commitments) and nullifiers computed. -``` \ No newline at end of file +``` + +ContractFactory +- Composer& composer; +- OracleWrapperInterface& oracle; +- const std::string contract_name; +- PrivateStateFactory private_state_factory; +- std::map> function_signatures; +- std::map> l1_functions; + +PrivateStateFactory +- Composer& composer; +- OracleWrapperInterface& oracle; +- const std::string contract_name; +- fr private_state_counter = 0; +- std::map> private_state_vars; +- std::vector> private_state_notes; +- std::vector commitments; +- std::vector nullifiers; + +PrivateStateVar +- PrivateStateFactory* state_factory; +- PrivateStateType private_state_type; +- std::string name; +- fr start_slot; +- grumpkin_point slot_point; +- std::map> private_states; +- bool is_mapping = false; +- std::optional> mapping_key_names = std::nullopt; +- bool is_partial_slot = false; + +PrivateStateNote +- PrivateStateVar& private_state_var; +- PrivateStateNotePreimage preimage; \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/contract_factory.hpp b/circuits/src/aztec3/circuits/apps/contract_factory.hpp index 367766fbb4c..d203ccea996 100644 --- a/circuits/src/aztec3/circuits/apps/contract_factory.hpp +++ b/circuits/src/aztec3/circuits/apps/contract_factory.hpp @@ -3,10 +3,11 @@ #include #include #include +#include #include "private_state_note.hpp" #include "private_state_var.hpp" #include "function.hpp" -#include "l1_function.hpp" +#include "l1_function_interface.hpp" #include "oracle_wrapper.hpp" namespace aztec3::circuits::apps { @@ -15,6 +16,7 @@ using plonk::stdlib::witness_t; using plonk::stdlib::types::CircuitTypes; using NT = plonk::stdlib::types::NativeTypes; using aztec3::circuits::abis::FunctionSignature; +using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; template class ContractFactory { typedef CircuitTypes CT; @@ -24,17 +26,25 @@ template class ContractFactory { public: Composer& composer; OracleWrapperInterface& oracle; + const std::string contract_name; + PrivateStateFactory private_state_factory; + OptionalPrivateCircuitPublicInputs private_circuit_public_inputs; + // UnpackedPrivateCircuitData unpacked_private_circuit_data; + std::map> function_signatures; - std::map> l1_functions; + std::map> l1_functions; ContractFactory(Composer& composer, OracleWrapperInterface& oracle, std::string contract_name) : composer(composer) , oracle(oracle) , contract_name(contract_name) , private_state_factory(PrivateStateFactory(composer, oracle, contract_name)) - {} + , private_circuit_public_inputs(OptionalPrivateCircuitPublicInputs::create()) + { + private_circuit_public_inputs.call_context = oracle.get_call_context(); + } void set_functions(std::vector> const& functions) { @@ -60,13 +70,13 @@ template class ContractFactory { return function_signatures[name]; } - void import_l1_function(L1FunctionStruct const& l1_function_struct) + void import_l1_function(L1FunctionInterfaceStruct const& l1_function_struct) { - L1Function l1_function = L1Function(this, l1_function_struct); + L1FunctionInterface l1_function = L1FunctionInterface(this, l1_function_struct); l1_functions.insert(std::make_pair(l1_function_struct.function_name, l1_function)); }; - L1Function& get_l1_function(std::string const& name) + L1FunctionInterface& get_l1_function(std::string const& name) { if (!l1_functions.contains(name)) { throw_or_abort("L1 function not found. Make sure to import_l1_function()"); @@ -88,9 +98,15 @@ template class ContractFactory { return private_state_factory.new_private_state(name, mapping_key_names, private_state_type); }; - void finalise() { private_state_factory.finalise(); }; - PrivateStateVar& get_private_state(std::string const& name) { return private_state_factory.get(name); }; + + void finalise() + { + private_state_factory.finalise(); + private_circuit_public_inputs.set_commitments(private_state_factory.new_commitments); + private_circuit_public_inputs.set_nullifiers(private_state_factory.new_nullifiers); + private_circuit_public_inputs.set_public(composer); + }; }; } // namespace aztec3::circuits::apps \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/function_executor.hpp b/circuits/src/aztec3/circuits/apps/function_executor.hpp new file mode 100644 index 00000000000..a908f90ee52 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/function_executor.hpp @@ -0,0 +1,52 @@ +// #pragma once +// #include +// #include +// #include +// #include +// #include +// #include "private_state_note.hpp" +// #include "private_state_var.hpp" +// #include "function.hpp" +// #include "l1_function_interface.hpp" +// #include "oracle_wrapper.hpp" + +// namespace aztec3::circuits::apps { + +// using plonk::stdlib::witness_t; +// using plonk::stdlib::types::CircuitTypes; +// using NT = plonk::stdlib::types::NativeTypes; +// using aztec3::circuits::abis::FunctionSignature; +// using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; + +// template class FunctionExecutor { +// typedef CircuitTypes CT; +// typedef typename CT::fr fr; + +// public: +// Composer& composer; +// OracleWrapperInterface& oracle; +// ContractFactory& contract_factory; +// PrivateStateFactory& private_state_factory; +// OptionalPrivateCircuitPublicInputs private_circuit_public_inputs; +// // UnpackedData unpacked_data; + +// FunctionExecutor(ContractFactory& contract_factory) +// : composer(contract_factory.composer) +// , oracle(contract_factory.oracle) +// , contract_factory(contract_factory) +// , private_state_factory(contract_factory.private_state_factory) +// , private_circuit_public_inputs(OptionalPrivateCircuitPublicInputs::create()) +// { +// private_circuit_public_inputs.call_context = oracle.get_call_context(); +// } + +// void finalise() +// { +// private_state_factory.finalise(); +// private_circuit_public_inputs.set_commitments(private_state_factory.commitments); +// private_circuit_public_inputs.set_nullifiers(private_state_factory.nullifiers); +// private_circuit_public_inputs.set_public(composer); +// }; +// }; + +// } // namespace aztec3::circuits::apps \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/l1_call.hpp b/circuits/src/aztec3/circuits/apps/l1_call.hpp index d1522161b76..39d39c6c02a 100644 --- a/circuits/src/aztec3/circuits/apps/l1_call.hpp +++ b/circuits/src/aztec3/circuits/apps/l1_call.hpp @@ -3,7 +3,7 @@ #include #include #include -#include "l1_function.hpp" +#include "l1_function_interface.hpp" // #include // #include @@ -17,12 +17,12 @@ template class L1Call { typedef typename CircuitTypes::fr fr; public: - L1Function& l1_function; + L1FunctionInterface& l1_function; std::vector args; fr hash_of_argument_encodings; fr partial_l1_call_stack_item; // keccak(function_selector, hash_of_argument_encodings) - L1Call(L1Function const& l1_function, std::vector const& args) + L1Call(L1FunctionInterface const& l1_function, std::vector const& args) : l1_function(l1_function) , args(args) { diff --git a/circuits/src/aztec3/circuits/apps/l1_function.hpp b/circuits/src/aztec3/circuits/apps/l1_function_interface.hpp similarity index 78% rename from circuits/src/aztec3/circuits/apps/l1_function.hpp rename to circuits/src/aztec3/circuits/apps/l1_function_interface.hpp index 123a252e5af..6bbb8bb325e 100644 --- a/circuits/src/aztec3/circuits/apps/l1_function.hpp +++ b/circuits/src/aztec3/circuits/apps/l1_function_interface.hpp @@ -16,7 +16,7 @@ using plonk::stdlib::types::NativeTypes; template class ContractFactory; // We use the struct to retain designated initialisation, to make contract creation more readable. -template struct L1FunctionStruct { +template struct L1FunctionInterfaceStruct { typedef typename CircuitTypes::fr fr; std::string function_name; @@ -24,7 +24,7 @@ template struct L1FunctionStruct { size_t num_params = 0; }; -template class L1Function { +template class L1FunctionInterface { typedef typename CircuitTypes::fr fr; public: @@ -33,16 +33,17 @@ template class L1Function { fr function_selector; size_t num_params; - L1Function(){}; + L1FunctionInterface(){}; - L1Function(ContractFactory* contract_factory, L1FunctionStruct const& l1_fn_struct) + L1FunctionInterface(ContractFactory* contract_factory, + L1FunctionInterfaceStruct const& l1_fn_struct) : contract_factory(contract_factory) , function_name(l1_fn_struct.function_name) , function_selector(l1_fn_struct.function_selector) , num_params(l1_fn_struct.num_params) {} - // L1Function(L1Function const& l1_function) + // L1FunctionInterface(L1FunctionInterface const& l1_function) // : contract_factory(l1_function.contract_factory) // , function_name(l1_function.function_name) // , function_selector(l1_function.function_selector) @@ -54,4 +55,4 @@ template class L1Function { } // namespace aztec3::circuits::apps -#include "l1_function.tpp" \ No newline at end of file +#include "l1_function_interface.tpp" \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/l1_function.tpp b/circuits/src/aztec3/circuits/apps/l1_function_interface.tpp similarity index 84% rename from circuits/src/aztec3/circuits/apps/l1_function.tpp rename to circuits/src/aztec3/circuits/apps/l1_function_interface.tpp index a68bc1ee312..80ed8631363 100644 --- a/circuits/src/aztec3/circuits/apps/l1_function.tpp +++ b/circuits/src/aztec3/circuits/apps/l1_function_interface.tpp @@ -13,7 +13,8 @@ using plonk::stdlib::witness_t; using plonk::stdlib::types::CircuitTypes; using plonk::stdlib::types::NativeTypes; -template std::pair, L1Result> L1Function::call(std::vector args) +template +std::pair, L1Result> L1FunctionInterface::call(std::vector args) { if (args.size() != num_params) { throw_or_abort("Incorrect number of args"); diff --git a/circuits/src/aztec3/circuits/apps/nullifier_preimage.hpp b/circuits/src/aztec3/circuits/apps/nullifier_preimage.hpp new file mode 100644 index 00000000000..83663eb8bb9 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/nullifier_preimage.hpp @@ -0,0 +1,67 @@ +#pragma once +#include +#include +#include +#include +#include +#include + +namespace aztec3::circuits::apps { + +using crypto::pedersen::generator_index_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; + +template struct NullifierPreimage { + typedef typename NCT::fr fr; + typedef typename NCT::boolean boolean; + + fr commitment; + fr owner_private_key; + boolean is_real; + + bool operator==(NullifierPreimage const&) const = default; + + template NullifierPreimage> to_circuit_type(Composer& composer) const + { + static_assert((std::is_same::value)); + + // Capture the composer: + auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + + NullifierPreimage> preimage = { + to_ct(commitment), + to_ct(owner_private_key), + to_ct(is_real), + }; + + return preimage; + }; +}; + +template void read(uint8_t const*& it, NullifierPreimage& preimage) +{ + using serialize::read; + + read(it, preimage.commitment); + read(it, preimage.owner_private_key); + read(it, preimage.is_real); +}; + +template void write(std::vector& buf, NullifierPreimage const& preimage) +{ + using serialize::write; + + write(buf, preimage.commitment); + write(buf, preimage.owner_private_key); + write(buf, preimage.is_real); +}; + +template std::ostream& operator<<(std::ostream& os, NullifierPreimage const& preimage) +{ + return os << "commitment: " << preimage.commitment << "\n" + << "owner_private_key: " << preimage.owner_private_key << "\n" + << "is_real: " << preimage.is_real << "\n"; +} + +} // namespace aztec3::circuits::apps \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/private_state_factory.hpp b/circuits/src/aztec3/circuits/apps/private_state_factory.hpp index f057cc3a839..5c2ee607bc9 100644 --- a/circuits/src/aztec3/circuits/apps/private_state_factory.hpp +++ b/circuits/src/aztec3/circuits/apps/private_state_factory.hpp @@ -1,9 +1,10 @@ #pragma once +#include #include +#include "nullifier_preimage.hpp" #include "private_state_note.hpp" #include "private_state_var.hpp" #include "oracle_wrapper.hpp" -#include namespace aztec3::circuits::apps { @@ -22,9 +23,10 @@ template class PrivateStateFactory { fr private_state_counter = 0; std::map> private_state_vars; - std::vector> private_state_notes; - std::vector commitments; - std::vector nullifiers; + std::vector> new_private_state_notes; + std::vector new_commitments; + std::vector> new_nullifier_preimages; + std::vector new_nullifiers; PrivateStateFactory(Composer& composer, OracleWrapperInterface& oracle, @@ -61,18 +63,25 @@ template class PrivateStateFactory { void finalise() { - if (private_state_notes.size() > nullifiers.size()) { - // We want to create more commitments than the number of nullifiers we've created so-far. But we want to - // inject an input_nullifier into each new commitment. So, let's create more dummy nullifiers. + + if (new_private_state_notes.size() > new_nullifiers.size()) { + // We've created more commitments than nullifiers so far. But we want to inject an input_nullifier into each + // new commitment. So, let's create more dummy nullifiers. const auto& msg_sender_private_key = oracle.get_msg_sender_private_key(); - for (size_t i = nullifiers.size(); i < private_state_notes.size(); ++i) { - nullifiers.push_back(PrivateStateNote::compute_dummy_nullifier( - oracle.generate_random_element(), msg_sender_private_key)); + for (size_t i = new_nullifiers.size(); i < new_private_state_notes.size(); ++i) { + auto dummy_commitment = oracle.generate_random_element(); + new_nullifiers.push_back( + PrivateStateNote::compute_dummy_nullifier(dummy_commitment, msg_sender_private_key)); + new_nullifier_preimages.push_back(NullifierPreimage{ + dummy_commitment, + msg_sender_private_key, + false, + }); } } - for (size_t i = 0; i < private_state_notes.size(); ++i) { - private_state_notes[i].preimage.input_nullifier = nullifiers[i]; - commitments.push_back(private_state_notes[i].compute_commitment()); + for (size_t i = 0; i < new_private_state_notes.size(); ++i) { + new_private_state_notes[i].preimage.input_nullifier = new_nullifiers[i]; + new_commitments.push_back(new_private_state_notes[i].compute_commitment()); } } @@ -86,12 +95,16 @@ template class PrivateStateFactory { void push_new_note(PrivateStateNote const private_state_note) { - private_state_notes.push_back(private_state_note); + new_private_state_notes.push_back(private_state_note); } - void push_new_commitment(fr const& commitment) { commitments.push_back(commitment); } + void push_new_nullifier_data(fr nullifier, NullifierPreimage nullifier_preimage) + { + new_nullifiers.push_back(nullifier); + new_nullifier_preimages.push_back(nullifier_preimage); + } - void push_new_nullifier(fr const& nullifier) { nullifiers.push_back(nullifier); } + std::vector> get_notes() { return new_private_state_notes; } }; } // namespace aztec3::circuits::apps \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/private_state_note.hpp b/circuits/src/aztec3/circuits/apps/private_state_note.hpp index 8f80eef9b99..f3b51e94c5f 100644 --- a/circuits/src/aztec3/circuits/apps/private_state_note.hpp +++ b/circuits/src/aztec3/circuits/apps/private_state_note.hpp @@ -1,6 +1,7 @@ #pragma once #include #include +#include "nullifier_preimage.hpp" namespace aztec3::circuits::apps { @@ -57,12 +58,15 @@ template class PrivateStateNote { }; fr compute_commitment() const; + grumpkin_point compute_partial_commitment() const; - fr compute_nullifier(fr const& owner_private_key); + std::pair> compute_nullifier(fr const& owner_private_key); + static fr compute_nullifier(fr const& commitment, fr const& owner_private_key, boolean const& is_real_commitment = true); + static fr compute_dummy_nullifier(fr const& dummy_commitment, fr const& owner_private_key); private: @@ -71,6 +75,7 @@ template class PrivateStateNote { std::optional partial_commitment; std::optional commitment; std::optional nullifier; + std::optional> nullifier_preimage; }; // // template PrivateStateNote from_buffer(B const& buffer, size_t offset = 0) diff --git a/circuits/src/aztec3/circuits/apps/private_state_note.tpp b/circuits/src/aztec3/circuits/apps/private_state_note.tpp index eb821249ef2..697ce3b56cc 100644 --- a/circuits/src/aztec3/circuits/apps/private_state_note.tpp +++ b/circuits/src/aztec3/circuits/apps/private_state_note.tpp @@ -59,8 +59,6 @@ template typename CircuitTypes::fr PrivateStateNot return *commitment; } - info("preimage: ", preimage); - grumpkin_point slot_point = private_state_var.slot_point; std::vector inputs; @@ -161,7 +159,8 @@ typename CircuitTypes::grumpkin_point PrivateStateNote::comp } template -typename CircuitTypes::fr PrivateStateNote::compute_nullifier(fr const& owner_private_key) +std::pair::fr, NullifierPreimage>> PrivateStateNote< + Composer>::compute_nullifier(fr const& owner_private_key) { if (is_partial) { throw_or_abort("Can't nullify a partial note."); @@ -170,11 +169,16 @@ typename CircuitTypes::fr PrivateStateNote::compute_nullifie throw_or_abort("Commitment not yet calculated. Call compute_commitment() or change how you initialise this " "note to include the `commit_on_init` bool."); } - if (nullifier.has_value()) { - return *nullifier; + if (nullifier && nullifier_preimage) { + return std::make_pair(*nullifier, *nullifier_preimage); } nullifier = PrivateStateNote::compute_nullifier(*commitment, owner_private_key, preimage.is_real); - return *nullifier; + nullifier_preimage = { + *commitment, + owner_private_key, + preimage.is_real, + }; + return std::make_pair(*nullifier, *nullifier_preimage); }; template diff --git a/circuits/src/aztec3/circuits/apps/private_state_note_preimage.hpp b/circuits/src/aztec3/circuits/apps/private_state_note_preimage.hpp index 5c6fc8dd8bc..ec8209f7528 100644 --- a/circuits/src/aztec3/circuits/apps/private_state_note_preimage.hpp +++ b/circuits/src/aztec3/circuits/apps/private_state_note_preimage.hpp @@ -93,6 +93,6 @@ template std::ostream& operator<<(std::ostream& os, PrivateStateN << "is_real: " << preimage.is_real << "\n"; } -template using MappingKeyValues = std::map>; +// template using MappingKeyValues = std::map>; } // namespace aztec3::circuits::apps \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/private_state_var.tpp b/circuits/src/aztec3/circuits/apps/private_state_var.tpp index dc8440875f0..917ca67cd69 100644 --- a/circuits/src/aztec3/circuits/apps/private_state_var.tpp +++ b/circuits/src/aztec3/circuits/apps/private_state_var.tpp @@ -271,16 +271,16 @@ void PrivateStateVar::subtract(PrivateStateOperand(*this, minuend_preimage_2, true); fr msg_sender_private_key = oracle.get_msg_sender_private_key(); - fr minuend_nullifier_1 = minuend_note_1.compute_nullifier(msg_sender_private_key); - fr minuend_nullifier_2 = minuend_note_2.compute_nullifier(msg_sender_private_key); + auto [minuend_nullifier_1, minuend_nullifier_preimage_1] = minuend_note_1.compute_nullifier(msg_sender_private_key); + auto [minuend_nullifier_2, minuend_nullifier_preimage_2] = minuend_note_2.compute_nullifier(msg_sender_private_key); /// TODO: merkle membership proofs for the two minuend notes. auto difference_note = PrivateStateNote(*this, difference_preimage); state_factory->push_new_note(difference_note); - state_factory->push_new_nullifier(minuend_nullifier_1); - state_factory->push_new_nullifier(minuend_nullifier_2); + state_factory->push_new_nullifier_data(minuend_nullifier_1, minuend_nullifier_preimage_1); + state_factory->push_new_nullifier_data(minuend_nullifier_2, minuend_nullifier_preimage_2); } // template class PrivateStateVar; diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp index 232040eb468..6b6fb1d2c65 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp @@ -1,6 +1,7 @@ #include "deposit.hpp" #include "contract.hpp" #include +// #include #include // #include @@ -17,9 +18,9 @@ OptionalPrivateCircuitPublicInputs deposit( CT::address msg_sender = oracle.get_msg_sender(); - auto contract = init(composer, oracle); + auto env = init(composer, oracle); - auto& balances = contract.get_private_state("balances"); + auto& balances = env.get_private_state("balances"); balances.at({ msg_sender.to_field(), asset_id }) .add({ @@ -29,25 +30,18 @@ OptionalPrivateCircuitPublicInputs deposit( .memo = memo, }); - contract.finalise(); - - // TODO: maybe pass `oracle` to this `create()` function as well? - auto public_inputs = OptionalPrivateCircuitPublicInputs::create(); - - public_inputs.call_context = oracle.get_call_context(); /// TODO: can this be abstracted away out of this body? + auto& public_inputs = env.private_circuit_public_inputs; public_inputs.custom_public_inputs[0] = amount; public_inputs.custom_public_inputs[1] = asset_id; public_inputs.custom_public_inputs[2] = memo; - public_inputs.set_commitments(contract.private_state_factory.commitments); - public_inputs.set_nullifiers(contract.private_state_factory.nullifiers); - - public_inputs.set_public(composer); + env.finalise(); info("public inputs: ", public_inputs); return public_inputs.to_native_type(); + // TODO: also return note preimages and nullifier preimages. }; } // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/escrow.test.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/escrow.test.cpp index 44a0acdaa13..41b9107bc86 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/escrow.test.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/escrow.test.cpp @@ -33,7 +33,8 @@ TEST(escrow_tests, test_deposit) auto asset_id = NT::fr(1); auto memo = NT::fr(999); - deposit(composer, oracle_wrapper, amount, asset_id, memo); + auto result = deposit(composer, oracle_wrapper, amount, asset_id, memo); + info("result: ", result); info("computed witness: ", composer.computed_witness); info("witness: ", composer.witness); diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp index 9f9d082cf79..7ddf0383a25 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp @@ -1,6 +1,7 @@ #include "transfer.hpp" #include "contract.hpp" #include +// #include #include // #include @@ -8,14 +9,14 @@ namespace aztec3::circuits::apps::test_apps::escrow { using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; -void transfer(Composer& composer, - OracleWrapper& oracle, - NT::fr const& _amount, - NT::address const& _to, - NT::fr const& _asset_id, - NT::fr const& _memo, - NT::boolean const& _reveal_msg_sender_to_recipient, - NT::fr const& _fee) +OptionalPrivateCircuitPublicInputs transfer(Composer& composer, + OracleWrapper& oracle, + NT::fr const& _amount, + NT::address const& _to, + NT::fr const& _asset_id, + NT::fr const& _memo, + NT::boolean const& _reveal_msg_sender_to_recipient, + NT::fr const& _fee) { info("\n\nin transfer..."); @@ -32,9 +33,9 @@ void transfer(Composer& composer, CT::address msg_sender = oracle.get_msg_sender(); - auto contract = init(composer, oracle); + auto env = init(composer, oracle); - auto& balances = contract.get_private_state("balances"); + auto& balances = env.get_private_state("balances"); // Circuit-specific logic ******************************************************* @@ -57,15 +58,9 @@ void transfer(Composer& composer, .memo = memo, }); - // Finalise state_factory ******************************************************* - - contract.finalise(); - // Assign circuit-specific public inputs **************************************** - auto public_inputs = OptionalPrivateCircuitPublicInputs::create(); - - public_inputs.call_context = oracle.get_call_context(); /// TODO: can this be abstracted away out of this body? + auto& public_inputs = env.private_circuit_public_inputs; public_inputs.custom_public_inputs[0] = amount; public_inputs.custom_public_inputs[1] = to.to_field(); @@ -77,15 +72,16 @@ void transfer(Composer& composer, public_inputs.emitted_public_inputs[0] = CT::fr::copy_as_new_witness(composer, fee); public_inputs.emitted_public_inputs[1] = CT::fr::copy_as_new_witness(composer, asset_id); - public_inputs.set_commitments(contract.private_state_factory.commitments); - public_inputs.set_nullifiers(contract.private_state_factory.nullifiers); - /// TODO: merkle membership check // public_inputs.old_private_data_tree_root - public_inputs.set_public(composer); + // Finalise ********************************************************************* + + env.finalise(); info("public inputs: ", public_inputs); + + return public_inputs.to_native_type(); }; } // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.hpp index 42f6cbae8d5..5090ec044de 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.hpp @@ -1,15 +1,18 @@ #pragma once #include "init.hpp" +#include namespace aztec3::circuits::apps::test_apps::escrow { -void transfer(Composer& composer, - OracleWrapper& oracle, - NT::fr const& _amount, - NT::address const& _to, - NT::fr const& _asset_id, - NT::fr const& _memo, - NT::boolean const& _reveal_msg_sender_to_recipient, - NT::fr const& _fee); +using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; + +OptionalPrivateCircuitPublicInputs transfer(Composer& composer, + OracleWrapper& oracle, + NT::fr const& _amount, + NT::address const& _to, + NT::fr const& _asset_id, + NT::fr const& _memo, + NT::boolean const& _reveal_msg_sender_to_recipient, + NT::fr const& _fee); } // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp index 3f1c0a23c0e..29873279ffb 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp @@ -10,13 +10,13 @@ namespace aztec3::circuits::apps::test_apps::escrow { using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; -void withdraw(Composer& composer, - OracleWrapper& oracle, - NT::fr const& _amount, - NT::fr const& _asset_id, - NT::fr const& _memo, - NT::fr const& _l1_withdrawal_address, - NT::fr const& _fee) +OptionalPrivateCircuitPublicInputs withdraw(Composer& composer, + OracleWrapper& oracle, + NT::fr const& _amount, + NT::fr const& _asset_id, + NT::fr const& _memo, + NT::fr const& _l1_withdrawal_address, + NT::fr const& _fee) { info("\n\nin withdraw..."); @@ -32,9 +32,9 @@ void withdraw(Composer& composer, CT::address msg_sender = oracle.get_msg_sender(); - auto contract = init(composer, oracle); + auto env = init(composer, oracle); - auto& balances = contract.get_private_state("balances"); + auto& balances = env.get_private_state("balances"); // Circuit-specific logic ******************************************************* @@ -46,7 +46,7 @@ void withdraw(Composer& composer, .memo = memo, }); - auto& l1_withdraw_function = contract.get_l1_function("withdraw"); + auto& l1_withdraw_function = env.get_l1_function("withdraw"); auto [l1_promise, l1_result] = l1_withdraw_function.call({ asset_id, amount, msg_sender.to_field() }); l1_promise.on_success("withdraw_success_callback", @@ -63,15 +63,9 @@ void withdraw(Composer& composer, memo, }); - // Finalise state_factory ******************************************************* - - contract.finalise(); - // Assign circuit-specific public inputs **************************************** - auto public_inputs = OptionalPrivateCircuitPublicInputs::create(); - - public_inputs.call_context = oracle.get_call_context(); /// TODO: can this be abstracted away out of this body? + auto& public_inputs = env.private_circuit_public_inputs; public_inputs.custom_public_inputs[0] = amount; public_inputs.custom_public_inputs[1] = asset_id; @@ -83,15 +77,14 @@ void withdraw(Composer& composer, public_inputs.emitted_public_inputs[1] = CT::fr::copy_as_new_witness(composer, asset_id); public_inputs.emitted_public_inputs[2] = CT::fr::copy_as_new_witness(composer, fee); - public_inputs.set_commitments(contract.private_state_factory.commitments); - public_inputs.set_nullifiers(contract.private_state_factory.nullifiers); + env.finalise(); /// TODO: merkle membership check // public_inputs.old_private_data_tree_root - public_inputs.set_public(composer); - info("public inputs: ", public_inputs); + + return public_inputs.to_native_type(); }; } // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.hpp index 9a4e89941f3..0ddb1a0b58d 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.hpp @@ -1,14 +1,17 @@ #pragma once #include "init.hpp" +#include namespace aztec3::circuits::apps::test_apps::escrow { -void withdraw(Composer& composer, - OracleWrapper& oracle, - NT::fr const& _amount, - NT::fr const& _asset_id, - NT::fr const& _memo, - NT::fr const& _l1_withdrawal_address, - NT::fr const& _fee); +using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; + +OptionalPrivateCircuitPublicInputs withdraw(Composer& composer, + OracleWrapper& oracle, + NT::fr const& _amount, + NT::fr const& _asset_id, + NT::fr const& _memo, + NT::fr const& _l1_withdrawal_address, + NT::fr const& _fee); } // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw_failure_callback.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw_failure_callback.cpp index c1bd7a011f1..cab8824b40f 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw_failure_callback.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw_failure_callback.cpp @@ -22,9 +22,9 @@ void withdraw_failure_callback(Composer& composer, CT::address msg_sender = oracle.get_msg_sender(); - auto contract = init(composer, oracle); + auto env = init(composer, oracle); - auto& balances = contract.get_private_state("balances"); + auto& balances = env.get_private_state("balances"); balances.at({ owner_address.to_field(), asset_id }) .add({ @@ -34,22 +34,14 @@ void withdraw_failure_callback(Composer& composer, .memo = memo, }); - contract.finalise(); - - // TODO: maybe pass `oracle` to this `create()` function as well? - auto public_inputs = OptionalPrivateCircuitPublicInputs::create(); - - public_inputs.call_context = oracle.get_call_context(); /// TODO: can this be abstracted away out of this body? + auto& public_inputs = env.private_circuit_public_inputs; public_inputs.custom_public_inputs[0] = asset_id; public_inputs.custom_public_inputs[1] = amount; public_inputs.custom_public_inputs[2] = owner_address.to_field(); public_inputs.custom_public_inputs[3] = memo; - public_inputs.set_commitments(contract.private_state_factory.commitments); - public_inputs.set_nullifiers(contract.private_state_factory.nullifiers); - - public_inputs.set_public(composer); + env.finalise(); info("public inputs: ", public_inputs); }; diff --git a/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp b/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp index 6834c1cf8d2..457a5734bb5 100644 --- a/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp +++ b/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp @@ -71,7 +71,8 @@ CT::AggregationObject verify_proofs(Composer& composer, Aggregator::aggregate(&composer, private_inputs.previous_kernel.vk, private_inputs.previous_kernel.proof, - num_private_kernel_public_inputs); + num_private_kernel_public_inputs, + aggregation_object); return aggregation_object; } diff --git a/circuits/src/aztec3/circuits/mock/mock_circuit_2.hpp b/circuits/src/aztec3/circuits/mock/mock_circuit_2.hpp index 07a89898b57..6e782b7c967 100644 --- a/circuits/src/aztec3/circuits/mock/mock_circuit_2.hpp +++ b/circuits/src/aztec3/circuits/mock/mock_circuit_2.hpp @@ -10,12 +10,6 @@ namespace aztec3::circuits::mock { -// ***************************************** - -// MIKE! TODO! This is the wrong PublicInputs class to use! Use the private kernel's PublicINputs!!! - -//******************************************* - using aztec3::circuits::abis::private_kernel::PublicInputs; using NT = plonk::stdlib::types::NativeTypes; using plonk::stdlib::pedersen; From 01b1ab6ed73a9ff97229b18f31ec606a46ce7c0f Mon Sep 17 00:00:00 2001 From: iAmMichaelConnor Date: Sat, 16 Jul 2022 21:06:36 +0000 Subject: [PATCH 009/166] refactor: add function excution context --- .../app-circuits/public-input-abis.md | 2 +- .../specs/src/noir-stuff/extremes/call-l1.md | 12 +- .../src/noir-stuff/extremes/call-private.md | 14 +- .../noir-stuff/extremes/call-public-same.md | 10 +- .../src/noir-stuff/extremes/call-public.md | 10 +- .../noir-stuff/extremes/decr-private-owned.md | 4 +- .../noir-stuff/extremes/deploy-contract.md | 12 +- .../src/noir-stuff/extremes/edit-public.md | 2 +- .../src/noir-stuff/extremes/emit-event.md | 2 +- .../extremes/incr-private-not-owned.md | 2 +- .../noir-stuff/extremes/incr-private-owned.md | 4 +- .../src/noir-stuff/extremes/read-public.md | 2 +- .../src/aztec3/circuits/abis/abis.test.cpp | 16 +- .../circuits/abis/function_signature.hpp | 16 +- .../abis/private_circuit_public_inputs.hpp | 104 ++++++------- .../abis/public_circuit_public_inputs.hpp | 12 +- .../aztec3/circuits/apps/contract_factory.hpp | 112 +++++--------- .../aztec3/circuits/apps/contract_factory.tpp | 107 +++++++++++++ .../circuits/apps/function_executor.hpp | 146 ++++++++++++------ .../circuits/apps/l1_function_interface.hpp | 11 +- .../circuits/apps/l1_function_interface.tpp | 2 +- .../src/aztec3/circuits/apps/l1_promise.hpp | 8 +- .../src/aztec3/circuits/apps/l1_promise.tpp | 6 +- .../circuits/apps/private_state_factory.hpp | 143 ++++------------- .../circuits/apps/private_state_var.hpp | 27 ++-- .../circuits/apps/private_state_var.tpp | 22 +-- .../escrow/{escrow.test.cpp => .test.cpp} | 20 ++- .../apps/test_apps/escrow/contract.hpp | 8 +- .../apps/test_apps/escrow/deposit.cpp | 30 ++-- .../apps/test_apps/escrow/deposit.hpp | 9 +- .../circuits/apps/test_apps/escrow/init.hpp | 1 + .../apps/test_apps/escrow/transfer.cpp | 33 ++-- .../apps/test_apps/escrow/transfer.hpp | 6 +- .../apps/test_apps/escrow/withdraw.cpp | 31 ++-- .../apps/test_apps/escrow/withdraw.hpp | 6 +- .../escrow/withdraw_failure_callback.cpp | 28 ++-- .../escrow/withdraw_failure_callback.hpp | 4 +- .../.test.cpp | 49 ++++++ .../contract.hpp | 24 +++ .../function1.cpp | 50 ++++++ .../function1.hpp | 12 ++ .../function2.cpp | 48 ++++++ .../function2.hpp | 12 ++ .../index.hpp | 4 + .../private_to_private_function_call/init.hpp | 21 +++ .../{private_kernel.test.cpp => .test.cpp} | 7 +- .../aztec3/circuits/kernel/private/init.hpp | 3 + .../kernel/private/private_kernel_circuit.cpp | 6 +- circuits/src/aztec3/constants.hpp | 2 +- circuits/src/aztec3/oracle/README.md | 2 +- 50 files changed, 748 insertions(+), 476 deletions(-) create mode 100644 circuits/src/aztec3/circuits/apps/contract_factory.tpp rename circuits/src/aztec3/circuits/apps/test_apps/escrow/{escrow.test.cpp => .test.cpp} (88%) create mode 100644 circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp create mode 100644 circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/contract.hpp create mode 100644 circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.cpp create mode 100644 circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.hpp create mode 100644 circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function2.cpp create mode 100644 circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function2.hpp create mode 100644 circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/index.hpp create mode 100644 circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/init.hpp rename circuits/src/aztec3/circuits/kernel/private/{private_kernel.test.cpp => .test.cpp} (98%) diff --git a/circuits/specs/src/architecture/app-circuits/public-input-abis.md b/circuits/specs/src/architecture/app-circuits/public-input-abis.md index 50ab9aed450..88d3230e631 100644 --- a/circuits/specs/src/architecture/app-circuits/public-input-abis.md +++ b/circuits/specs/src/architecture/app-circuits/public-input-abis.md @@ -16,7 +16,7 @@ All private contract circuits have a fixed number of public inputs. Most of thes | *`customPublicOutputs` | Up to 32 circuit-specific values _returned by_ circuit. All of these inputs will be 'swallowed' by the private kernel snark. Hence any private outputs can safely be put here, which enables private circuits to call other private circuits, and pass private data to them. | | `emittedPublicInputs` | Public inputs which will be revealed to the 'public world' (L1 or L2). E.g. allowing certain inputs to be more-easily extracted by the RollupProcessor contract (rather than having to unpack this vast ABI object of inputs, which would cost too much hash-wise). An example of its usefulness is passing a value from L1 to L2 when doing an L1->L2 tx (see 'deposit' example in the other doc). TODO: consider whether this could be a single value, for simplicity. It could be a hash of data if more values need to be exposed. If so, we'll rename to `emittedPublicInputsHash`. | | *`executedCallback: {` | Populated if this circuit is a callback, so that the purported L1 Result to which this circuit is responding can be validated against the l1ResultsTree. | -| `- l1ResultHash`, | If this function is a callback function, following some L1 call, then it needs to expose the `l1ResultHash` to ensure the callback is actually using data emitted by L1. The preimage of the `l1ResultHash` will need to be passed in as private inputs to the circuit. Note: the `l1ResultHash` MUST be computed with a sha256 hash, because that's what the RollupProcessor will have used. This is unfortunate, as it forces apps to adhere to a specific calculation within their circuits. DISAGREE NOW - we don't need to calcualte this within the app circuit: we can just hash the custom_public_inputs and compare that hash against the L1ResultHash. | +| `- l1ResultHash`, | If this function is a callback function, following some L1 call, then it needs to expose the `l1ResultHash` to ensure the callback is actually using data emitted by L1. The preimage of the `l1ResultHash` will need to be passed in as private inputs to the circuit. Note: the `l1ResultHash` MUST be computed with a sha256 hash, because that's what the RollupProcessor will have used. This is unfortunate, as it forces apps to adhere to a specific calculation within their circuits. DISAGREE NOW - we don't need to calcualte this within the app circuit: we can just hash the custom_inputs and compare that hash against the L1ResultHash. | | `- l1ResultsTreeLeafIndex`, | Communicates to the rollup provider the correct leaf to prove membership against in the l1ResultsTree. Only if we don't want to hide the callback will the rollup provider perform the membership check (within the Base Rollup Circuit). Otherwise it'll be performed in the Private Kernel Circuit. | | `}`| | `outputCommitments` | output notes to be added into the `privateDataTree` (up to 16) | diff --git a/circuits/specs/src/noir-stuff/extremes/call-l1.md b/circuits/specs/src/noir-stuff/extremes/call-l1.md index b8d4ca2eaaf..d91f4940e24 100644 --- a/circuits/specs/src/noir-stuff/extremes/call-l1.md +++ b/circuits/specs/src/noir-stuff/extremes/call-l1.md @@ -104,7 +104,7 @@ fn swap_a_for_b( token_balance_a_new_salt, }, PUBLIC_INPUTS: { - custom_public_inputs: [ + custom_inputs: [ amount_a, ], emitted_public_inputs: {}, @@ -142,7 +142,7 @@ fn swap_a_for_b( ) { // Params: - let amount_a = PUBLIC_INPUTS.custom_public_inputs.amount_a + let amount_a = PUBLIC_INPUTS.custom_inputs.amount_a /******************************************************************************** * MAKE THE L1 CALL @@ -185,13 +185,13 @@ fn swap_a_for_b( // Some public inputs are omitted from this object when calculating a // _callback's_ call hash, because they depend on the (as of yet) // unknown L1 result. - custom_public_inputs: [ + custom_inputs: [ 0, // Inputs which will be 'result' values are set as 0. ], emitted_public_inputs: {}, // executed_callback: {...}, // Object is omitted, // since it's not known yet. - // TODO: maybe we ONLY need the custom_public_inputs??? + // TODO: maybe we ONLY need the custom_inputs??? // TODO: model the claim circuit, so I understand what's needed for // that context. output_commitments: { @@ -239,7 +239,7 @@ fn swap_a_for_b( is_callback: true, // <-- callback! }, public_inputs: { - custom_public_inputs: [ + custom_inputs: [ amount_a, // All args are known for a failure callback. (There's // no result being fed in). ], @@ -380,7 +380,7 @@ fn hide_amount_b( token_balance_b_new_salt, }, PUBLIC_INPUTS: { - custom_public_inputs: { + custom_inputs: { amount_b, }, emitted_public_inputs: {}, // lots of unused stuff denoted by {} or []. diff --git a/circuits/specs/src/noir-stuff/extremes/call-private.md b/circuits/specs/src/noir-stuff/extremes/call-private.md index 549f5090f7f..3f5801be68d 100644 --- a/circuits/specs/src/noir-stuff/extremes/call-private.md +++ b/circuits/specs/src/noir-stuff/extremes/call-private.md @@ -47,7 +47,7 @@ fn my_private_function( }, public_inputs: { // All of the public inputs of a private function call - custom_public_inputs: [ + custom_inputs: [ a, b, c, @@ -85,7 +85,7 @@ fn my_private_function( ] }, PUBLIC_INPUTS: { - custom_public_inputs: [ + custom_inputs: [ a, b, ], @@ -115,8 +115,8 @@ fn my_private_function( called_from_l1: false, } ) { - let a = PUBLIC_INPUTS.custom_public_inputs.a; - let b = PUBLIC_INPUTS.custom_public_inputs.b; + let a = PUBLIC_INPUTS.custom_inputs.a; + let b = PUBLIC_INPUTS.custom_inputs.b; let c = a + b; @@ -131,9 +131,9 @@ fn my_private_function( assert(call_stack_item.function_signature.vk_index == 0); // Check the correct parameters are being passed to the function: - assert(call_stack_item.public_inputs.custom_public_inputs[0] == a); - assert(call_stack_item.public_inputs.custom_public_inputs[1] == b); - assert(call_stack_item.public_inputs.custom_public_inputs[2] == c); + assert(call_stack_item.public_inputs.custom_inputs[0] == a); + assert(call_stack_item.public_inputs.custom_inputs[1] == b); + assert(call_stack_item.public_inputs.custom_inputs[2] == c); // The call context will be checked in the kernel snark, so we don't need // to check it here. diff --git a/circuits/specs/src/noir-stuff/extremes/call-public-same.md b/circuits/specs/src/noir-stuff/extremes/call-public-same.md index ce405e64c03..1a33cc0e6b8 100644 --- a/circuits/specs/src/noir-stuff/extremes/call-public-same.md +++ b/circuits/specs/src/noir-stuff/extremes/call-public-same.md @@ -110,8 +110,8 @@ fn my_private_function( called_from_l1: false, } ) { - let a = PUBLIC_INPUTS.custom_public_inputs.a; - let b = PUBLIC_INPUTS.custom_public_inputs.b; + let a = PUBLIC_INPUTS.custom_inputs.a; + let b = PUBLIC_INPUTS.custom_inputs.b; let c = a + b; @@ -128,9 +128,9 @@ fn my_private_function( assert(call_stack_item.function_signature.vkIndex == 0); // Check the correct parameters are being passed to the function: - assert(call_stack_item.public_inputs.custom_public_inputs[0] == a); - assert(call_stack_item.public_inputs.custom_public_inputs[1] == b); - assert(call_stack_item.public_inputs.custom_public_inputs[2] == c); + assert(call_stack_item.public_inputs.custom_inputs[0] == a); + assert(call_stack_item.public_inputs.custom_inputs[1] == b); + assert(call_stack_item.public_inputs.custom_inputs[2] == c); // The call context will be checked in the kernel snark, so we don't need // to check it here. diff --git a/circuits/specs/src/noir-stuff/extremes/call-public.md b/circuits/specs/src/noir-stuff/extremes/call-public.md index 63d12d20dbc..af0408c3bf8 100644 --- a/circuits/specs/src/noir-stuff/extremes/call-public.md +++ b/circuits/specs/src/noir-stuff/extremes/call-public.md @@ -112,8 +112,8 @@ fn my_private_function( called_from_l1: false, } ) { - let a = PUBLIC_INPUTS.custom_public_inputs.a; - let b = PUBLIC_INPUTS.custom_public_inputs.b; + let a = PUBLIC_INPUTS.custom_inputs.a; + let b = PUBLIC_INPUTS.custom_inputs.b; let c = a + b; @@ -128,9 +128,9 @@ fn my_private_function( assert(call_stack_item.function_signature.vkIndex == 0); // Check the correct parameters are being passed to the function: - assert(call_stack_item.public_inputs.custom_public_inputs[0] == a); - assert(call_stack_item.public_inputs.custom_public_inputs[1] == b); - assert(call_stack_item.public_inputs.custom_public_inputs[2] == c); + assert(call_stack_item.public_inputs.custom_inputs[0] == a); + assert(call_stack_item.public_inputs.custom_inputs[1] == b); + assert(call_stack_item.public_inputs.custom_inputs[2] == c); // The call context will be checked in the kernel snark, so we don't need // to check it here. diff --git a/circuits/specs/src/noir-stuff/extremes/decr-private-owned.md b/circuits/specs/src/noir-stuff/extremes/decr-private-owned.md index 622513f08c2..e6aba85e6af 100644 --- a/circuits/specs/src/noir-stuff/extremes/decr-private-owned.md +++ b/circuits/specs/src/noir-stuff/extremes/decr-private-owned.md @@ -63,7 +63,7 @@ fn decrement_my_own_private_state( x_new_salt, }, PUBLIC_INPUTS: { - custom_public_inputs: {}, // lots of unused stuff denoted by {} or []. + custom_inputs: {}, // lots of unused stuff denoted by {} or []. emitted_public_inputs: {}, executed_callback: {}, @@ -169,7 +169,7 @@ fn decrement_my_own_private_state( x_new_salt, }, PUBLIC_INPUTS: { - custom_public_inputs: {}, // lots of unused stuff denoted by {} or []. + custom_inputs: {}, // lots of unused stuff denoted by {} or []. emitted_public_inputs: {}, executed_callback: {}, diff --git a/circuits/specs/src/noir-stuff/extremes/deploy-contract.md b/circuits/specs/src/noir-stuff/extremes/deploy-contract.md index a9ec63dfa74..b4b28a1809a 100644 --- a/circuits/specs/src/noir-stuff/extremes/deploy-contract.md +++ b/circuits/specs/src/noir-stuff/extremes/deploy-contract.md @@ -93,7 +93,7 @@ fn deploy( ], }, PUBLIC_INPUTS: { - custom_public_inputs: [], + custom_inputs: [], emitted_public_inputs: {}, executed_callback: {}, @@ -137,8 +137,8 @@ fn deploy( // Check the correct parameters are being passed to the constructors: - assert(private_constructor_public_inputs.custom_public_inputs[0] == 123); - assert(public_constructor_public_inputs.custom_public_inputs[0] == 456); + assert(private_constructor_public_inputs.custom_inputs[0] == 123); + assert(public_constructor_public_inputs.custom_inputs[0] == 456); // The call contexts will be checked in the kernel snark, so we don't need // to check it here. @@ -183,13 +183,13 @@ fn private_constructor( b_new_salt, }, PUBLIC_INPUTS: { - custom_public_inputs: [ + custom_inputs: [ _b, // Although this param was decorated as `secret`, it cannot be a // private input to the circuit, because it's passed into the circuit // by another circuit (which must validate the correctness of the // value being passed in). // It will still be hidden from the world, since the private kernel - // circuit will swallow all custom_public_inputs, unless they're also + // circuit will swallow all custom_inputs, unless they're also // emitted as events. // TODO: prevent `secret` params from being exposed by an app via // the `emittedPublicInputs` or call stacks, so that the kernel circuit @@ -280,7 +280,7 @@ fn public_constructor( called_from_l1: false, } ) { - let amount = PUBLIC_INPUTS.custom_public_inputs.amount; + let amount = PUBLIC_INPUTS.custom_inputs.amount; // Perform the calculation (for example): require(a_storage_slot == 1); diff --git a/circuits/specs/src/noir-stuff/extremes/edit-public.md b/circuits/specs/src/noir-stuff/extremes/edit-public.md index 78c44109adc..4f94a129392 100644 --- a/circuits/specs/src/noir-stuff/extremes/edit-public.md +++ b/circuits/specs/src/noir-stuff/extremes/edit-public.md @@ -53,7 +53,7 @@ fn my_public_function( called_from_l1: false, } ) { - let amount = PUBLIC_INPUTS.custom_public_inputs.amount; + let amount = PUBLIC_INPUTS.custom_inputs.amount; // Perform the calculation: require(x_storage_slot == 1); diff --git a/circuits/specs/src/noir-stuff/extremes/emit-event.md b/circuits/specs/src/noir-stuff/extremes/emit-event.md index 67b8fb06e58..d9021a90749 100644 --- a/circuits/specs/src/noir-stuff/extremes/emit-event.md +++ b/circuits/specs/src/noir-stuff/extremes/emit-event.md @@ -68,7 +68,7 @@ fn called_by_l1( // none shown }, PUBLIC_INPUTS: { - custom_public_inputs: [ + custom_inputs: [ a, b, ], diff --git a/circuits/specs/src/noir-stuff/extremes/incr-private-not-owned.md b/circuits/specs/src/noir-stuff/extremes/incr-private-not-owned.md index 7a37b8012c3..c6383ecf7cd 100644 --- a/circuits/specs/src/noir-stuff/extremes/incr-private-not-owned.md +++ b/circuits/specs/src/noir-stuff/extremes/incr-private-not-owned.md @@ -36,7 +36,7 @@ fn increment_someone_elses_private_state( x_new_salt, }, PUBLIC_INPUTS: { - custom_public_inputs: {}, // lots of unused stuff denoted by {} or []. + custom_inputs: {}, // lots of unused stuff denoted by {} or []. emitted_public_inputs: {}, executed_callback: {}, diff --git a/circuits/specs/src/noir-stuff/extremes/incr-private-owned.md b/circuits/specs/src/noir-stuff/extremes/incr-private-owned.md index 7bf3e3ebd7d..bc4150c99a0 100644 --- a/circuits/specs/src/noir-stuff/extremes/incr-private-owned.md +++ b/circuits/specs/src/noir-stuff/extremes/incr-private-owned.md @@ -81,7 +81,7 @@ fn increment_my_own_private_state( x_new_salt, }, PUBLIC_INPUTS: { - custom_public_inputs: {}, // lots of unused stuff denoted by {} or []. + custom_inputs: {}, // lots of unused stuff denoted by {} or []. emitted_public_inputs: {}, executed_callback: {}, @@ -239,7 +239,7 @@ fn increment_someone_elses_private_state( x_new_salt, }, PUBLIC_INPUTS: { - custom_public_inputs: {}, // lots of unused stuff denoted by {} or []. + custom_inputs: {}, // lots of unused stuff denoted by {} or []. emitted_public_inputs: {}, executed_callback: {}, diff --git a/circuits/specs/src/noir-stuff/extremes/read-public.md b/circuits/specs/src/noir-stuff/extremes/read-public.md index 4fdaebad1d3..7b5c30d8931 100644 --- a/circuits/specs/src/noir-stuff/extremes/read-public.md +++ b/circuits/specs/src/noir-stuff/extremes/read-public.md @@ -53,7 +53,7 @@ fn my_private_function( called_from_l1: false, } ) { - let amount = PUBLIC_INPUTS.custom_public_inputs.amount; + let amount = PUBLIC_INPUTS.custom_inputs.amount; // Perform the calculation: require(x_storage_slot == 1); diff --git a/circuits/src/aztec3/circuits/abis/abis.test.cpp b/circuits/src/aztec3/circuits/abis/abis.test.cpp index c219b9246d2..126bc0b873c 100644 --- a/circuits/src/aztec3/circuits/abis/abis.test.cpp +++ b/circuits/src/aztec3/circuits/abis/abis.test.cpp @@ -16,7 +16,7 @@ class abi_tests : public ::testing::Test {}; TEST(abi_tests, test_native_function_signature) { FunctionSignature function_signature = { - .contract_address = 10, + // .contract_address = 10, .vk_index = 11, .is_private = false, .is_constructor = false, @@ -33,7 +33,7 @@ TEST(abi_tests, test_native_function_signature) TEST(abi_tests, test_native_to_circuit_function_signature) { FunctionSignature native_function_signature = { - .contract_address = 10, + // .contract_address = 10, .vk_index = 11, .is_private = false, .is_constructor = false, @@ -75,7 +75,7 @@ TEST(abi_tests, test_native_to_circuit_call_context) TEST(abi_tests, test_native_public_inputs) { PublicCircuitPublicInputs public_inputs = { - .custom_public_inputs = { 1, 2, 3, 4, 5, 6, 7, 8 }, + .custom_inputs = { 1, 2, 3, 4, 5, 6, 7, 8 }, .custom_outputs = { 9, 10, 11, 12 }, .emitted_public_inputs = { 13, 14, 15, 16 }, .emitted_outputs = { 17, 18, 19, 20 }, @@ -95,7 +95,7 @@ TEST(abi_tests, test_native_public_inputs) TEST(abi_tests, test_native_to_circuit_public_circuit_public_inputs) { PublicCircuitPublicInputs native_public_inputs = { - .custom_public_inputs = { 1, 2, 3, 4, 5, 6, 7, 8 }, + .custom_inputs = { 1, 2, 3, 4, 5, 6, 7, 8 }, .custom_outputs = { 9, 10, 11, 12 }, .emitted_public_inputs = { 13, 14, 15, 16 }, .emitted_outputs = { 17, 18, 19, 20 }, @@ -120,7 +120,7 @@ TEST(abi_tests, test_native_to_circuit_public_circuit_public_inputs) TEST(abi_tests, test_native_call_stack_item) { PublicCircuitPublicInputs public_inputs = { - .custom_public_inputs = { 1, 2, 3, 4, 5, 6, 7, 8 }, + .custom_inputs = { 1, 2, 3, 4, 5, 6, 7, 8 }, .custom_outputs = { 9, 10, 11, 12 }, .emitted_public_inputs = { 13, 14, 15, 16 }, .emitted_outputs = { 17, 18, 19, 20 }, @@ -136,7 +136,7 @@ TEST(abi_tests, test_native_call_stack_item) CallStackItem call_stack_item = { .function_signature = { - .contract_address = 10, + // .contract_address = 10, .vk_index = 11, .is_private = false, .is_constructor = false, @@ -156,7 +156,7 @@ TEST(abi_tests, test_native_call_stack_item) TEST(abi_tests, test_native_to_circuit_call_stack_item) { PublicCircuitPublicInputs public_inputs = { - .custom_public_inputs = { 1, 2, 3, 4, 5, 6, 7, 8 }, + .custom_inputs = { 1, 2, 3, 4, 5, 6, 7, 8 }, .custom_outputs = { 9, 10, 11, 12 }, .emitted_public_inputs = { 13, 14, 15, 16 }, .emitted_outputs = { 17, 18, 19, 20 }, @@ -172,7 +172,7 @@ TEST(abi_tests, test_native_to_circuit_call_stack_item) CallStackItem native_call_stack_item = { .function_signature = { - .contract_address = 10, + // .contract_address = 10, .vk_index = 11, .is_private = false, .is_constructor = false, diff --git a/circuits/src/aztec3/circuits/abis/function_signature.hpp b/circuits/src/aztec3/circuits/abis/function_signature.hpp index e8621487dac..dad71107ed8 100644 --- a/circuits/src/aztec3/circuits/abis/function_signature.hpp +++ b/circuits/src/aztec3/circuits/abis/function_signature.hpp @@ -20,7 +20,8 @@ template struct FunctionSignature { typedef typename NCT::grumpkin_point grumpkin_point; typedef typename NCT::fr fr; - address contract_address; + // address contract_address; // TODO: remove contract_address from function_signature? The other stuff is all known + // before deployment. uint32 vk_index; boolean is_private = false; boolean is_constructor = false; @@ -37,7 +38,7 @@ template struct FunctionSignature { auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; FunctionSignature> function_signature = { - to_ct(contract_address), + // to_ct(contract_address), to_ct(vk_index), to_ct(is_private), to_ct(is_constructor), @@ -50,7 +51,7 @@ template struct FunctionSignature { { static_assert(!(std::is_same::value)); - contract_address.to_field().set_public(); + // contract_address.to_field().set_public(); fr(vk_index).set_public(); fr(is_private).set_public(); fr(is_constructor).set_public(); @@ -59,7 +60,7 @@ template struct FunctionSignature { fr hash() const { std::vector inputs = { - contract_address.to_field(), + // contract_address.to_field(), fr(vk_index), fr(is_private), fr(is_constructor), @@ -73,7 +74,7 @@ template void read(uint8_t const*& it, FunctionSignature& fu { using serialize::read; - read(it, function_signature.contract_address); + // read(it, function_signature.contract_address); read(it, function_signature.vk_index); read(it, function_signature.is_private); read(it, function_signature.is_constructor); @@ -83,7 +84,7 @@ template void write(std::vector& buf, FunctionSignature< { using serialize::write; - write(buf, function_signature.contract_address); + // write(buf, function_signature.contract_address); write(buf, function_signature.vk_index); write(buf, function_signature.is_private); write(buf, function_signature.is_constructor); @@ -91,8 +92,7 @@ template void write(std::vector& buf, FunctionSignature< template std::ostream& operator<<(std::ostream& os, FunctionSignature const& function_signature) { - return os << "contract_address: " << function_signature.contract_address << "\n" - << "vk_index: " << function_signature.vk_index << "\n" + return os << "vk_index: " << function_signature.vk_index << "\n" << "is_private: " << function_signature.is_private << "\n" << "is_constructor: " << function_signature.is_constructor << "\n"; } diff --git a/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp b/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp index 77fb22bfaf9..94ec221c606 100644 --- a/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp +++ b/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp @@ -24,7 +24,9 @@ template class PrivateCircuitPublicInputs { public: CallContext call_context; - std::array custom_public_inputs; + std::array custom_inputs; + std::array custom_outputs; + std::array emitted_public_inputs; ExecutedCallback executed_callback; @@ -52,7 +54,9 @@ template class PrivateCircuitPublicInputs { PrivateCircuitPublicInputs> pis = { to_circuit_type(call_context), - to_ct(custom_public_inputs), + to_ct(custom_inputs), + to_ct(custom_outputs), + to_ct(emitted_public_inputs), to_circuit_type(executed_callback), @@ -80,7 +84,9 @@ template class PrivateCircuitPublicInputs { inputs.push_back(call_context.hash()); - spread_arr_into_vec(custom_public_inputs, inputs); + spread_arr_into_vec(custom_inputs, inputs); + spread_arr_into_vec(custom_outputs, inputs); + spread_arr_into_vec(emitted_public_inputs, inputs); inputs.push_back(executed_callback.hash()); @@ -119,7 +125,9 @@ template class OptionalPrivateCircuitPublicInputs { public: std::optional> call_context; - std::array custom_public_inputs; + std::array custom_inputs; + std::array custom_outputs; + std::array emitted_public_inputs; std::optional> executed_callback; @@ -140,7 +148,9 @@ template class OptionalPrivateCircuitPublicInputs { OptionalPrivateCircuitPublicInputs( std::optional> const& call_context, - std::array const& custom_public_inputs, + std::array const& custom_inputs, + std::array const& custom_outputs, + std::array const& emitted_public_inputs, std::optional> const& executed_callback, @@ -156,7 +166,8 @@ template class OptionalPrivateCircuitPublicInputs { opt_fr const& old_private_data_tree_root) : call_context(call_context) - , custom_public_inputs(custom_public_inputs) + , custom_inputs(custom_inputs) + , custom_outputs(custom_outputs) , emitted_public_inputs(emitted_public_inputs) , executed_callback(executed_callback) , output_commitments(output_commitments) @@ -177,7 +188,9 @@ template class OptionalPrivateCircuitPublicInputs { new_inputs.call_context = std::nullopt; - new_inputs.custom_public_inputs.fill(std::nullopt); + new_inputs.custom_inputs.fill(std::nullopt); + new_inputs.custom_outputs.fill(std::nullopt); + new_inputs.emitted_public_inputs.fill(std::nullopt); new_inputs.executed_callback = std::nullopt; @@ -222,7 +235,9 @@ template class OptionalPrivateCircuitPublicInputs { make_unused_element_zero(composer, call_context); - make_unused_array_elements_zero(composer, custom_public_inputs); + make_unused_array_elements_zero(composer, custom_inputs); + make_unused_array_elements_zero(composer, custom_outputs); + make_unused_array_elements_zero(composer, emitted_public_inputs); make_unused_element_zero(composer, executed_callback); @@ -251,7 +266,9 @@ template class OptionalPrivateCircuitPublicInputs { (*call_context).set_public(); - set_array_public(custom_public_inputs); + set_array_public(custom_inputs); + set_array_public(custom_outputs); + set_array_public(emitted_public_inputs); (*executed_callback).set_public(); @@ -282,7 +299,9 @@ template class OptionalPrivateCircuitPublicInputs { OptionalPrivateCircuitPublicInputs> pis = { to_circuit_type(call_context), - to_ct(custom_public_inputs), + to_ct(custom_inputs), + to_ct(custom_outputs), + to_ct(emitted_public_inputs), to_circuit_type(executed_callback), @@ -314,7 +333,9 @@ template class OptionalPrivateCircuitPublicInputs { OptionalPrivateCircuitPublicInputs pis = { to_native_type(call_context), - to_nt(custom_public_inputs), + to_nt(custom_inputs), + to_nt(custom_outputs), + to_nt(emitted_public_inputs), to_native_type(executed_callback), @@ -347,7 +368,9 @@ template class OptionalPrivateCircuitPublicInputs { inputs.push_back((*call_context).hash()); - spread_arr_opt_into_vec(custom_public_inputs, inputs); + spread_arr_opt_into_vec(custom_inputs, inputs); + spread_arr_opt_into_vec(custom_outputs, inputs); + spread_arr_opt_into_vec(emitted_public_inputs, inputs); inputs.push_back((*executed_callback).hash()); @@ -374,7 +397,9 @@ template class OptionalPrivateCircuitPublicInputs { return PrivateCircuitPublicInputs{ .call_context = call_context.value(), - .custom_public_inputs = map(custom_public_inputs, get_value), + .custom_inputs = map(custom_inputs, get_value), + .custom_outputs = map(custom_outputs, get_value), + .emitted_public_inputs = map(emitted_public_inputs, get_value), .executed_callback = executed_callback.value(), @@ -416,50 +441,6 @@ template class OptionalPrivateCircuitPublicInputs { vec.insert(vec.end(), &arr[0], &arr[0] + arr_size); } - /// TODO: unused? - // template bool check_all_elements_populated() - // { - // static_assert((std::is_same, NCT>::value)); - - // bool check_if_populated = [&](std::optional& e) { - // if (!e) { - // return false; - // } - // return true; - // }; - - // bool still_populated = true; - - // // call_context is not optional. - - // still_populated &= std::all_of(custom_public_inputs.begin(), custom_public_inputs.end(), check_if_populated); - // still_populated &= std::all_of(emitted_public_inputs.begin(), emitted_public_inputs.end(), - // check_if_populated); - - // // executed_callback.make_unused_inputs_zero(composer); - - // still_populated &= std::all_of(output_commitments.begin(), output_commitments.end(), check_if_populated); - // still_populated &= std::all_of(input_nullifiers.begin(), input_nullifiers.end(), check_if_populated); - - // still_populated &= std::all_of(private_call_stack.begin(), private_call_stack.end(), check_if_populated); - // still_populated &= std::all_of(public_call_stack.begin(), public_call_stack.end(), check_if_populated); - // still_populated &= std::all_of( - // contract_deployment_call_stack.begin(), contract_deployment_call_stack.end(), check_if_populated); - // still_populated &= std::all_of(partial_l1_call_stack.begin(), partial_l1_call_stack.end(), - // check_if_populated); still_populated &= std::all_of(callback_stack.begin(), callback_stack.end(), - // check_if_populated); - - // still_populated &= check_if_populated(old_private_data_tree_root); - // still_populated &= check_if_populated(is_fee_payment); - // still_populated &= check_if_populated(pay_fee_from_l1); - // still_populated &= check_if_populated(pay_fee_from_public_l2); - // still_populated &= check_if_populated(called_from_l1); - - // all_elements_populated = still_populated; - - // return all_elements_populated; - // } - template void make_unused_array_elements_zero(Composer& composer, std::array, SIZE>& arr) { @@ -540,7 +521,8 @@ void read(uint8_t const*& it, OptionalPrivateCircuitPublicInputs& private_c OptionalPrivateCircuitPublicInputs& pis = private_circuit_public_inputs; read(it, pis.call_context); - read(it, pis.custom_public_inputs); + read(it, pis.custom_inputs); + read(it, pis.custom_outputs); read(it, pis.emitted_public_inputs); read(it, pis.executed_callback); read(it, pis.output_commitments); @@ -561,7 +543,8 @@ void write(std::vector& buf, OptionalPrivateCircuitPublicInputs co OptionalPrivateCircuitPublicInputs const& pis = private_circuit_public_inputs; write(buf, pis.call_context); - write(buf, pis.custom_public_inputs); + write(buf, pis.custom_inputs); + write(buf, pis.custom_outputs); write(buf, pis.emitted_public_inputs); write(buf, pis.executed_callback); write(buf, pis.output_commitments); @@ -580,7 +563,8 @@ std::ostream& operator<<(std::ostream& os, OptionalPrivateCircuitPublicInputs const& pis = private_circuit_public_inputs; return os << "call_context: " << pis.call_context << "\n" - << "custom_public_inputs: " << pis.custom_public_inputs << "\n" + << "custom_inputs: " << pis.custom_inputs << "\n" + << "custom_outputs: " << pis.custom_outputs << "\n" << "emitted_public_inputs: " << pis.emitted_public_inputs << "\n" << "executed_callback: " << pis.executed_callback << "\n" << "output_commitments: " << pis.output_commitments << "\n" diff --git a/circuits/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp b/circuits/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp index abf35d9cdf4..c013a27c611 100644 --- a/circuits/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp +++ b/circuits/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp @@ -23,7 +23,7 @@ template struct PublicCircuitPublicInputs { // address msg_sender; // TODO! - std::array custom_public_inputs; + std::array custom_inputs; std::array custom_outputs; std::array emitted_public_inputs; @@ -52,7 +52,7 @@ template struct PublicCircuitPublicInputs { static PublicCircuitPublicInputs empty() { PublicCircuitPublicInputs pis = { - std::array::fill(0), + std::array::fill(0), std::array::fill(0), std::array::fill(0), @@ -84,7 +84,7 @@ template struct PublicCircuitPublicInputs { auto to_circuit_type = [&](auto& e) { return e.to_circuit_type(composer); }; PublicCircuitPublicInputs> pis = { - .custom_public_inputs = to_ct(custom_public_inputs), + .custom_inputs = to_ct(custom_inputs), .custom_outputs = to_ct(custom_outputs), .emitted_public_inputs = to_ct(emitted_public_inputs), .emitted_outputs = to_ct(emitted_outputs), @@ -115,7 +115,7 @@ template void read(uint8_t const*& it, PublicCircuitPublicInputs< using serialize::read; PublicCircuitPublicInputs& pis = private_circuit_public_inputs; - read(it, pis.custom_public_inputs); + read(it, pis.custom_inputs); read(it, pis.custom_outputs); read(it, pis.emitted_public_inputs); read(it, pis.emitted_ouputs); @@ -139,7 +139,7 @@ void write(std::vector& buf, PublicCircuitPublicInputs const& priv PublicCircuitPublicInputs const& pis = private_circuit_public_inputs; - write(buf, pis.custom_public_inputs); + write(buf, pis.custom_inputs); write(buf, pis.custom_outputs); write(buf, pis.emitted_public_inputs); write(buf, pis.emitted_ouputs); @@ -161,7 +161,7 @@ std::ostream& operator<<(std::ostream& os, PublicCircuitPublicInputs const& { PublicCircuitPublicInputs const& pis = private_circuit_public_inputs; - return os << "custom_public_inputs: " << pis.custom_public_inputs << "\n" + return os << "custom_inputs: " << pis.custom_inputs << "\n" << "custom_outputs: " << pis.custom_outputs << "\n" << "emitted_public_inputs: " << pis.emitted_public_inputs << "\n" << "emitted_outputs: " << pis.emitted_outputs << "\n" diff --git a/circuits/src/aztec3/circuits/apps/contract_factory.hpp b/circuits/src/aztec3/circuits/apps/contract_factory.hpp index d203ccea996..61aa0280ef1 100644 --- a/circuits/src/aztec3/circuits/apps/contract_factory.hpp +++ b/circuits/src/aztec3/circuits/apps/contract_factory.hpp @@ -1,14 +1,15 @@ #pragma once -#include -#include -#include +// #include +// #include +// #include #include -#include -#include "private_state_note.hpp" +// #include +// #include "function_executor.hpp" +// #include "private_state_note.hpp" #include "private_state_var.hpp" #include "function.hpp" #include "l1_function_interface.hpp" -#include "oracle_wrapper.hpp" +// #include "oracle_wrapper.hpp" namespace aztec3::circuits::apps { @@ -16,97 +17,64 @@ using plonk::stdlib::witness_t; using plonk::stdlib::types::CircuitTypes; using NT = plonk::stdlib::types::NativeTypes; using aztec3::circuits::abis::FunctionSignature; -using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; +// using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; -template class ContractFactory { +template class FunctionExecutionContext; + +template class Contract { typedef CircuitTypes CT; typedef typename CT::fr fr; typedef typename CT::uint32 uint32; public: - Composer& composer; - OracleWrapperInterface& oracle; + FunctionExecutionContext& exec_ctx; const std::string contract_name; + fr state_counter = 0; - PrivateStateFactory private_state_factory; - OptionalPrivateCircuitPublicInputs private_circuit_public_inputs; - // UnpackedPrivateCircuitData unpacked_private_circuit_data; + std::vector state_names; + std::map> private_state_vars; std::map> function_signatures; std::map> l1_functions; - ContractFactory(Composer& composer, OracleWrapperInterface& oracle, std::string contract_name) - : composer(composer) - , oracle(oracle) + Contract(FunctionExecutionContext& exec_ctx, std::string const& contract_name) + : exec_ctx(exec_ctx) , contract_name(contract_name) - , private_state_factory(PrivateStateFactory(composer, oracle, contract_name)) - , private_circuit_public_inputs(OptionalPrivateCircuitPublicInputs::create()) { - private_circuit_public_inputs.call_context = oracle.get_call_context(); + exec_ctx.register_contract(this); } - void set_functions(std::vector> const& functions) - { - for (uint32_t i = 0; i < functions.size(); ++i) { - const auto& function = functions[i]; - if (function_signatures.contains(function.name)) { - throw_or_abort("Name already exists"); - } - function_signatures[function.name] = FunctionSignature{ - .contract_address = oracle.get_this_contract_address(), - .vk_index = uint32(i), - .is_private = function.is_private, - .is_constructor = function.is_constructor, - }; - } - }; - - FunctionSignature get_function_signature_by_name(std::string const& name) - { - if (!function_signatures.contains(name)) { - throw_or_abort("function signature not found"); - } - return function_signatures[name]; - } + void set_functions(std::vector> const& functions); - void import_l1_function(L1FunctionInterfaceStruct const& l1_function_struct) - { - L1FunctionInterface l1_function = L1FunctionInterface(this, l1_function_struct); - l1_functions.insert(std::make_pair(l1_function_struct.function_name, l1_function)); - }; + // TODO: return some Function class which has a `call` method... + // FunctionSignature get_function(std::string name) { return function_signature[name]; } - L1FunctionInterface& get_l1_function(std::string const& name) - { - if (!l1_functions.contains(name)) { - throw_or_abort("L1 function not found. Make sure to import_l1_function()"); - } - return l1_functions[name]; - } + FunctionSignature get_function_signature_by_name(std::string const& name); + + void import_l1_function(L1FunctionInterfaceStruct const& l1_function_struct); + + L1FunctionInterface& get_l1_function(std::string const& name); + + void push_new_state_name(std::string const& name); PrivateStateVar& new_private_state(std::string const& name, - PrivateStateType const& private_state_type = PARTITIONED) - { - return private_state_factory.new_private_state(name, private_state_type); - }; + PrivateStateType const& private_state_type = PARTITIONED); // For initialising a private state which is a mapping. PrivateStateVar& new_private_state(std::string const& name, std::vector const& mapping_key_names, - PrivateStateType const& private_state_type = PARTITIONED) - { - return private_state_factory.new_private_state(name, mapping_key_names, private_state_type); - }; + PrivateStateType const& private_state_type = PARTITIONED); - PrivateStateVar& get_private_state(std::string const& name) { return private_state_factory.get(name); }; - - void finalise() - { - private_state_factory.finalise(); - private_circuit_public_inputs.set_commitments(private_state_factory.new_commitments); - private_circuit_public_inputs.set_nullifiers(private_state_factory.new_nullifiers); - private_circuit_public_inputs.set_public(composer); - }; + PrivateStateVar& get_private_state(std::string const& name); }; -} // namespace aztec3::circuits::apps \ No newline at end of file +} // namespace aztec3::circuits::apps + +// Importing in this way (rather than explicit instantiation of a template class at the bottom of a .cpp file) preserves +// the following: +// - We retain implicit instantiation of templates, meaning we can pick and choose (with static_assert) which class +// methods support native, +// circuit or both types. +// - We don't implement method definitions in this file, to avoid a circular dependency with exec_ctx.hpp. +#include "contract_factory.tpp" \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/contract_factory.tpp b/circuits/src/aztec3/circuits/apps/contract_factory.tpp new file mode 100644 index 00000000000..a2992bdc01c --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/contract_factory.tpp @@ -0,0 +1,107 @@ +#pragma once +#include +#include +#include +#include +// #include +#include "function_executor.hpp" +// #include "private_state_note.hpp" +#include "private_state_var.hpp" +#include "function.hpp" +#include "l1_function_interface.hpp" +// #include "oracle_wrapper.hpp" + +namespace aztec3::circuits::apps { + +using plonk::stdlib::witness_t; +using plonk::stdlib::types::CircuitTypes; +using NT = plonk::stdlib::types::NativeTypes; +using aztec3::circuits::abis::FunctionSignature; +// using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; + +template +void Contract::set_functions(std::vector>> const& functions) +{ + for (uint32_t i = 0; i < functions.size(); ++i) { + const auto& function = functions[i]; + if (function_signatures.contains(function.name)) { + throw_or_abort("Name already exists"); + } + function_signatures[function.name] = FunctionSignature{ + // .contract_address = exec.oracle.get_this_contract_address(), + .vk_index = uint32(i), + .is_private = function.is_private, + .is_constructor = function.is_constructor, + }; + } +}; + +// TODO: return some Function class which has a `call` method... +// FunctionSignature get_function(std::string name) { return function_signature[name]; } + +template +FunctionSignature> Contract::get_function_signature_by_name(std::string const& name) +{ + if (!function_signatures.contains(name)) { + throw_or_abort("function signature not found"); + } + return function_signatures[name]; +} + +template +void Contract::import_l1_function(L1FunctionInterfaceStruct const& l1_function_struct) +{ + L1FunctionInterface l1_function = L1FunctionInterface(this, l1_function_struct); + l1_functions.insert(std::make_pair(l1_function_struct.function_name, l1_function)); +}; + +template L1FunctionInterface& Contract::get_l1_function(std::string const& name) +{ + if (!l1_functions.contains(name)) { + throw_or_abort("L1 function not found. Make sure to import_l1_function()"); + } + return l1_functions[name]; +} + +template void Contract::push_new_state_name(std::string const& name) +{ + if (index_of(state_names, name) == -1) { + state_names.push_back(name); + return; + } + throw_or_abort("name already exists"); +} + +template +PrivateStateVar& Contract::new_private_state(std::string const& name, + PrivateStateType const& private_state_type) +{ + push_new_state_name(name); + PrivateStateVar private_state_var = + PrivateStateVar(&exec_ctx, private_state_type, name, state_counter++); + private_state_vars.insert(std::make_pair(name, private_state_var)); + return private_state_vars[name]; +}; + +// For initialising a private state which is a mapping. +template +PrivateStateVar& Contract::new_private_state(std::string const& name, + std::vector const& mapping_key_names, + PrivateStateType const& private_state_type) +{ + push_new_state_name(name); + PrivateStateVar private_state_var = + PrivateStateVar(&exec_ctx, private_state_type, name, state_counter++, mapping_key_names); + private_state_vars.insert(std::make_pair(name, private_state_var)); + return private_state_vars[name]; +}; + +template PrivateStateVar& Contract::get_private_state(std::string const& name) +{ + if (!private_state_vars.contains(name)) { + throw_or_abort("name not found"); + } + return private_state_vars[name]; +}; + +} // namespace aztec3::circuits::apps \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/function_executor.hpp b/circuits/src/aztec3/circuits/apps/function_executor.hpp index a908f90ee52..b952c15f219 100644 --- a/circuits/src/aztec3/circuits/apps/function_executor.hpp +++ b/circuits/src/aztec3/circuits/apps/function_executor.hpp @@ -1,52 +1,100 @@ -// #pragma once -// #include -// #include -// #include -// #include -// #include -// #include "private_state_note.hpp" +#pragma once +#include +#include +#include +#include +#include +#include "contract_factory.hpp" +#include "nullifier_preimage.hpp" +#include "oracle_wrapper.hpp" +#include "private_state_note.hpp" // #include "private_state_var.hpp" // #include "function.hpp" // #include "l1_function_interface.hpp" -// #include "oracle_wrapper.hpp" - -// namespace aztec3::circuits::apps { - -// using plonk::stdlib::witness_t; -// using plonk::stdlib::types::CircuitTypes; -// using NT = plonk::stdlib::types::NativeTypes; -// using aztec3::circuits::abis::FunctionSignature; -// using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; - -// template class FunctionExecutor { -// typedef CircuitTypes CT; -// typedef typename CT::fr fr; - -// public: -// Composer& composer; -// OracleWrapperInterface& oracle; -// ContractFactory& contract_factory; -// PrivateStateFactory& private_state_factory; -// OptionalPrivateCircuitPublicInputs private_circuit_public_inputs; -// // UnpackedData unpacked_data; - -// FunctionExecutor(ContractFactory& contract_factory) -// : composer(contract_factory.composer) -// , oracle(contract_factory.oracle) -// , contract_factory(contract_factory) -// , private_state_factory(contract_factory.private_state_factory) -// , private_circuit_public_inputs(OptionalPrivateCircuitPublicInputs::create()) -// { -// private_circuit_public_inputs.call_context = oracle.get_call_context(); -// } - -// void finalise() -// { -// private_state_factory.finalise(); -// private_circuit_public_inputs.set_commitments(private_state_factory.commitments); -// private_circuit_public_inputs.set_nullifiers(private_state_factory.nullifiers); -// private_circuit_public_inputs.set_public(composer); -// }; -// }; - -// } // namespace aztec3::circuits::apps \ No newline at end of file + +namespace aztec3::circuits::apps { + +using plonk::stdlib::witness_t; +using plonk::stdlib::types::CircuitTypes; +using NT = plonk::stdlib::types::NativeTypes; +using aztec3::circuits::abis::FunctionSignature; +using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; + +template class FunctionExecutionContext { + typedef CircuitTypes CT; + typedef typename CT::fr fr; + + public: + Composer& composer; + OracleWrapperInterface& oracle; + + Contract* contract = nullptr; + + OptionalPrivateCircuitPublicInputs private_circuit_public_inputs; + // UnpackedData unpacked_data; + + std::vector> new_private_state_notes; + std::vector new_commitments; + std::vector> new_nullifier_preimages; + std::vector new_nullifiers; + + FunctionExecutionContext(Composer& composer, OracleWrapperInterface& oracle) + : composer(composer) + , oracle(oracle) + , private_circuit_public_inputs(OptionalPrivateCircuitPublicInputs::create()) + { + private_circuit_public_inputs.call_context = oracle.get_call_context(); + } + + void register_contract(Contract* contract) + { + if (this->contract != nullptr) { + throw_or_abort("contract already assigned to this FunctionExecutionContext"); + } + this->contract = contract; + } + + void push_new_note(PrivateStateNote const private_state_note) + { + new_private_state_notes.push_back(private_state_note); + } + + void push_new_nullifier_data(fr nullifier, NullifierPreimage nullifier_preimage) + { + new_nullifiers.push_back(nullifier); + new_nullifier_preimages.push_back(nullifier_preimage); + } + + void finalise_private_state_changes() + { + if (new_private_state_notes.size() > new_nullifier_preimages.size()) { + // We've created more commitments than nullifiers so far. But we want to inject an input_nullifier into each + // new commitment. So, let's create more dummy nullifiers. + const auto& msg_sender_private_key = oracle.get_msg_sender_private_key(); + for (size_t i = new_nullifier_preimages.size(); i < new_private_state_notes.size(); ++i) { + auto dummy_commitment = oracle.generate_random_element(); + new_nullifier_preimages.push_back(NullifierPreimage{ + dummy_commitment, + msg_sender_private_key, + false, + }); + new_nullifiers.push_back( + PrivateStateNote::compute_dummy_nullifier(dummy_commitment, msg_sender_private_key)); + } + } + for (size_t i = 0; i < new_private_state_notes.size(); ++i) { + new_private_state_notes[i].preimage.input_nullifier = new_nullifiers[i]; + new_commitments.push_back(new_private_state_notes[i].compute_commitment()); + } + } + + void finalise() + { + finalise_private_state_changes(); + private_circuit_public_inputs.set_commitments(new_commitments); + private_circuit_public_inputs.set_nullifiers(new_nullifiers); + private_circuit_public_inputs.set_public(composer); + }; +}; + +} // namespace aztec3::circuits::apps \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/l1_function_interface.hpp b/circuits/src/aztec3/circuits/apps/l1_function_interface.hpp index 6bbb8bb325e..1976f282650 100644 --- a/circuits/src/aztec3/circuits/apps/l1_function_interface.hpp +++ b/circuits/src/aztec3/circuits/apps/l1_function_interface.hpp @@ -13,7 +13,7 @@ using plonk::stdlib::witness_t; using plonk::stdlib::types::CircuitTypes; using plonk::stdlib::types::NativeTypes; -template class ContractFactory; +template class Contract; // We use the struct to retain designated initialisation, to make contract creation more readable. template struct L1FunctionInterfaceStruct { @@ -28,23 +28,22 @@ template class L1FunctionInterface { typedef typename CircuitTypes::fr fr; public: - ContractFactory* contract_factory; + Contract* contract; std::string function_name; fr function_selector; size_t num_params; L1FunctionInterface(){}; - L1FunctionInterface(ContractFactory* contract_factory, - L1FunctionInterfaceStruct const& l1_fn_struct) - : contract_factory(contract_factory) + L1FunctionInterface(Contract* contract, L1FunctionInterfaceStruct const& l1_fn_struct) + : contract(contract) , function_name(l1_fn_struct.function_name) , function_selector(l1_fn_struct.function_selector) , num_params(l1_fn_struct.num_params) {} // L1FunctionInterface(L1FunctionInterface const& l1_function) - // : contract_factory(l1_function.contract_factory) + // : contract(l1_function.contract) // , function_name(l1_function.function_name) // , function_selector(l1_function.function_selector) // , num_params(l1_function.num_params) diff --git a/circuits/src/aztec3/circuits/apps/l1_function_interface.tpp b/circuits/src/aztec3/circuits/apps/l1_function_interface.tpp index 80ed8631363..b101c9ca9d2 100644 --- a/circuits/src/aztec3/circuits/apps/l1_function_interface.tpp +++ b/circuits/src/aztec3/circuits/apps/l1_function_interface.tpp @@ -20,7 +20,7 @@ std::pair, L1Result> L1FunctionInterface::call(std throw_or_abort("Incorrect number of args"); } - auto promise = L1Promise(*contract_factory); + auto promise = L1Promise(*contract); L1Result result; return std::make_pair(promise, result); } diff --git a/circuits/src/aztec3/circuits/apps/l1_promise.hpp b/circuits/src/aztec3/circuits/apps/l1_promise.hpp index e89431c066a..9e029395006 100644 --- a/circuits/src/aztec3/circuits/apps/l1_promise.hpp +++ b/circuits/src/aztec3/circuits/apps/l1_promise.hpp @@ -17,7 +17,7 @@ using plonk::stdlib::witness_t; using plonk::stdlib::types::CircuitTypes; using plonk::stdlib::types::NativeTypes; -template class ContractFactory; +template class Contract; template class L1Promise { typedef CircuitTypes CT; @@ -26,11 +26,11 @@ template class L1Promise { typedef typename CT::boolean boolean; public: - ContractFactory& contract_factory; + Contract& contract; CallbackStackItem callback_stack_item; - L1Promise(ContractFactory& contract_factory) - : contract_factory(contract_factory) + L1Promise(Contract& contract) + : contract(contract) {} void on_success(std::string const& function_name, std::vector> const& args); diff --git a/circuits/src/aztec3/circuits/apps/l1_promise.tpp b/circuits/src/aztec3/circuits/apps/l1_promise.tpp index 6a62ab2fa4f..124f7b757ac 100644 --- a/circuits/src/aztec3/circuits/apps/l1_promise.tpp +++ b/circuits/src/aztec3/circuits/apps/l1_promise.tpp @@ -21,7 +21,6 @@ void L1Promise::on_success(std::string const& function_name, std::vector> const& args) { // construct success_callback_call_hash and success_result_arg_map_acc - // auto& oracle = contract_factory.oracle; std::vector> arg_input_pairs; @@ -41,7 +40,7 @@ void L1Promise::on_success(std::string const& function_name, // TODO: do this calc in the CallStackItem struct instead, once we know whether we can simply hash args instead of // the whole set of public inputs. - auto function_signature = contract_factory.get_function_signature_by_name(function_name); + auto function_signature = contract.get_function_signature_by_name(function_name); fr function_signature_hash = function_signature.hash(); fr arg_hash = CT::compress(arg_input_pairs); @@ -59,7 +58,6 @@ template void L1Promise::on_failure(std::string const& function_name, std::vector const& args) { // construct failure_callback_call_hash - // auto& oracle = contract_factory.oracle; std::vector> arg_input_pairs; @@ -69,7 +67,7 @@ void L1Promise::on_failure(std::string const& function_name, std::vect // TODO: do this calc in the CallStackItem struct instead, once we know whether we can simply hash args instead of // the whole set of public inputs. - auto function_signature = contract_factory.get_function_signature_by_name(function_name); + auto function_signature = contract.get_function_signature_by_name(function_name); fr function_signature_hash = function_signature.hash(); fr arg_hash = CT::compress(arg_input_pairs); diff --git a/circuits/src/aztec3/circuits/apps/private_state_factory.hpp b/circuits/src/aztec3/circuits/apps/private_state_factory.hpp index 5c2ee607bc9..fac2f8d561c 100644 --- a/circuits/src/aztec3/circuits/apps/private_state_factory.hpp +++ b/circuits/src/aztec3/circuits/apps/private_state_factory.hpp @@ -1,110 +1,33 @@ -#pragma once -#include -#include -#include "nullifier_preimage.hpp" -#include "private_state_note.hpp" -#include "private_state_var.hpp" -#include "oracle_wrapper.hpp" - -namespace aztec3::circuits::apps { - -// using plonk::stdlib::witness_t; -using plonk::stdlib::types::CircuitTypes; -using NT = plonk::stdlib::types::NativeTypes; - -template class PrivateStateFactory { - typedef CircuitTypes CT; - typedef typename CT::fr fr; - - public: - Composer& composer; // TODO: can we remove this? - OracleWrapperInterface& oracle; - const std::string contract_name; - fr private_state_counter = 0; - - std::map> private_state_vars; - std::vector> new_private_state_notes; - std::vector new_commitments; - std::vector> new_nullifier_preimages; - std::vector new_nullifiers; - - PrivateStateFactory(Composer& composer, - OracleWrapperInterface& oracle, - std::string contract_name) - : composer(composer) - , oracle(oracle) - , contract_name(contract_name){}; - - PrivateStateVar& new_private_state(std::string const& name, - PrivateStateType const& private_state_type = PARTITIONED) - { - if (private_state_vars.contains(name)) { - throw_or_abort("name already exists"); - } - PrivateStateVar private_state_var = - PrivateStateVar(this, private_state_type, name, private_state_counter++); - private_state_vars.insert(std::make_pair(name, private_state_var)); - return private_state_vars[name]; - }; - - // For initialising a private state which is a mapping. - PrivateStateVar& new_private_state(std::string const& name, - std::vector const& mapping_key_names, - PrivateStateType const& private_state_type = PARTITIONED) - { - if (private_state_vars.contains(name)) { - throw_or_abort("name already exists"); - } - PrivateStateVar private_state_var = - PrivateStateVar(this, private_state_type, name, private_state_counter++, mapping_key_names); - private_state_vars.insert(std::make_pair(name, private_state_var)); - return private_state_vars[name]; - }; - - void finalise() - { - - if (new_private_state_notes.size() > new_nullifiers.size()) { - // We've created more commitments than nullifiers so far. But we want to inject an input_nullifier into each - // new commitment. So, let's create more dummy nullifiers. - const auto& msg_sender_private_key = oracle.get_msg_sender_private_key(); - for (size_t i = new_nullifiers.size(); i < new_private_state_notes.size(); ++i) { - auto dummy_commitment = oracle.generate_random_element(); - new_nullifiers.push_back( - PrivateStateNote::compute_dummy_nullifier(dummy_commitment, msg_sender_private_key)); - new_nullifier_preimages.push_back(NullifierPreimage{ - dummy_commitment, - msg_sender_private_key, - false, - }); - } - } - for (size_t i = 0; i < new_private_state_notes.size(); ++i) { - new_private_state_notes[i].preimage.input_nullifier = new_nullifiers[i]; - new_commitments.push_back(new_private_state_notes[i].compute_commitment()); - } - } - - PrivateStateVar& get(std::string const& name) - { - if (!private_state_vars.contains(name)) { - throw_or_abort("name not found"); - } - return private_state_vars[name]; - }; - - void push_new_note(PrivateStateNote const private_state_note) - { - new_private_state_notes.push_back(private_state_note); - } - - void push_new_nullifier_data(fr nullifier, NullifierPreimage nullifier_preimage) - { - new_nullifiers.push_back(nullifier); - new_nullifier_preimages.push_back(nullifier_preimage); - } - - std::vector> get_notes() { return new_private_state_notes; } -}; - -} // namespace aztec3::circuits::apps \ No newline at end of file +// #pragma once +// #include +// #include +// #include "nullifier_preimage.hpp" +// #include "private_state_note.hpp" +// #include "private_state_var.hpp" +// #include "oracle_wrapper.hpp" + +// namespace aztec3::circuits::apps { + +// // using plonk::stdlib::witness_t; +// using plonk::stdlib::types::CircuitTypes; +// using NT = plonk::stdlib::types::NativeTypes; + +// template class PrivateStateFactory { +// typedef CircuitTypes CT; +// typedef typename CT::fr fr; + +// public: +// Composer& composer; // TODO: can we remove this? +// OracleWrapperInterface& oracle; +// const std::string contract_name; +// fr private_state_counter = 0; + +// std::map> private_state_vars; +// // std::vector> new_private_state_notes; +// // std::vector new_commitments; +// // std::vector> new_nullifier_preimages; +// // std::vector new_nullifiers; + +// }; + +// } // namespace aztec3::circuits::apps \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/private_state_var.hpp b/circuits/src/aztec3/circuits/apps/private_state_var.hpp index 25bfb025931..2dea09f4c09 100644 --- a/circuits/src/aztec3/circuits/apps/private_state_var.hpp +++ b/circuits/src/aztec3/circuits/apps/private_state_var.hpp @@ -1,6 +1,7 @@ #pragma once #include #include +// #include "function_executor.hpp" #include "private_state_note.hpp" #include "private_state_note_preimage.hpp" #include "private_state_operand.hpp" @@ -11,7 +12,8 @@ namespace aztec3::circuits::apps { using plonk::stdlib::types::CircuitTypes; using plonk::stdlib::types::NativeTypes; -template class PrivateStateFactory; +// template class PrivateStateFactory; +template class FunctionExecutionContext; template class PrivateStateVar { public: @@ -20,9 +22,10 @@ template class PrivateStateVar { typedef typename CT::address address; typedef typename CT::grumpkin_point grumpkin_point; - PrivateStateFactory* - state_factory; // Pointer, because PrivateStateVar can't hold a reference (because it gets initialised as a - // member of a map within PrivateStateFactory, so might not be passed data upon initialisation) + FunctionExecutionContext* + exec_ctx; // Pointer, because PrivateStateVar can't hold a reference (because it gets initialised as a member of + // a map within PrivateStateFactory, so might not be passed data upon initialisation) + PrivateStateType private_state_type; std::string name; fr start_slot; @@ -40,7 +43,7 @@ template class PrivateStateVar { PrivateStateVar(){}; PrivateStateVar(PrivateStateVar const& private_state_var) - : state_factory(private_state_var.state_factory) + : exec_ctx(private_state_var.exec_ctx) , private_state_type(private_state_var.private_state_type) , name(private_state_var.name) , start_slot(private_state_var.start_slot) @@ -50,11 +53,11 @@ template class PrivateStateVar { , is_partial_slot(private_state_var.is_partial_slot){}; // For initialising a basic fr state: - PrivateStateVar(PrivateStateFactory* state_factory, + PrivateStateVar(FunctionExecutionContext* exec_ctx, PrivateStateType const& private_state_type, std::string const& name, fr const& start_slot) - : state_factory(state_factory) + : exec_ctx(exec_ctx) , private_state_type(private_state_type) , name(name) , start_slot(start_slot) @@ -63,12 +66,12 @@ template class PrivateStateVar { }; // For initialising a mapping var: - PrivateStateVar(PrivateStateFactory* state_factory, + PrivateStateVar(FunctionExecutionContext* exec_ctx, PrivateStateType const& private_state_type, std::string const& name, fr const start_slot, std::vector const& mapping_key_names) - : state_factory(state_factory) + : exec_ctx(exec_ctx) , private_state_type(private_state_type) , name(name) , start_slot(start_slot) @@ -108,13 +111,13 @@ template class PrivateStateVar { grumpkin_point compute_start_slot_point(); // For initialising an fr state from within a mapping: - PrivateStateVar(PrivateStateFactory* state_factory, + PrivateStateVar(FunctionExecutionContext* exec_ctx, PrivateStateType const& private_state_type, std::string const& name, fr const& start_slot, grumpkin_point const& slot_point, bool const& is_partial_slot) - : state_factory(state_factory) + : exec_ctx(exec_ctx) , private_state_type(private_state_type) , name(name) , start_slot(start_slot) @@ -134,5 +137,5 @@ template class PrivateStateVar { // - We retain implicit instantiation of templates, meaning we can pick and choose (with static_assert) which class // methods support native, // circuit or both types. -// - We don't implement method definitions in this file, to avoid a circular dependency with state_factory.hpp. +// - We don't implement method definitions in this file, to avoid a circular dependency with function_executor.hpp. #include "private_state_var.tpp" diff --git a/circuits/src/aztec3/circuits/apps/private_state_var.tpp b/circuits/src/aztec3/circuits/apps/private_state_var.tpp index 917ca67cd69..aa482a943a5 100644 --- a/circuits/src/aztec3/circuits/apps/private_state_var.tpp +++ b/circuits/src/aztec3/circuits/apps/private_state_var.tpp @@ -7,8 +7,8 @@ #include #include #include +// #include "function_executor.hpp" #include "oracle_wrapper.hpp" -#include "private_state_factory.hpp" #include "private_state_note.hpp" #include "private_state_note_preimage.hpp" #include "private_state_operand.hpp" @@ -139,7 +139,7 @@ PrivateStateVar& PrivateStateVar::at(std::vector new_state = - PrivateStateVar(state_factory, private_state_type, name, start_slot, new_slot_point, is_partial_slot); + PrivateStateVar(exec_ctx, private_state_type, name, start_slot, new_slot_point, is_partial_slot); private_states[lookup] = new_state; @@ -191,7 +191,7 @@ template void PrivateStateVar::validate_operand(PrivateStateOperand const& operand) const { if (operand.creator_address) { - auto& oracle = state_factory->oracle; + auto& oracle = exec_ctx->oracle; const auto& msg_sender = oracle.get_msg_sender(); (*operand.creator_address).assert_is_in_set({ msg_sender, address(0) }); } @@ -203,7 +203,7 @@ void PrivateStateVar::add(PrivateStateOperand> arithmetic_checks(); validate_operand(operand); - auto& oracle = state_factory->oracle; + auto& oracle = exec_ctx->oracle; auto& composer = oracle.composer; PrivateStateNotePreimage new_note_preimage = PrivateStateNotePreimage{ @@ -213,14 +213,14 @@ void PrivateStateVar::add(PrivateStateOperand> .owner_address = operand.owner_address, .creator_address = operand.creator_address, .salt = oracle.generate_salt(), - // .input_nullifier = // this will be injected by the state_factory + // .input_nullifier = // this will be injected by the exec_ctx .memo = operand.memo, .is_real = plonk::stdlib::types::to_ct(composer, true), }; auto new_note = PrivateStateNote(*this, new_note_preimage); - state_factory->push_new_note(new_note); + exec_ctx->push_new_note(new_note); } template @@ -231,7 +231,7 @@ void PrivateStateVar::subtract(PrivateStateOperandoracle; + auto& oracle = exec_ctx->oracle; auto& composer = oracle.composer; const fr& subtrahend = operand.value; @@ -262,7 +262,7 @@ void PrivateStateVar::subtract(PrivateStateOperand::subtract(PrivateStateOperand(*this, difference_preimage); - state_factory->push_new_note(difference_note); - state_factory->push_new_nullifier_data(minuend_nullifier_1, minuend_nullifier_preimage_1); - state_factory->push_new_nullifier_data(minuend_nullifier_2, minuend_nullifier_preimage_2); + exec_ctx->push_new_note(difference_note); + exec_ctx->push_new_nullifier_data(minuend_nullifier_1, minuend_nullifier_preimage_1); + exec_ctx->push_new_nullifier_data(minuend_nullifier_2, minuend_nullifier_preimage_2); } // template class PrivateStateVar; diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/escrow.test.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp similarity index 88% rename from circuits/src/aztec3/circuits/apps/test_apps/escrow/escrow.test.cpp rename to circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp index 41b9107bc86..d11c1acd060 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/escrow.test.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp @@ -6,6 +6,8 @@ // #include // #include #include "index.hpp" +#include "contract.hpp" + // #include "deposit.hpp" // #include // #include @@ -22,18 +24,20 @@ TEST(escrow_tests, test_deposit) DB db; const NT::address contract_address = 12345; + const NT::fr msg_sender_private_key = 123456789; const NT::address msg_sender = NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); - const NT::fr msg_sender_private_key = 123456789; NativeOracle oracle = NativeOracle(db, contract_address, msg_sender, msg_sender_private_key); OracleWrapper oracle_wrapper = OracleWrapper(composer, oracle); + FunctionExecutionContext exec_ctx(composer, oracle_wrapper); + auto amount = NT::fr(5); auto asset_id = NT::fr(1); auto memo = NT::fr(999); - auto result = deposit(composer, oracle_wrapper, amount, asset_id, memo); + auto result = deposit(exec_ctx, amount, asset_id, memo); info("result: ", result); info("computed witness: ", composer.computed_witness); @@ -52,9 +56,9 @@ TEST(escrow_tests, test_transfer) DB db; const NT::address contract_address = 12345; + const NT::fr msg_sender_private_key = 123456789; const NT::address msg_sender = NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); - const NT::fr msg_sender_private_key = 123456789; CallContext call_context = { .msg_sender = msg_sender, @@ -65,6 +69,8 @@ TEST(escrow_tests, test_transfer) NativeOracle oracle = NativeOracle(db, call_context, msg_sender_private_key); OracleWrapper oracle_wrapper = OracleWrapper(composer, oracle); + FunctionExecutionContext exec_ctx(composer, oracle_wrapper); + auto amount = NT::fr(5); auto to = NT::address(657756); auto asset_id = NT::fr(1); @@ -72,7 +78,7 @@ TEST(escrow_tests, test_transfer) auto reveal_msg_sender_to_recipient = true; auto fee = NT::fr(2); - transfer(composer, oracle_wrapper, amount, to, asset_id, memo, reveal_msg_sender_to_recipient, fee); + transfer(exec_ctx, amount, to, asset_id, memo, reveal_msg_sender_to_recipient, fee); info("computed witness: ", composer.computed_witness); info("witness: ", composer.witness); @@ -90,9 +96,9 @@ TEST(escrow_tests, test_withdraw) DB db; const NT::address contract_address = 12345; + const NT::fr msg_sender_private_key = 123456789; const NT::address msg_sender = NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); - const NT::fr msg_sender_private_key = 123456789; CallContext call_context = { .msg_sender = msg_sender, @@ -103,13 +109,15 @@ TEST(escrow_tests, test_withdraw) NativeOracle oracle = NativeOracle(db, call_context, msg_sender_private_key); OracleWrapper oracle_wrapper = OracleWrapper(composer, oracle); + FunctionExecutionContext exec_ctx(composer, oracle_wrapper); + auto amount = NT::fr(5); auto asset_id = NT::fr(1); auto memo = NT::fr(999); auto l1_withdrawal_address = NT::fr(657756); auto fee = NT::fr(2); - withdraw(composer, oracle_wrapper, amount, asset_id, memo, l1_withdrawal_address, fee); + withdraw(exec_ctx, amount, asset_id, memo, l1_withdrawal_address, fee); info("computed witness: ", composer.computed_witness); info("witness: ", composer.witness); diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp index 7020a2e6d7b..08bc87a026b 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp @@ -1,13 +1,14 @@ #pragma once -#include "init.hpp" #include #include +#include +#include "init.hpp" namespace aztec3::circuits::apps::test_apps::escrow { -inline ContractFactory init(Composer& composer, OracleWrapper& oracle) +inline Contract init_contract(FunctionExecutionContext& exec_ctx) { - ContractFactory contract(composer, oracle, "Escrow"); + Contract contract(exec_ctx, "Escrow"); contract.new_private_state("balances", { "owner", "asset_id" }); @@ -27,6 +28,7 @@ inline ContractFactory init(Composer& composer, OracleWrapper& oracle) .num_params = 3, }); + // TODO: create a new FunctionExecutor(contract) and return it. return contract; } diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp index 6b6fb1d2c65..4a80a5516d3 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp @@ -1,26 +1,28 @@ +#include +#include #include "deposit.hpp" #include "contract.hpp" -#include -// #include -#include -// #include namespace aztec3::circuits::apps::test_apps::escrow { using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; -OptionalPrivateCircuitPublicInputs deposit( - Composer& composer, OracleWrapper& oracle, NT::fr const& _amount, NT::fr const& _asset_id, NT::fr const& _memo) +OptionalPrivateCircuitPublicInputs deposit(FunctionExecutionContext& exec_ctx, + NT::fr const& _amount, + NT::fr const& _asset_id, + NT::fr const& _memo) { + auto& composer = exec_ctx.composer; + auto& oracle = exec_ctx.oracle; + Contract contract = init_contract(exec_ctx); + CT::fr amount = to_ct(composer, _amount); CT::fr asset_id = to_ct(composer, _asset_id); CT::fr memo = to_ct(composer, _memo); CT::address msg_sender = oracle.get_msg_sender(); - auto env = init(composer, oracle); - - auto& balances = env.get_private_state("balances"); + auto& balances = contract.get_private_state("balances"); balances.at({ msg_sender.to_field(), asset_id }) .add({ @@ -30,13 +32,13 @@ OptionalPrivateCircuitPublicInputs deposit( .memo = memo, }); - auto& public_inputs = env.private_circuit_public_inputs; + auto& public_inputs = exec_ctx.private_circuit_public_inputs; - public_inputs.custom_public_inputs[0] = amount; - public_inputs.custom_public_inputs[1] = asset_id; - public_inputs.custom_public_inputs[2] = memo; + public_inputs.custom_inputs[0] = amount; + public_inputs.custom_inputs[1] = asset_id; + public_inputs.custom_inputs[2] = memo; - env.finalise(); + exec_ctx.finalise(); info("public inputs: ", public_inputs); diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.hpp index 5ed6ad05495..9a985231acd 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.hpp @@ -1,12 +1,15 @@ #pragma once -#include "init.hpp" #include +#include +#include "init.hpp" namespace aztec3::circuits::apps::test_apps::escrow { using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; -OptionalPrivateCircuitPublicInputs deposit( - Composer& composer, OracleWrapper& oracle, NT::fr const& _amount, NT::fr const& _asset_id, NT::fr const& _memo); +OptionalPrivateCircuitPublicInputs deposit(FunctionExecutionContext& exec_ctx, + NT::fr const& _amount, + NT::fr const& _asset_id, + NT::fr const& _memo); } // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/init.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/init.hpp index bf428bb52c2..b2df9356f30 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/init.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/init.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include namespace aztec3::circuits::apps::test_apps::escrow { diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp index 7ddf0383a25..1846f49509d 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp @@ -1,16 +1,15 @@ -#include "transfer.hpp" -#include "contract.hpp" #include -// #include +#include #include // #include +#include "transfer.hpp" +#include "contract.hpp" namespace aztec3::circuits::apps::test_apps::escrow { using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; -OptionalPrivateCircuitPublicInputs transfer(Composer& composer, - OracleWrapper& oracle, +OptionalPrivateCircuitPublicInputs transfer(FunctionExecutionContext& exec_ctx, NT::fr const& _amount, NT::address const& _to, NT::fr const& _asset_id, @@ -22,6 +21,10 @@ OptionalPrivateCircuitPublicInputs transfer(Composer& composer, // Initialisation *************************************************************** + auto& composer = exec_ctx.composer; + auto& oracle = exec_ctx.oracle; + Contract contract = init_contract(exec_ctx); + CT::fr amount = to_ct(composer, _amount); CT::address to = to_ct(composer, _to); CT::fr asset_id = to_ct(composer, _asset_id); @@ -33,9 +36,7 @@ OptionalPrivateCircuitPublicInputs transfer(Composer& composer, CT::address msg_sender = oracle.get_msg_sender(); - auto env = init(composer, oracle); - - auto& balances = env.get_private_state("balances"); + auto& balances = contract.get_private_state("balances"); // Circuit-specific logic ******************************************************* @@ -60,14 +61,14 @@ OptionalPrivateCircuitPublicInputs transfer(Composer& composer, // Assign circuit-specific public inputs **************************************** - auto& public_inputs = env.private_circuit_public_inputs; + auto& public_inputs = exec_ctx.private_circuit_public_inputs; - public_inputs.custom_public_inputs[0] = amount; - public_inputs.custom_public_inputs[1] = to.to_field(); - public_inputs.custom_public_inputs[2] = asset_id; - public_inputs.custom_public_inputs[3] = memo; - public_inputs.custom_public_inputs[4] = CT::fr(reveal_msg_sender_to_recipient); - public_inputs.custom_public_inputs[5] = fee; + public_inputs.custom_inputs[0] = amount; + public_inputs.custom_inputs[1] = to.to_field(); + public_inputs.custom_inputs[2] = asset_id; + public_inputs.custom_inputs[3] = memo; + public_inputs.custom_inputs[4] = CT::fr(reveal_msg_sender_to_recipient); + public_inputs.custom_inputs[5] = fee; public_inputs.emitted_public_inputs[0] = CT::fr::copy_as_new_witness(composer, fee); public_inputs.emitted_public_inputs[1] = CT::fr::copy_as_new_witness(composer, asset_id); @@ -77,7 +78,7 @@ OptionalPrivateCircuitPublicInputs transfer(Composer& composer, // Finalise ********************************************************************* - env.finalise(); + exec_ctx.finalise(); info("public inputs: ", public_inputs); diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.hpp index 5090ec044de..8a180d94ae4 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.hpp @@ -1,13 +1,13 @@ #pragma once -#include "init.hpp" #include +#include +#include "init.hpp" namespace aztec3::circuits::apps::test_apps::escrow { using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; -OptionalPrivateCircuitPublicInputs transfer(Composer& composer, - OracleWrapper& oracle, +OptionalPrivateCircuitPublicInputs transfer(FunctionExecutionContext& exec_ctx, NT::fr const& _amount, NT::address const& _to, NT::fr const& _asset_id, diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp index 29873279ffb..b4b7211b214 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp @@ -1,17 +1,16 @@ -#include "withdraw.hpp" -#include "contract.hpp" #include #include #include #include // #include +#include "withdraw.hpp" +#include "contract.hpp" namespace aztec3::circuits::apps::test_apps::escrow { using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; -OptionalPrivateCircuitPublicInputs withdraw(Composer& composer, - OracleWrapper& oracle, +OptionalPrivateCircuitPublicInputs withdraw(FunctionExecutionContext& exec_ctx, NT::fr const& _amount, NT::fr const& _asset_id, NT::fr const& _memo, @@ -22,6 +21,10 @@ OptionalPrivateCircuitPublicInputs withdraw(Composer& composer, // Initialisation *************************************************************** + auto& composer = exec_ctx.composer; + auto& oracle = exec_ctx.oracle; + Contract contract = init_contract(exec_ctx); + CT::fr amount = to_ct(composer, _amount); CT::fr asset_id = to_ct(composer, _asset_id); CT::fr memo = to_ct(composer, _memo); @@ -32,9 +35,7 @@ OptionalPrivateCircuitPublicInputs withdraw(Composer& composer, CT::address msg_sender = oracle.get_msg_sender(); - auto env = init(composer, oracle); - - auto& balances = env.get_private_state("balances"); + auto& balances = contract.get_private_state("balances"); // Circuit-specific logic ******************************************************* @@ -46,7 +47,7 @@ OptionalPrivateCircuitPublicInputs withdraw(Composer& composer, .memo = memo, }); - auto& l1_withdraw_function = env.get_l1_function("withdraw"); + auto& l1_withdraw_function = contract.get_l1_function("withdraw"); auto [l1_promise, l1_result] = l1_withdraw_function.call({ asset_id, amount, msg_sender.to_field() }); l1_promise.on_success("withdraw_success_callback", @@ -65,19 +66,19 @@ OptionalPrivateCircuitPublicInputs withdraw(Composer& composer, // Assign circuit-specific public inputs **************************************** - auto& public_inputs = env.private_circuit_public_inputs; + auto& public_inputs = exec_ctx.private_circuit_public_inputs; - public_inputs.custom_public_inputs[0] = amount; - public_inputs.custom_public_inputs[1] = asset_id; - public_inputs.custom_public_inputs[2] = memo; - public_inputs.custom_public_inputs[3] = l1_withdrawal_address; - public_inputs.custom_public_inputs[4] = fee; + public_inputs.custom_inputs[0] = amount; + public_inputs.custom_inputs[1] = asset_id; + public_inputs.custom_inputs[2] = memo; + public_inputs.custom_inputs[3] = l1_withdrawal_address; + public_inputs.custom_inputs[4] = fee; public_inputs.emitted_public_inputs[0] = CT::fr::copy_as_new_witness(composer, l1_withdrawal_address); public_inputs.emitted_public_inputs[1] = CT::fr::copy_as_new_witness(composer, asset_id); public_inputs.emitted_public_inputs[2] = CT::fr::copy_as_new_witness(composer, fee); - env.finalise(); + exec_ctx.finalise(); /// TODO: merkle membership check // public_inputs.old_private_data_tree_root diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.hpp index 0ddb1a0b58d..19127b313e4 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.hpp @@ -1,13 +1,13 @@ #pragma once -#include "init.hpp" #include +#include +#include "init.hpp" namespace aztec3::circuits::apps::test_apps::escrow { using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; -OptionalPrivateCircuitPublicInputs withdraw(Composer& composer, - OracleWrapper& oracle, +OptionalPrivateCircuitPublicInputs withdraw(FunctionExecutionContext& exec_ctx, NT::fr const& _amount, NT::fr const& _asset_id, NT::fr const& _memo, diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw_failure_callback.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw_failure_callback.cpp index cab8824b40f..8d60cbdf84a 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw_failure_callback.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw_failure_callback.cpp @@ -1,20 +1,22 @@ +#include +#include #include "deposit.hpp" #include "contract.hpp" -#include -#include -// #include namespace aztec3::circuits::apps::test_apps::escrow { using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; -void withdraw_failure_callback(Composer& composer, - OracleWrapper& oracle, +void withdraw_failure_callback(FunctionExecutionContext& exec_ctx, NT::fr const& _asset_id, NT::fr const& _amount, NT::address const& _owner_address, NT::fr const& _memo) { + auto& composer = exec_ctx.composer; + auto& oracle = exec_ctx.oracle; + Contract contract = init_contract(exec_ctx); + CT::fr asset_id = to_ct(composer, _asset_id); CT::fr amount = to_ct(composer, _amount); CT::address owner_address = to_ct(composer, _owner_address); @@ -22,9 +24,7 @@ void withdraw_failure_callback(Composer& composer, CT::address msg_sender = oracle.get_msg_sender(); - auto env = init(composer, oracle); - - auto& balances = env.get_private_state("balances"); + auto& balances = contract.get_private_state("balances"); balances.at({ owner_address.to_field(), asset_id }) .add({ @@ -34,14 +34,14 @@ void withdraw_failure_callback(Composer& composer, .memo = memo, }); - auto& public_inputs = env.private_circuit_public_inputs; + auto& public_inputs = exec_ctx.private_circuit_public_inputs; - public_inputs.custom_public_inputs[0] = asset_id; - public_inputs.custom_public_inputs[1] = amount; - public_inputs.custom_public_inputs[2] = owner_address.to_field(); - public_inputs.custom_public_inputs[3] = memo; + public_inputs.custom_inputs[0] = asset_id; + public_inputs.custom_inputs[1] = amount; + public_inputs.custom_inputs[2] = owner_address.to_field(); + public_inputs.custom_inputs[3] = memo; - env.finalise(); + exec_ctx.finalise(); info("public inputs: ", public_inputs); }; diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw_failure_callback.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw_failure_callback.hpp index bfdc6ab42f6..0b3f5513ee4 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw_failure_callback.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw_failure_callback.hpp @@ -1,10 +1,10 @@ #pragma once +#include #include "init.hpp" namespace aztec3::circuits::apps::test_apps::escrow { -void withdraw_failure_callback(Composer& composer, - OracleWrapper& oracle, +void withdraw_failure_callback(FunctionExecutionContext& exec_ctx, NT::fr const& _asset_id, NT::fr const& _amount, NT::address const& _owner_address, diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp new file mode 100644 index 00000000000..3e20e6ea1f0 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp @@ -0,0 +1,49 @@ +// #include +// #include +// // #include +// // #include +// // #include +// // #include +// // #include +// #include "index.hpp" +// // #include "deposit.hpp" +// // #include +// // #include +// // #include + +// namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { + +// class escrow_tests : public ::testing::Test {}; + +// TEST(escrow_tests, test_deposit) +// { + +// Composer composer; +// DB db; + +// const NT::address contract_address = 12345; +// const NT::address msg_sender = +// NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, +// 0x2ef9f7f09867fd6eULL)); +// const NT::fr msg_sender_private_key = 123456789; + +// NativeOracle oracle = NativeOracle(db, contract_address, msg_sender, msg_sender_private_key); +// OracleWrapper oracle_wrapper = OracleWrapper(composer, oracle); + +// auto a = NT::fr(111); +// auto b = NT::fr(222); +// auto c = NT::fr(333); + +// auto result = function1(composer, oracle_wrapper, a, b, c); +// info("result: ", result); + +// info("computed witness: ", composer.computed_witness); +// info("witness: ", composer.witness); +// // info("constant variables: ", composer.constant_variables); +// // info("variables: ", composer.variables); +// info("failed?: ", composer.failed); +// info("err: ", composer.err); +// info("n: ", composer.n); +// } + +// } // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/contract.hpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/contract.hpp new file mode 100644 index 00000000000..b8fe2667d3a --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/contract.hpp @@ -0,0 +1,24 @@ +// #pragma once +// #include "init.hpp" +// #include +// #include + +// namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { + +// inline ContractFactory init(Composer& composer, OracleWrapper& oracle) +// { +// ContractFactory contract(composer, oracle, "priv_to_priv_function_call"); + +// contract.new_private_state("x"); +// contract.new_private_state("y"); + +// // Solely used for assigning vk indices. +// contract.set_functions({ +// { .name = "function1", .is_private = true }, +// { .name = "function2", .is_private = true }, +// }); + +// return contract; +// } + +// } // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.cpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.cpp new file mode 100644 index 00000000000..13063517811 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.cpp @@ -0,0 +1,50 @@ +// #include "contract.hpp" +// #include "function1.hpp" +// #include +// #include + +// namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { + +// using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; + +// OptionalPrivateCircuitPublicInputs function1( +// Composer& composer, OracleWrapper& oracle, NT::fr const& _a, NT::fr const& _b, NT::fr const& _c) +// { +// CT::fr a = to_ct(composer, _a); +// CT::fr b = to_ct(composer, _b); +// CT::fr c = to_ct(composer, _c); + +// CT::address msg_sender = oracle.get_msg_sender(); + +// auto env = init(composer, oracle); + +// auto& x = env.get_private_state("x"); + +// x.add({ +// .value = a, +// .owner_address = msg_sender, +// .creator_address = msg_sender, +// .memo = 0, +// }); + +// auto function2 = env.get_function("function2"); + +// auto result = function2.call(a, b, c); + +// auto& public_inputs = env.private_circuit_public_inputs; + +// public_inputs.custom_inputs[0] = a; +// public_inputs.custom_inputs[1] = b; +// public_inputs.custom_inputs[2] = c; + +// public_inputs.private_call_stack[0] = ... + +// env.finalise(); + +// info("public inputs: ", public_inputs); + +// return public_inputs.to_native_type(); +// // TODO: also return note preimages and nullifier preimages. +// }; + +// } // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.hpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.hpp new file mode 100644 index 00000000000..99553ff5a5b --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.hpp @@ -0,0 +1,12 @@ +// #pragma once +// #include "init.hpp" +// #include + +// namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { + +// using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; + +// OptionalPrivateCircuitPublicInputs function1( +// Composer& composer, OracleWrapper& oracle, NT::fr const& _a, NT::fr const& _b, NT::fr const& _c); + +// } // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function2.cpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function2.cpp new file mode 100644 index 00000000000..d5185b594e1 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function2.cpp @@ -0,0 +1,48 @@ +// #include "contract.hpp" +// #include "function1.hpp" +// #include +// #include + +// namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { + +// using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; + +// OptionalPrivateCircuitPublicInputs function1( +// Composer& composer, OracleWrapper& oracle, NT::fr const& _d, NT::fr const& _e, NT::fr const& _f) +// { +// CT::fr d = to_ct(composer, _d); +// CT::fr e = to_ct(composer, _e); +// CT::fr f = to_ct(composer, _f); + +// CT::address msg_sender = oracle.get_msg_sender(); + +// auto env = init(composer, oracle); + +// auto& y = env.get_private_state("y"); + +// auto product = d * e * f; + +// y.add({ +// .value = product, +// .owner_address = msg_sender, +// .creator_address = msg_sender, +// .memo = 0, +// }); + +// auto& public_inputs = env.private_circuit_public_inputs; + +// public_inputs.custom_inputs[0] = d; +// public_inputs.custom_inputs[1] = e; +// public_inputs.custom_inputs[2] = f; + +// public_inputs.custom_outputs[0] = product; + +// env.finalise(); + +// info("public inputs: ", public_inputs); + +// return public_inputs.to_native_type(); +// // TODO: also return note preimages and nullifier preimages. +// }; + +// } // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function2.hpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function2.hpp new file mode 100644 index 00000000000..6c9c865c12c --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function2.hpp @@ -0,0 +1,12 @@ +// #pragma once +// #include "init.hpp" +// #include + +// namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { + +// using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; + +// OptionalPrivateCircuitPublicInputs function1( +// Composer& composer, OracleWrapper& oracle, NT::fr const& _d, NT::fr const& _e, NT::fr const& _f); + +// } // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/index.hpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/index.hpp new file mode 100644 index 00000000000..03f7484f7ee --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/index.hpp @@ -0,0 +1,4 @@ +// #include "init.hpp" +// #include "contract.hpp" +// #include "function1.hpp" +// // #include "function2.hpp" \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/init.hpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/init.hpp new file mode 100644 index 00000000000..fbc4276329e --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/init.hpp @@ -0,0 +1,21 @@ +// #pragma once +// #include +// #include +// #include +// #include +// #include +// #include + +// namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { + +// using Composer = plonk::stdlib::types::turbo::Composer; +// using CT = plonk::stdlib::types::CircuitTypes; +// using NT = plonk::stdlib::types::NativeTypes; + +// using DB = oracle::FakeDB; +// using oracle::NativeOracle; +// using OracleWrapper = OracleWrapperInterface; + +// using plonk::stdlib::types::to_ct; + +// } // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/kernel/private/private_kernel.test.cpp b/circuits/src/aztec3/circuits/kernel/private/.test.cpp similarity index 98% rename from circuits/src/aztec3/circuits/kernel/private/private_kernel.test.cpp rename to circuits/src/aztec3/circuits/kernel/private/.test.cpp index d24a6a0b66c..7a63cf5ffd6 100644 --- a/circuits/src/aztec3/circuits/kernel/private/private_kernel.test.cpp +++ b/circuits/src/aztec3/circuits/kernel/private/.test.cpp @@ -74,12 +74,13 @@ TEST(private_kernel_tests, test_deposit) NativeOracle deposit_oracle = NativeOracle(db, escrow_contract_address, msg_sender, msg_sender_private_key); OracleWrapper deposit_oracle_wrapper = OracleWrapper(deposit_composer, deposit_oracle); + FunctionExecutionContext deposit_ctx(deposit_composer, deposit_oracle_wrapper); + auto amount = NT::fr(5); auto asset_id = NT::fr(1); auto memo = NT::fr(999); - OptionalPrivateCircuitPublicInputs deposit_public_inputs = - deposit(deposit_composer, deposit_oracle_wrapper, amount, asset_id, memo); + OptionalPrivateCircuitPublicInputs deposit_public_inputs = deposit(deposit_ctx, amount, asset_id, memo); UnrolledProver deposit_prover = deposit_composer.create_unrolled_prover(); NT::Proof deposit_proof = deposit_prover.construct_proof(); @@ -132,7 +133,7 @@ TEST(private_kernel_tests, test_deposit) const CallStackItem deposit_call_stack_item{ .function_signature = FunctionSignature{ - .contract_address = escrow_contract_address, + // .contract_address = escrow_contract_address, .vk_index = 0, // TODO: deduce this from a NT state_factory. .is_private = true, // .is_constructor = false, diff --git a/circuits/src/aztec3/circuits/kernel/private/init.hpp b/circuits/src/aztec3/circuits/kernel/private/init.hpp index e6da88ac599..d6307327547 100644 --- a/circuits/src/aztec3/circuits/kernel/private/init.hpp +++ b/circuits/src/aztec3/circuits/kernel/private/init.hpp @@ -6,6 +6,7 @@ #include #include +#include #include @@ -28,4 +29,6 @@ using DB = oracle::FakeDB; using oracle::NativeOracle; using OracleWrapper = aztec3::circuits::apps::OracleWrapperInterface; +using FunctionExecutionContext = aztec3::circuits::apps::FunctionExecutionContext; + } // namespace aztec3::circuits::kernel::private_kernel \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp b/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp index 457a5734bb5..9b318228810 100644 --- a/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp +++ b/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp @@ -131,9 +131,9 @@ void validate_inputs(PrivateInputs const& private_inputs, PublicInputs& "A user cannot make a delegatecall or staticcall"); // The below also prevents delegatecall/staticcall - is_base_case.must_imply(private_inputs.private_call.call_stack_item.call_context.storage_contract_address == - private_inputs.private_call.call_stack_item.function_signature.contract_address, - "Storage contract address must be that of the called contract in the base case"); + // is_base_case.must_imply(private_inputs.private_call.call_stack_item.call_context.storage_contract_address == + // private_inputs.private_call.call_stack_item.function_signature.contract_address, + // "Storage contract address must be that of the called contract in the base case"); // TODO: privatelyExecutedCallback logic and checks } diff --git a/circuits/src/aztec3/constants.hpp b/circuits/src/aztec3/constants.hpp index 80df2420321..e8565cbec0f 100644 --- a/circuits/src/aztec3/constants.hpp +++ b/circuits/src/aztec3/constants.hpp @@ -3,7 +3,7 @@ namespace aztec3 { -constexpr size_t CUSTOM_PUBLIC_INPUTS_LENGTH = 8; +constexpr size_t CUSTOM_INPUTS_LENGTH = 8; constexpr size_t CUSTOM_OUTPUTS_LENGTH = 4; constexpr size_t EMITTED_PUBLIC_INPUTS_LENGTH = 4; constexpr size_t EMITTED_OUTPUTS_LENGTH = 4; diff --git a/circuits/src/aztec3/oracle/README.md b/circuits/src/aztec3/oracle/README.md index 3dbcc37e0fc..39fa4e6cbf6 100644 --- a/circuits/src/aztec3/oracle/README.md +++ b/circuits/src/aztec3/oracle/README.md @@ -1,6 +1,6 @@ # aztec3::circuits::oracle -When Aztec3 makes a call to a circuit executor (such as Noir or the test apps in aztec3/circuits/apps/test_apps), we don't pass _all_ public inputs when calling the circuit; only the `custom_public_inputs` inputs are sent initially. +When Aztec3 makes a call to a circuit executor (such as Noir or the test apps in aztec3/circuits/apps/test_apps), we don't pass _all_ public inputs when calling the circuit; only the `custom_inputs` inputs are sent initially. Why? From 5e2815f8f7a1f0837ea2ba1464efe374cdf787f7 Mon Sep 17 00:00:00 2001 From: iAmMichaelConnor Date: Mon, 18 Jul 2022 21:00:55 +0000 Subject: [PATCH 010/166] feat: tx_origin percolate through nested calls --- .../src/aztec3/circuits/abis/call_context.hpp | 39 ++++---- .../aztec3/circuits/apps/contract_factory.hpp | 5 +- .../aztec3/circuits/apps/contract_factory.tpp | 4 +- ...{function.hpp => function_declaration.hpp} | 2 +- .../circuits/apps/function_executor.hpp | 2 +- .../aztec3/circuits/apps/oracle_wrapper.hpp | 5 ++ .../circuits/apps/test_apps/escrow/.test.cpp | 7 -- .../apps/test_apps/escrow/contract.hpp | 2 +- .../apps/test_apps/escrow/deposit.cpp | 2 +- .../apps/test_apps/escrow/transfer.cpp | 2 +- .../apps/test_apps/escrow/withdraw.cpp | 3 +- .../.test.cpp | 90 +++++++++---------- .../contract.hpp | 37 ++++---- .../function1.cpp | 89 +++++++++++------- .../function1.hpp | 19 ++-- .../function2.cpp | 6 +- .../function2.hpp | 6 +- .../index.hpp | 8 +- .../private_to_private_function_call/init.hpp | 32 +++---- circuits/src/aztec3/oracle/oracle.hpp | 4 + 20 files changed, 198 insertions(+), 166 deletions(-) rename circuits/src/aztec3/circuits/apps/{function.hpp => function_declaration.hpp} (90%) diff --git a/circuits/src/aztec3/circuits/abis/call_context.hpp b/circuits/src/aztec3/circuits/abis/call_context.hpp index 0cb9d91a801..c7085ec12d5 100644 --- a/circuits/src/aztec3/circuits/abis/call_context.hpp +++ b/circuits/src/aztec3/circuits/abis/call_context.hpp @@ -20,6 +20,7 @@ template struct CallContext { address msg_sender; address storage_contract_address; + address tx_origin; boolean is_delegate_call; boolean is_static_call; @@ -34,10 +35,14 @@ template struct CallContext { boolean operator==(CallContext const& other) const { - return msg_sender == other.msg_sender && storage_contract_address == other.storage_contract_address; + return msg_sender == other.msg_sender && storage_contract_address == other.storage_contract_address && + tx_origin == other.tx_origin && is_delegate_call == other.is_delegate_call && + is_static_call == other.is_static_call && is_callback == other.is_callback && + is_fee_payment == other.is_fee_payment && pay_fee_from_l1 == other.pay_fee_from_l1 && + called_from_public_l2 == other.called_from_public_l2; }; - static CallContext empty() { return { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; }; + static CallContext empty() { return { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; }; template CallContext> to_circuit_type(Composer& composer) const { @@ -47,10 +52,9 @@ template struct CallContext { auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; CallContext> call_context = { - to_ct(msg_sender), to_ct(storage_contract_address), - to_ct(is_delegate_call), to_ct(is_static_call), - to_ct(is_callback), to_ct(is_fee_payment), - to_ct(pay_fee_from_l1), to_ct(pay_fee_from_public_l2), + to_ct(msg_sender), to_ct(storage_contract_address), to_ct(tx_origin), + to_ct(is_delegate_call), to_ct(is_static_call), to_ct(is_callback), + to_ct(is_fee_payment), to_ct(pay_fee_from_l1), to_ct(pay_fee_from_public_l2), to_ct(called_from_l1), to_ct(called_from_public_l2), }; @@ -64,10 +68,9 @@ template struct CallContext { auto to_nt = [&](auto& e) { return plonk::stdlib::types::to_nt(e); }; CallContext call_context = { - to_nt(msg_sender), to_nt(storage_contract_address), - to_nt(is_delegate_call), to_nt(is_static_call), - to_nt(is_callback), to_nt(is_fee_payment), - to_nt(pay_fee_from_l1), to_nt(pay_fee_from_public_l2), + to_nt(msg_sender), to_nt(storage_contract_address), to_nt(tx_origin), + to_nt(is_delegate_call), to_nt(is_static_call), to_nt(is_callback), + to_nt(is_fee_payment), to_nt(pay_fee_from_l1), to_nt(pay_fee_from_public_l2), to_nt(called_from_l1), to_nt(called_from_public_l2), }; @@ -77,11 +80,12 @@ template struct CallContext { fr hash() const { std::vector inputs = { - msg_sender.to_field(), storage_contract_address.to_field(), - fr(is_delegate_call), fr(is_static_call), - fr(is_callback), fr(is_fee_payment), - fr(pay_fee_from_l1), fr(pay_fee_from_public_l2), - fr(called_from_l1), fr(called_from_public_l2), + msg_sender.to_field(), storage_contract_address.to_field(), + tx_origin.to_field(), fr(is_delegate_call), + fr(is_static_call), fr(is_callback), + fr(is_fee_payment), fr(pay_fee_from_l1), + fr(pay_fee_from_public_l2), fr(called_from_l1), + fr(called_from_public_l2), }; return NCT::compress(inputs, GeneratorIndex::CALL_CONTEXT); @@ -93,6 +97,7 @@ template struct CallContext { msg_sender.to_field().assert_is_zero(); storage_contract_address.to_field().assert_is_zero(); + tx_origin.to_field().assert_is_zero(); fr(is_delegate_call).assert_is_zero(); fr(is_static_call).assert_is_zero(); fr(is_callback).assert_is_zero(); @@ -109,6 +114,7 @@ template struct CallContext { msg_sender.to_field().set_public(); storage_contract_address.to_field().set_public(); + tx_origin.to_field().set_public(); fr(is_delegate_call).set_public(); fr(is_static_call).set_public(); fr(is_callback).set_public(); @@ -126,6 +132,7 @@ template void read(uint8_t const*& it, CallContext& call_con read(it, call_context.msg_sender); read(it, call_context.storage_contract_address); + read(it, call_context.tx_origin); read(it, call_context.is_delegate_call); read(it, call_context.is_static_call); read(it, call_context.is_callback); @@ -142,6 +149,7 @@ template void write(std::vector& buf, CallContext c write(buf, call_context.msg_sender); write(buf, call_context.storage_contract_address); + write(buf, call_context.tx_origin); write(buf, call_context.is_delegate_call); write(buf, call_context.is_static_call); write(buf, call_context.is_callback); @@ -156,6 +164,7 @@ template std::ostream& operator<<(std::ostream& os, CallContext // #include "function_executor.hpp" // #include "private_state_note.hpp" +#include "function_declaration.hpp" #include "private_state_var.hpp" -#include "function.hpp" #include "l1_function_interface.hpp" + // #include "oracle_wrapper.hpp" namespace aztec3::circuits::apps { @@ -45,7 +46,7 @@ template class Contract { exec_ctx.register_contract(this); } - void set_functions(std::vector> const& functions); + void set_functions(std::vector> const& functions); // TODO: return some Function class which has a `call` method... // FunctionSignature get_function(std::string name) { return function_signature[name]; } diff --git a/circuits/src/aztec3/circuits/apps/contract_factory.tpp b/circuits/src/aztec3/circuits/apps/contract_factory.tpp index a2992bdc01c..5f28df45c7d 100644 --- a/circuits/src/aztec3/circuits/apps/contract_factory.tpp +++ b/circuits/src/aztec3/circuits/apps/contract_factory.tpp @@ -7,7 +7,7 @@ #include "function_executor.hpp" // #include "private_state_note.hpp" #include "private_state_var.hpp" -#include "function.hpp" +#include "function_declaration.hpp" #include "l1_function_interface.hpp" // #include "oracle_wrapper.hpp" @@ -20,7 +20,7 @@ using aztec3::circuits::abis::FunctionSignature; // using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; template -void Contract::set_functions(std::vector>> const& functions) +void Contract::set_functions(std::vector>> const& functions) { for (uint32_t i = 0; i < functions.size(); ++i) { const auto& function = functions[i]; diff --git a/circuits/src/aztec3/circuits/apps/function.hpp b/circuits/src/aztec3/circuits/apps/function_declaration.hpp similarity index 90% rename from circuits/src/aztec3/circuits/apps/function.hpp rename to circuits/src/aztec3/circuits/apps/function_declaration.hpp index 5127a88f40e..7c70d11e148 100644 --- a/circuits/src/aztec3/circuits/apps/function.hpp +++ b/circuits/src/aztec3/circuits/apps/function_declaration.hpp @@ -10,7 +10,7 @@ using plonk::stdlib::witness_t; using plonk::stdlib::types::CircuitTypes; using plonk::stdlib::types::NativeTypes; -template struct Function { +template struct FunctionDeclaration { typedef typename NCT::boolean boolean; std::string name; diff --git a/circuits/src/aztec3/circuits/apps/function_executor.hpp b/circuits/src/aztec3/circuits/apps/function_executor.hpp index b952c15f219..4fa96d459f5 100644 --- a/circuits/src/aztec3/circuits/apps/function_executor.hpp +++ b/circuits/src/aztec3/circuits/apps/function_executor.hpp @@ -9,7 +9,7 @@ #include "oracle_wrapper.hpp" #include "private_state_note.hpp" // #include "private_state_var.hpp" -// #include "function.hpp" +// #include "function_declaration.hpp" // #include "l1_function_interface.hpp" namespace aztec3::circuits::apps { diff --git a/circuits/src/aztec3/circuits/apps/oracle_wrapper.hpp b/circuits/src/aztec3/circuits/apps/oracle_wrapper.hpp index 3aa1055512d..cae7458892d 100644 --- a/circuits/src/aztec3/circuits/apps/oracle_wrapper.hpp +++ b/circuits/src/aztec3/circuits/apps/oracle_wrapper.hpp @@ -26,6 +26,9 @@ template class OracleWrapperInterface { public: Composer& composer; NativeOracle& oracle; + + // Initialise from Native. + // Used when initialising for a user's first call. OracleWrapperInterface(Composer& composer, NativeOracle& oracle) : composer(composer) , oracle(oracle){}; @@ -53,6 +56,8 @@ template class OracleWrapperInterface { address& get_this_contract_address() { return get_call_context().storage_contract_address; }; + address& get_tx_origin() { return get_call_context().tx_origin; }; + fr generate_salt() const { return plonk::stdlib::types::to_ct(composer, oracle.generate_salt()); } fr generate_random_element() const diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp index d11c1acd060..795d07a5a6f 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp @@ -2,17 +2,10 @@ #include // #include // #include -// #include -// #include // #include #include "index.hpp" #include "contract.hpp" -// #include "deposit.hpp" -// #include -// #include -// #include - namespace aztec3::circuits::apps::test_apps::escrow { class escrow_tests : public ::testing::Test {}; diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp index 08bc87a026b..56e356825ee 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp @@ -1,6 +1,6 @@ #pragma once #include -#include +#include #include #include "init.hpp" diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp index 4a80a5516d3..5c4a6d26846 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp @@ -1,6 +1,6 @@ +#include "deposit.hpp" #include #include -#include "deposit.hpp" #include "contract.hpp" namespace aztec3::circuits::apps::test_apps::escrow { diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp index 1846f49509d..0efb2cf9673 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp @@ -1,8 +1,8 @@ +#include "transfer.hpp" #include #include #include // #include -#include "transfer.hpp" #include "contract.hpp" namespace aztec3::circuits::apps::test_apps::escrow { diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp index b4b7211b214..30245ff901a 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp @@ -1,9 +1,8 @@ +#include "withdraw.hpp" #include #include #include #include -// #include -#include "withdraw.hpp" #include "contract.hpp" namespace aztec3::circuits::apps::test_apps::escrow { diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp index 3e20e6ea1f0..14577149b5f 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp @@ -1,49 +1,41 @@ -// #include -// #include -// // #include -// // #include -// // #include -// // #include -// // #include -// #include "index.hpp" -// // #include "deposit.hpp" -// // #include -// // #include -// // #include - -// namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { - -// class escrow_tests : public ::testing::Test {}; - -// TEST(escrow_tests, test_deposit) -// { - -// Composer composer; -// DB db; - -// const NT::address contract_address = 12345; -// const NT::address msg_sender = -// NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, -// 0x2ef9f7f09867fd6eULL)); -// const NT::fr msg_sender_private_key = 123456789; - -// NativeOracle oracle = NativeOracle(db, contract_address, msg_sender, msg_sender_private_key); -// OracleWrapper oracle_wrapper = OracleWrapper(composer, oracle); - -// auto a = NT::fr(111); -// auto b = NT::fr(222); -// auto c = NT::fr(333); - -// auto result = function1(composer, oracle_wrapper, a, b, c); -// info("result: ", result); - -// info("computed witness: ", composer.computed_witness); -// info("witness: ", composer.witness); -// // info("constant variables: ", composer.constant_variables); -// // info("variables: ", composer.variables); -// info("failed?: ", composer.failed); -// info("err: ", composer.err); -// info("n: ", composer.n); -// } - -// } // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file +#include +#include +#include "index.hpp" + +namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { + +class escrow_tests : public ::testing::Test {}; + +TEST(escrow_tests, test_deposit) +{ + + Composer fn1_composer; + DB db; + + const NT::address contract_address = 12345; + const NT::fr msg_sender_private_key = 123456789; + const NT::address msg_sender = + NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); + + NativeOracle fn1_oracle = NativeOracle(db, contract_address, msg_sender, msg_sender_private_key); + OracleWrapper fn1_oracle_wrapper = OracleWrapper(fn1_composer, fn1_oracle); + + FunctionExecutionContext fn1_exec_ctx(fn1_composer, fn1_oracle_wrapper); + + auto a = NT::fr(111); + auto b = NT::fr(222); + auto c = NT::fr(333); + + auto result = function1(fn1_exec_ctx, a, b, c); + info("result: ", result); + + info("computed witness: ", fn1_composer.computed_witness); + info("witness: ", fn1_composer.witness); + // info("constant variables: ", fn1_composer.constant_variables); + // info("variables: ", fn1_composer.variables); + info("failed?: ", fn1_composer.failed); + info("err: ", fn1_composer.err); + info("n: ", fn1_composer.n); +} + +} // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/contract.hpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/contract.hpp index b8fe2667d3a..bc73b283dff 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/contract.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/contract.hpp @@ -1,24 +1,25 @@ -// #pragma once -// #include "init.hpp" -// #include -// #include +#pragma once +#include +#include +#include +#include "init.hpp" -// namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { +namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { -// inline ContractFactory init(Composer& composer, OracleWrapper& oracle) -// { -// ContractFactory contract(composer, oracle, "priv_to_priv_function_call"); +inline Contract init_contract(FunctionExecutionContext& exec_ctx) +{ + Contract contract(exec_ctx, "priv_to_priv_function_call"); -// contract.new_private_state("x"); -// contract.new_private_state("y"); + contract.new_private_state("x"); + contract.new_private_state("y"); -// // Solely used for assigning vk indices. -// contract.set_functions({ -// { .name = "function1", .is_private = true }, -// { .name = "function2", .is_private = true }, -// }); + // Solely used for assigning vk indices. + contract.set_functions({ + { .name = "function1", .is_private = true }, + { .name = "function2", .is_private = true }, + }); -// return contract; -// } + return contract; +} -// } // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file +} // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.cpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.cpp index 13063517811..de53e3e2027 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.cpp @@ -1,50 +1,71 @@ -// #include "contract.hpp" -// #include "function1.hpp" -// #include -// #include +#include "function1.hpp" +#include +#include +#include "contract.hpp" -// namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { +namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { -// using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; +using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; -// OptionalPrivateCircuitPublicInputs function1( -// Composer& composer, OracleWrapper& oracle, NT::fr const& _a, NT::fr const& _b, NT::fr const& _c) -// { -// CT::fr a = to_ct(composer, _a); -// CT::fr b = to_ct(composer, _b); -// CT::fr c = to_ct(composer, _c); +OptionalPrivateCircuitPublicInputs function1(FunctionExecutionContext& exec_ctx, + NT::fr const& _a, + NT::fr const& _b, + NT::fr const& _c) +{ + auto& composer = exec_ctx.composer; + auto& oracle = exec_ctx.oracle; + Contract contract = init_contract(exec_ctx); -// CT::address msg_sender = oracle.get_msg_sender(); + CT::fr a = to_ct(composer, _a); + CT::fr b = to_ct(composer, _b); + CT::fr c = to_ct(composer, _c); -// auto env = init(composer, oracle); + CT::address msg_sender = oracle.get_msg_sender(); -// auto& x = env.get_private_state("x"); + auto& x = contract.get_private_state("x"); -// x.add({ -// .value = a, -// .owner_address = msg_sender, -// .creator_address = msg_sender, -// .memo = 0, -// }); + x.add({ + .value = a, + .owner_address = msg_sender, + .creator_address = msg_sender, + .memo = 0, + }); -// auto function2 = env.get_function("function2"); + // auto function2 = contract.get_function("function2"); + const NT::address fn2_contract_address = 23456; -// auto result = function2.call(a, b, c); + Composer fn2_composer; -// auto& public_inputs = env.private_circuit_public_inputs; + // Note: it's ok that we swap back into Native Types here - we don't need constraints. Creation of fn2_oracle is + // necessary for circuit construction only; it's not part of the circuit itself. We check that the call_contexts + // (msg_sender, contract_address, tx_origin) of functions 1 & 2 relate to one-another in the private kernel circuit, + // by comparing the functions' public inputs. + NativeOracle fn2_oracle = NativeOracle(oracle.oracle.db, + fn2_contract_address, + oracle.get_this_contract_address() + .to_field() + .get_value(), // TODO: add get_value() method to address type directly. + oracle.get_tx_origin().to_field().get_value()); + OracleWrapper fn2_oracle_wrapper = OracleWrapper(fn2_composer, fn2_oracle); -// public_inputs.custom_inputs[0] = a; -// public_inputs.custom_inputs[1] = b; -// public_inputs.custom_inputs[2] = c; + FunctionExecutionContext fn1_exec_ctx(fn2_composer, fn2_oracle_wrapper); -// public_inputs.private_call_stack[0] = ... + // auto result = function2.call(a, b, c); -// env.finalise(); + auto& public_inputs = exec_ctx.private_circuit_public_inputs; -// info("public inputs: ", public_inputs); + public_inputs.custom_inputs[0] = a; + public_inputs.custom_inputs[1] = b; + public_inputs.custom_inputs[2] = c; -// return public_inputs.to_native_type(); -// // TODO: also return note preimages and nullifier preimages. -// }; + // public_inputs.private_call_stack[0] = ... -// } // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file + exec_ctx.finalise(); + + info("public inputs: ", public_inputs); + + return public_inputs.to_native_type(); + // TODO: also return note preimages and nullifier preimages. +}; + +} // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.hpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.hpp index 99553ff5a5b..a8cf2288947 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.hpp @@ -1,12 +1,15 @@ -// #pragma once -// #include "init.hpp" -// #include +#pragma once +#include "init.hpp" +#include +#include -// namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { +namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { -// using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; +using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; -// OptionalPrivateCircuitPublicInputs function1( -// Composer& composer, OracleWrapper& oracle, NT::fr const& _a, NT::fr const& _b, NT::fr const& _c); +OptionalPrivateCircuitPublicInputs function1(FunctionExecutionContext& exec_ctx, + NT::fr const& _a, + NT::fr const& _b, + NT::fr const& _c); -// } // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file +} // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function2.cpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function2.cpp index d5185b594e1..3e6e8533b25 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function2.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function2.cpp @@ -7,8 +7,10 @@ // using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; -// OptionalPrivateCircuitPublicInputs function1( -// Composer& composer, OracleWrapper& oracle, NT::fr const& _d, NT::fr const& _e, NT::fr const& _f) +// OptionalPrivateCircuitPublicInputs function1(FunctionExecutionContext& exec_ctx, +// NT::fr const& _d, +// NT::fr const& _e, +// NT::fr const& _f) // { // CT::fr d = to_ct(composer, _d); // CT::fr e = to_ct(composer, _e); diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function2.hpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function2.hpp index 6c9c865c12c..c624c30c9e4 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function2.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function2.hpp @@ -6,7 +6,9 @@ // using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; -// OptionalPrivateCircuitPublicInputs function1( -// Composer& composer, OracleWrapper& oracle, NT::fr const& _d, NT::fr const& _e, NT::fr const& _f); +// OptionalPrivateCircuitPublicInputs function2(FunctionExecutionContext& exec_ctx, +// NT::fr const& _d, +// NT::fr const& _e, +// NT::fr const& _f); // } // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/index.hpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/index.hpp index 03f7484f7ee..0e6564100ea 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/index.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/index.hpp @@ -1,4 +1,4 @@ -// #include "init.hpp" -// #include "contract.hpp" -// #include "function1.hpp" -// // #include "function2.hpp" \ No newline at end of file +#include "init.hpp" +#include "contract.hpp" +#include "function1.hpp" +// #include "function2.hpp" \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/init.hpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/init.hpp index fbc4276329e..15404f916c2 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/init.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/init.hpp @@ -1,21 +1,21 @@ -// #pragma once -// #include -// #include -// #include -// #include -// #include -// #include +#pragma once +#include +#include +#include +#include +#include +#include -// namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { +namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { -// using Composer = plonk::stdlib::types::turbo::Composer; -// using CT = plonk::stdlib::types::CircuitTypes; -// using NT = plonk::stdlib::types::NativeTypes; +using Composer = plonk::stdlib::types::turbo::Composer; +using CT = plonk::stdlib::types::CircuitTypes; +using NT = plonk::stdlib::types::NativeTypes; -// using DB = oracle::FakeDB; -// using oracle::NativeOracle; -// using OracleWrapper = OracleWrapperInterface; +using DB = oracle::FakeDB; +using oracle::NativeOracle; +using OracleWrapper = OracleWrapperInterface; -// using plonk::stdlib::types::to_ct; +using plonk::stdlib::types::to_ct; -// } // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file +} // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file diff --git a/circuits/src/aztec3/oracle/oracle.hpp b/circuits/src/aztec3/oracle/oracle.hpp index 807fb48d9ce..e9be5db6b21 100644 --- a/circuits/src/aztec3/oracle/oracle.hpp +++ b/circuits/src/aztec3/oracle/oracle.hpp @@ -20,6 +20,7 @@ template class NativeOracleInterface { NT::fr const& contract_address, // NT::fr const& portal_contract_address, NT::address const& msg_sender, + NT::address const& tx_origin, NT::boolean const& is_delegate_call = false, NT::boolean const& is_static_call = false, NT::boolean const& is_fee_payment = false, @@ -31,6 +32,7 @@ template class NativeOracleInterface { , call_context({ .msg_sender = msg_sender, .storage_contract_address = contract_address, + .tx_origin = tx_origin, .is_delegate_call = is_delegate_call, .is_static_call = is_static_call, .is_fee_payment = is_fee_payment, @@ -47,6 +49,7 @@ template class NativeOracleInterface { NT::fr const& contract_address, // NT::fr const& portal_contract_address, NT::address const& msg_sender, + NT::address const& tx_origin, std::optional msg_sender_private_key, NT::boolean const& is_delegate_call = false, NT::boolean const& is_static_call = false, @@ -59,6 +62,7 @@ template class NativeOracleInterface { , call_context({ .msg_sender = msg_sender, .storage_contract_address = contract_address, + .tx_origin = tx_origin, .is_delegate_call = is_delegate_call, .is_static_call = is_static_call, .is_fee_payment = is_fee_payment, From d3493bd6cfe19d14cbd6b31e5fecc2c95c204dbe Mon Sep 17 00:00:00 2001 From: iAmMichaelConnor Date: Mon, 18 Jul 2022 21:11:35 +0000 Subject: [PATCH 011/166] chore: renaming --- .../circuits/apps/{contract_factory.hpp => contract.hpp} | 6 +----- .../circuits/apps/{contract_factory.tpp => contract.tpp} | 5 +---- ...function_executor.hpp => function_execution_context.hpp} | 2 +- circuits/src/aztec3/circuits/apps/l1_function_interface.hpp | 1 - circuits/src/aztec3/circuits/apps/l1_function_interface.tpp | 3 +-- circuits/src/aztec3/circuits/apps/l1_promise.hpp | 1 - circuits/src/aztec3/circuits/apps/l1_promise.tpp | 2 +- circuits/src/aztec3/circuits/apps/private_state_var.hpp | 4 ++-- circuits/src/aztec3/circuits/apps/private_state_var.tpp | 3 +-- .../src/aztec3/circuits/apps/test_apps/escrow/contract.hpp | 4 ++-- .../src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp | 2 +- .../src/aztec3/circuits/apps/test_apps/escrow/deposit.hpp | 2 +- circuits/src/aztec3/circuits/apps/test_apps/escrow/init.hpp | 2 +- .../src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp | 2 +- .../src/aztec3/circuits/apps/test_apps/escrow/transfer.hpp | 2 +- .../src/aztec3/circuits/apps/test_apps/escrow/withdraw.hpp | 2 +- .../apps/test_apps/escrow/withdraw_failure_callback.cpp | 2 +- .../apps/test_apps/escrow/withdraw_failure_callback.hpp | 2 +- .../test_apps/private_to_private_function_call/contract.hpp | 4 ++-- .../private_to_private_function_call/function1.cpp | 2 +- .../private_to_private_function_call/function1.hpp | 2 +- circuits/src/aztec3/circuits/kernel/private/init.hpp | 2 +- 22 files changed, 23 insertions(+), 34 deletions(-) rename circuits/src/aztec3/circuits/apps/{contract_factory.hpp => contract.hpp} (93%) rename circuits/src/aztec3/circuits/apps/{contract_factory.tpp => contract.tpp} (95%) rename circuits/src/aztec3/circuits/apps/{function_executor.hpp => function_execution_context.hpp} (99%) diff --git a/circuits/src/aztec3/circuits/apps/contract_factory.hpp b/circuits/src/aztec3/circuits/apps/contract.hpp similarity index 93% rename from circuits/src/aztec3/circuits/apps/contract_factory.hpp rename to circuits/src/aztec3/circuits/apps/contract.hpp index 13016d7dae9..09fcfd42a94 100644 --- a/circuits/src/aztec3/circuits/apps/contract_factory.hpp +++ b/circuits/src/aztec3/circuits/apps/contract.hpp @@ -1,11 +1,7 @@ #pragma once // #include // #include -// #include #include -// #include -// #include "function_executor.hpp" -// #include "private_state_note.hpp" #include "function_declaration.hpp" #include "private_state_var.hpp" #include "l1_function_interface.hpp" @@ -78,4 +74,4 @@ template class Contract { // methods support native, // circuit or both types. // - We don't implement method definitions in this file, to avoid a circular dependency with exec_ctx.hpp. -#include "contract_factory.tpp" \ No newline at end of file +#include "contract.tpp" \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/contract_factory.tpp b/circuits/src/aztec3/circuits/apps/contract.tpp similarity index 95% rename from circuits/src/aztec3/circuits/apps/contract_factory.tpp rename to circuits/src/aztec3/circuits/apps/contract.tpp index 5f28df45c7d..fb7a1ab743e 100644 --- a/circuits/src/aztec3/circuits/apps/contract_factory.tpp +++ b/circuits/src/aztec3/circuits/apps/contract.tpp @@ -3,13 +3,10 @@ #include #include #include -// #include -#include "function_executor.hpp" -// #include "private_state_note.hpp" +#include "function_execution_context.hpp" #include "private_state_var.hpp" #include "function_declaration.hpp" #include "l1_function_interface.hpp" -// #include "oracle_wrapper.hpp" namespace aztec3::circuits::apps { diff --git a/circuits/src/aztec3/circuits/apps/function_executor.hpp b/circuits/src/aztec3/circuits/apps/function_execution_context.hpp similarity index 99% rename from circuits/src/aztec3/circuits/apps/function_executor.hpp rename to circuits/src/aztec3/circuits/apps/function_execution_context.hpp index 4fa96d459f5..1b70b15649d 100644 --- a/circuits/src/aztec3/circuits/apps/function_executor.hpp +++ b/circuits/src/aztec3/circuits/apps/function_execution_context.hpp @@ -4,7 +4,7 @@ #include #include #include -#include "contract_factory.hpp" +#include "contract.hpp" #include "nullifier_preimage.hpp" #include "oracle_wrapper.hpp" #include "private_state_note.hpp" diff --git a/circuits/src/aztec3/circuits/apps/l1_function_interface.hpp b/circuits/src/aztec3/circuits/apps/l1_function_interface.hpp index 1976f282650..27bbd36d562 100644 --- a/circuits/src/aztec3/circuits/apps/l1_function_interface.hpp +++ b/circuits/src/aztec3/circuits/apps/l1_function_interface.hpp @@ -3,7 +3,6 @@ #include #include #include -// #include "contract_factory.hpp" // TODO: circular dependency #include "l1_promise.hpp" #include "l1_result.hpp" diff --git a/circuits/src/aztec3/circuits/apps/l1_function_interface.tpp b/circuits/src/aztec3/circuits/apps/l1_function_interface.tpp index b101c9ca9d2..28cc9ec5453 100644 --- a/circuits/src/aztec3/circuits/apps/l1_function_interface.tpp +++ b/circuits/src/aztec3/circuits/apps/l1_function_interface.tpp @@ -1,9 +1,8 @@ -// #pragma once #include #include #include #include -#include "contract_factory.hpp" // TODO: circular dependency? +#include "contract.hpp" #include "l1_promise.hpp" #include "l1_result.hpp" diff --git a/circuits/src/aztec3/circuits/apps/l1_promise.hpp b/circuits/src/aztec3/circuits/apps/l1_promise.hpp index 9e029395006..4f2e2d44ff2 100644 --- a/circuits/src/aztec3/circuits/apps/l1_promise.hpp +++ b/circuits/src/aztec3/circuits/apps/l1_promise.hpp @@ -7,7 +7,6 @@ #include #include #include -// #include "contract_factory.hpp" // TODO: circular dependency? #include "l1_result.hpp" namespace aztec3::circuits::apps { diff --git a/circuits/src/aztec3/circuits/apps/l1_promise.tpp b/circuits/src/aztec3/circuits/apps/l1_promise.tpp index 124f7b757ac..11bce93fcbc 100644 --- a/circuits/src/aztec3/circuits/apps/l1_promise.tpp +++ b/circuits/src/aztec3/circuits/apps/l1_promise.tpp @@ -6,7 +6,7 @@ #include #include #include -#include "contract_factory.hpp" +#include "contract.hpp" #include "l1_result.hpp" namespace aztec3::circuits::apps { diff --git a/circuits/src/aztec3/circuits/apps/private_state_var.hpp b/circuits/src/aztec3/circuits/apps/private_state_var.hpp index 2dea09f4c09..71b4cddd2de 100644 --- a/circuits/src/aztec3/circuits/apps/private_state_var.hpp +++ b/circuits/src/aztec3/circuits/apps/private_state_var.hpp @@ -1,7 +1,6 @@ #pragma once #include #include -// #include "function_executor.hpp" #include "private_state_note.hpp" #include "private_state_note_preimage.hpp" #include "private_state_operand.hpp" @@ -137,5 +136,6 @@ template class PrivateStateVar { // - We retain implicit instantiation of templates, meaning we can pick and choose (with static_assert) which class // methods support native, // circuit or both types. -// - We don't implement method definitions in this file, to avoid a circular dependency with function_executor.hpp. +// - We don't implement method definitions in this file, to avoid a circular dependency with +// function_execution_context.hpp. #include "private_state_var.tpp" diff --git a/circuits/src/aztec3/circuits/apps/private_state_var.tpp b/circuits/src/aztec3/circuits/apps/private_state_var.tpp index aa482a943a5..c63ac36772c 100644 --- a/circuits/src/aztec3/circuits/apps/private_state_var.tpp +++ b/circuits/src/aztec3/circuits/apps/private_state_var.tpp @@ -1,4 +1,4 @@ -// #include "private_state_var.hpp" +#pragma once // #include #include #include @@ -7,7 +7,6 @@ #include #include #include -// #include "function_executor.hpp" #include "oracle_wrapper.hpp" #include "private_state_note.hpp" #include "private_state_note_preimage.hpp" diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp index 56e356825ee..1b8d7dc4ff0 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp @@ -1,7 +1,7 @@ #pragma once -#include +#include #include -#include +#include #include "init.hpp" namespace aztec3::circuits::apps::test_apps::escrow { diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp index 5c4a6d26846..44deb65417a 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp @@ -1,6 +1,6 @@ #include "deposit.hpp" #include -#include +#include #include "contract.hpp" namespace aztec3::circuits::apps::test_apps::escrow { diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.hpp index 9a985231acd..ca23a1115c7 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.hpp @@ -1,6 +1,6 @@ #pragma once #include -#include +#include #include "init.hpp" namespace aztec3::circuits::apps::test_apps::escrow { diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/init.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/init.hpp index b2df9356f30..b10e631df8d 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/init.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/init.hpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include namespace aztec3::circuits::apps::test_apps::escrow { diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp index 0efb2cf9673..616fd754962 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp @@ -1,6 +1,6 @@ #include "transfer.hpp" #include -#include +#include #include // #include #include "contract.hpp" diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.hpp index 8a180d94ae4..3a29e74da8d 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.hpp @@ -1,6 +1,6 @@ #pragma once #include -#include +#include #include "init.hpp" namespace aztec3::circuits::apps::test_apps::escrow { diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.hpp index 19127b313e4..868e29ba96b 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.hpp @@ -1,6 +1,6 @@ #pragma once #include -#include +#include #include "init.hpp" namespace aztec3::circuits::apps::test_apps::escrow { diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw_failure_callback.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw_failure_callback.cpp index 8d60cbdf84a..fb878651f9a 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw_failure_callback.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw_failure_callback.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include "deposit.hpp" #include "contract.hpp" diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw_failure_callback.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw_failure_callback.hpp index 0b3f5513ee4..ed86630ff8c 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw_failure_callback.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw_failure_callback.hpp @@ -1,5 +1,5 @@ #pragma once -#include +#include #include "init.hpp" namespace aztec3::circuits::apps::test_apps::escrow { diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/contract.hpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/contract.hpp index bc73b283dff..f99a8589dd9 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/contract.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/contract.hpp @@ -1,7 +1,7 @@ #pragma once -#include +#include #include -#include +#include #include "init.hpp" namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.cpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.cpp index de53e3e2027..cca31a42a24 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.cpp @@ -1,6 +1,6 @@ #include "function1.hpp" #include -#include +#include #include "contract.hpp" namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.hpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.hpp index a8cf2288947..04f58ddd2b1 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.hpp @@ -1,7 +1,7 @@ #pragma once #include "init.hpp" #include -#include +#include namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { diff --git a/circuits/src/aztec3/circuits/kernel/private/init.hpp b/circuits/src/aztec3/circuits/kernel/private/init.hpp index d6307327547..7de5e57449f 100644 --- a/circuits/src/aztec3/circuits/kernel/private/init.hpp +++ b/circuits/src/aztec3/circuits/kernel/private/init.hpp @@ -6,7 +6,7 @@ #include #include -#include +#include #include From 22563ebd156c69e8910bef0a50bae7c59e56824a Mon Sep 17 00:00:00 2001 From: iAmMichaelConnor Date: Mon, 18 Jul 2022 21:36:27 +0000 Subject: [PATCH 012/166] fix: tests --- circuits/src/aztec3/circuits/abis/call_context.hpp | 2 +- .../src/aztec3/circuits/apps/test_apps/escrow/.test.cpp | 6 +++++- .../test_apps/private_to_private_function_call/.test.cpp | 4 ++-- circuits/src/aztec3/circuits/kernel/private/.test.cpp | 6 ++++-- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/circuits/src/aztec3/circuits/abis/call_context.hpp b/circuits/src/aztec3/circuits/abis/call_context.hpp index c7085ec12d5..a9f766a6b84 100644 --- a/circuits/src/aztec3/circuits/abis/call_context.hpp +++ b/circuits/src/aztec3/circuits/abis/call_context.hpp @@ -20,7 +20,7 @@ template struct CallContext { address msg_sender; address storage_contract_address; - address tx_origin; + address tx_origin = msg_sender; boolean is_delegate_call; boolean is_static_call; diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp index 795d07a5a6f..97b60869d06 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp @@ -20,8 +20,9 @@ TEST(escrow_tests, test_deposit) const NT::fr msg_sender_private_key = 123456789; const NT::address msg_sender = NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); + const NT::address tx_origin = msg_sender; - NativeOracle oracle = NativeOracle(db, contract_address, msg_sender, msg_sender_private_key); + NativeOracle oracle = NativeOracle(db, contract_address, msg_sender, tx_origin, msg_sender_private_key); OracleWrapper oracle_wrapper = OracleWrapper(composer, oracle); FunctionExecutionContext exec_ctx(composer, oracle_wrapper); @@ -52,10 +53,12 @@ TEST(escrow_tests, test_transfer) const NT::fr msg_sender_private_key = 123456789; const NT::address msg_sender = NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); + const NT::address tx_origin = msg_sender; CallContext call_context = { .msg_sender = msg_sender, .storage_contract_address = contract_address, + .tx_origin = msg_sender, .is_fee_payment = true, }; @@ -96,6 +99,7 @@ TEST(escrow_tests, test_withdraw) CallContext call_context = { .msg_sender = msg_sender, .storage_contract_address = contract_address, + .tx_origin = msg_sender, .is_fee_payment = true, }; diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp index 14577149b5f..e0ac26d5213 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp @@ -4,9 +4,9 @@ namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { -class escrow_tests : public ::testing::Test {}; +class private_to_private_function_call_tests : public ::testing::Test {}; -TEST(escrow_tests, test_deposit) +TEST(private_to_private_function_call_tests, test_private_to_private_function_call) { Composer fn1_composer; diff --git a/circuits/src/aztec3/circuits/kernel/private/.test.cpp b/circuits/src/aztec3/circuits/kernel/private/.test.cpp index 7a63cf5ffd6..b94e94ee7ee 100644 --- a/circuits/src/aztec3/circuits/kernel/private/.test.cpp +++ b/circuits/src/aztec3/circuits/kernel/private/.test.cpp @@ -64,14 +64,16 @@ TEST(private_kernel_tests, test_deposit) const NT::fr escrow_contract_leaf_index = 1; const NT::fr escrow_portal_contract_address = 23456; + const NT::fr msg_sender_private_key = 123456789; const NT::address msg_sender = NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); - const NT::fr msg_sender_private_key = 123456789; + const NT::address tx_origin = msg_sender; Composer deposit_composer; DB db; - NativeOracle deposit_oracle = NativeOracle(db, escrow_contract_address, msg_sender, msg_sender_private_key); + NativeOracle deposit_oracle = + NativeOracle(db, escrow_contract_address, msg_sender, tx_origin, msg_sender_private_key); OracleWrapper deposit_oracle_wrapper = OracleWrapper(deposit_composer, deposit_oracle); FunctionExecutionContext deposit_ctx(deposit_composer, deposit_oracle_wrapper); From 8f6e693660304458e900e109cadfc4d1d78dfb86 Mon Sep 17 00:00:00 2001 From: iAmMichaelConnor Date: Fri, 22 Jul 2022 10:53:03 +0000 Subject: [PATCH 013/166] tying up loose ends, before pausing --- .../circuits/apps/l1_function_interface.hpp | 13 +++++- .../circuits/apps/l1_function_interface.tpp | 44 +++++++++---------- .../apps/test_apps/escrow/contract.hpp | 1 + .../.test.cpp | 3 +- 4 files changed, 36 insertions(+), 25 deletions(-) diff --git a/circuits/src/aztec3/circuits/apps/l1_function_interface.hpp b/circuits/src/aztec3/circuits/apps/l1_function_interface.hpp index 27bbd36d562..2f84dac1b43 100644 --- a/circuits/src/aztec3/circuits/apps/l1_function_interface.hpp +++ b/circuits/src/aztec3/circuits/apps/l1_function_interface.hpp @@ -48,9 +48,18 @@ template class L1FunctionInterface { // , num_params(l1_function.num_params) // {} - std::pair, L1Result> call(std::vector args); + std::pair, L1Result> call(std::vector args) + { + if (args.size() != num_params) { + throw_or_abort("Incorrect number of args"); + } + + auto promise = L1Promise(*contract); + L1Result result; + return std::make_pair(promise, result); + } }; } // namespace aztec3::circuits::apps -#include "l1_function_interface.tpp" \ No newline at end of file +// #include "l1_function_interface.tpp" \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/l1_function_interface.tpp b/circuits/src/aztec3/circuits/apps/l1_function_interface.tpp index 28cc9ec5453..c22c2f1f92c 100644 --- a/circuits/src/aztec3/circuits/apps/l1_function_interface.tpp +++ b/circuits/src/aztec3/circuits/apps/l1_function_interface.tpp @@ -1,27 +1,27 @@ -#include -#include -#include -#include -#include "contract.hpp" -#include "l1_promise.hpp" -#include "l1_result.hpp" +// #include +// #include +// #include +// #include +// #include "contract.hpp" +// #include "l1_promise.hpp" +// #include "l1_result.hpp" -namespace aztec3::circuits::apps { +// namespace aztec3::circuits::apps { -using plonk::stdlib::witness_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; +// using plonk::stdlib::witness_t; +// using plonk::stdlib::types::CircuitTypes; +// using plonk::stdlib::types::NativeTypes; -template -std::pair, L1Result> L1FunctionInterface::call(std::vector args) -{ - if (args.size() != num_params) { - throw_or_abort("Incorrect number of args"); - } +// template +// std::pair, L1Result> L1FunctionInterface::call(std::vector args) +// { +// if (args.size() != num_params) { +// throw_or_abort("Incorrect number of args"); +// } - auto promise = L1Promise(*contract); - L1Result result; - return std::make_pair(promise, result); -} +// auto promise = L1Promise(*contract); +// L1Result result; +// return std::make_pair(promise, result); +// } -} // namespace aztec3::circuits::apps \ No newline at end of file +// } // namespace aztec3::circuits::apps \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp index 1b8d7dc4ff0..84eb7457a65 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp @@ -22,6 +22,7 @@ inline Contract init_contract(FunctionExecutionContext& exec { .name = "withdraw_failure_callback", .is_private = true }, }); + // TODO: this L1 declaration interface is just to get something working. contract.import_l1_function({ .function_name = "withdraw", .function_selector = 12345, diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp index e0ac26d5213..5cd1a6d13d2 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp @@ -16,8 +16,9 @@ TEST(private_to_private_function_call_tests, test_private_to_private_function_ca const NT::fr msg_sender_private_key = 123456789; const NT::address msg_sender = NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); + const NT::address tx_origin = msg_sender; - NativeOracle fn1_oracle = NativeOracle(db, contract_address, msg_sender, msg_sender_private_key); + NativeOracle fn1_oracle = NativeOracle(db, contract_address, msg_sender, tx_origin, msg_sender_private_key); OracleWrapper fn1_oracle_wrapper = OracleWrapper(fn1_composer, fn1_oracle); FunctionExecutionContext fn1_exec_ctx(fn1_composer, fn1_oracle_wrapper); From b3eee49b00104a0d002124922375206718ffc9d0 Mon Sep 17 00:00:00 2001 From: iAmMichaelConnor Date: Sun, 11 Dec 2022 22:29:43 +0000 Subject: [PATCH 014/166] Huge ABI changes, given Q4 2022 speccing talks --- circuits/src/aztec3/circuits/abis/.test.cpp | 190 +++++++++++++ .../src/aztec3/circuits/abis/abis.test.cpp | 252 ------------------ .../src/aztec3/circuits/abis/call_context.hpp | 73 ++--- .../aztec3/circuits/abis/call_stack_item.hpp | 48 ++-- .../circuits/abis/callback_stack_item.hpp | 121 --------- ...contract_deployment_call_public_inputs.hpp | 4 +- .../circuits/abis/executed_callback.hpp | 101 ------- .../circuits/abis/function_signature.hpp | 15 +- circuits/src/aztec3/circuits/abis/index.hpp | 2 - .../abis/optionally_revealed_data.hpp | 9 +- .../abis/private_circuit_public_inputs.hpp | 181 +++++-------- .../abis/private_kernel/accumulated_data.hpp | 29 +- .../call_context_reconciliation_data.hpp | 58 ++++ .../abis/private_kernel/constant_data.hpp | 25 +- .../abis/private_kernel/old_tree_roots.hpp | 6 +- .../private_kernel/previous_kernel_data.hpp | 6 +- .../abis/private_kernel/private_call_data.hpp | 26 +- .../abis/private_kernel/private_inputs.hpp | 14 +- .../abis/private_kernel/public_inputs.hpp | 11 +- .../abis/public_circuit_public_inputs.hpp | 148 +++++----- .../aztec3/circuits/abis/signed_tx_object.hpp | 55 ++++ .../src/aztec3/circuits/abis/state_read.hpp | 10 + .../aztec3/circuits/abis/state_transition.hpp | 11 + .../src/aztec3/circuits/abis/tx_context.hpp | 85 ++++++ .../src/aztec3/circuits/abis/tx_object.hpp | 84 ++++++ .../src/aztec3/circuits/apps/contract.hpp | 3 +- .../src/aztec3/circuits/apps/contract.tpp | 8 +- .../apps/function_execution_context.hpp | 14 +- circuits/src/aztec3/circuits/apps/index.hpp | 1 - circuits/src/aztec3/circuits/apps/l1_call.hpp | 2 +- .../circuits/apps/l1_function_interface.hpp | 13 +- .../src/aztec3/circuits/apps/l1_promise.hpp | 41 --- .../src/aztec3/circuits/apps/l1_promise.tpp | 84 ------ .../src/aztec3/circuits/apps/l1_result.hpp | 28 -- .../aztec3/circuits/apps/oracle_wrapper.hpp | 3 +- .../circuits/apps/private_state.test.cpp | 3 +- .../circuits/apps/private_state_factory.hpp | 33 --- .../circuits/apps/private_state_note.hpp | 2 +- .../circuits/apps/private_state_note.tpp | 9 +- .../circuits/apps/private_state_var.hpp | 6 +- .../circuits/apps/private_state_var.tpp | 11 +- .../circuits/apps/test_apps/escrow/.test.cpp | 6 +- .../apps/test_apps/escrow/contract.hpp | 3 +- .../apps/test_apps/escrow/deposit.cpp | 4 +- .../apps/test_apps/escrow/deposit.hpp | 4 +- .../circuits/apps/test_apps/escrow/index.hpp | 3 +- .../circuits/apps/test_apps/escrow/init.hpp | 8 +- .../apps/test_apps/escrow/transfer.cpp | 8 +- .../apps/test_apps/escrow/transfer.hpp | 4 +- .../apps/test_apps/escrow/withdraw.cpp | 28 +- .../escrow/withdraw_failure_callback.cpp | 49 ---- .../escrow/withdraw_failure_callback.hpp | 13 - .../aztec3/circuits/kernel/private/.test.cpp | 197 ++++++++------ .../aztec3/circuits/kernel/private/init.hpp | 10 +- .../kernel/private/private_kernel_circuit.cpp | 233 ++++++++-------- .../kernel/private/private_kernel_circuit.hpp | 2 + ..._circuit_2.hpp => mock_kernel_circuit.hpp} | 2 +- circuits/src/aztec3/constants.hpp | 12 +- circuits/src/aztec3/oracle/oracle.hpp | 24 +- 59 files changed, 1080 insertions(+), 1355 deletions(-) create mode 100644 circuits/src/aztec3/circuits/abis/.test.cpp delete mode 100644 circuits/src/aztec3/circuits/abis/abis.test.cpp delete mode 100644 circuits/src/aztec3/circuits/abis/callback_stack_item.hpp delete mode 100644 circuits/src/aztec3/circuits/abis/executed_callback.hpp create mode 100644 circuits/src/aztec3/circuits/abis/private_kernel/call_context_reconciliation_data.hpp create mode 100644 circuits/src/aztec3/circuits/abis/signed_tx_object.hpp create mode 100644 circuits/src/aztec3/circuits/abis/tx_context.hpp create mode 100644 circuits/src/aztec3/circuits/abis/tx_object.hpp delete mode 100644 circuits/src/aztec3/circuits/apps/l1_promise.hpp delete mode 100644 circuits/src/aztec3/circuits/apps/l1_promise.tpp delete mode 100644 circuits/src/aztec3/circuits/apps/l1_result.hpp delete mode 100644 circuits/src/aztec3/circuits/apps/private_state_factory.hpp delete mode 100644 circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw_failure_callback.cpp delete mode 100644 circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw_failure_callback.hpp rename circuits/src/aztec3/circuits/mock/{mock_circuit_2.hpp => mock_kernel_circuit.hpp} (92%) diff --git a/circuits/src/aztec3/circuits/abis/.test.cpp b/circuits/src/aztec3/circuits/abis/.test.cpp new file mode 100644 index 00000000000..dda79da9a88 --- /dev/null +++ b/circuits/src/aztec3/circuits/abis/.test.cpp @@ -0,0 +1,190 @@ +#include +#include +#include +// #include +#include "index.hpp" +#include + +namespace aztec3::circuits::abis { + +using TurboComposer = plonk::stdlib::types::turbo::Composer; +using CT = plonk::stdlib::types::CircuitTypes; +using NT = plonk::stdlib::types::NativeTypes; + +class abi_tests : public ::testing::Test {}; + +TEST(abi_tests, test_native_function_signature) +{ + FunctionSignature function_signature = { + .vk_index = 11, + .is_private = false, + .is_constructor = false, + }; + + info("function signature: ", function_signature); + + auto buffer = to_buffer(function_signature); + auto function_signature_2 = from_buffer>(buffer.data()); + + EXPECT_EQ(function_signature, function_signature_2); +} + +TEST(abi_tests, test_native_to_circuit_function_signature) +{ + FunctionSignature native_function_signature = { + .vk_index = 11, + .is_private = false, + .is_constructor = false, + }; + + info("function signature: ", native_function_signature); + + TurboComposer turbo_composer; + FunctionSignature circuit_function_signature = native_function_signature.to_circuit_type(turbo_composer); + + info("function signature: ", circuit_function_signature); +} + +TEST(abi_tests, test_native_call_context) +{ + CallContext call_context = { + .msg_sender = 10, + .storage_contract_address = 11, + .tx_origin = 12, + .is_delegate_call = false, + .is_static_call = false, + }; + + info("call context: ", call_context); +} + +TEST(abi_tests, test_native_to_circuit_call_context) +{ + CallContext native_call_context = { + .msg_sender = 10, + .storage_contract_address = 11, + .tx_origin = 12, + .is_delegate_call = false, + .is_static_call = false, + }; + + info("call context: ", native_call_context); + + TurboComposer turbo_composer; + CallContext circuit_call_context = native_call_context.to_circuit_type(turbo_composer); + + info("call context: ", circuit_call_context); +} + +// TEST(abi_tests, test_native_public_inputs) +// { +// PublicCircuitPublicInputs public_inputs = { +// .custom_inputs = { 1, 2, 3, 4, 5, 6, 7, 8 }, +// .custom_outputs = { 9, 10, 11, 12 }, +// .emitted_events = { 13, 14, 15, 16 }, +// .state_transitions = { { { 21, 22, 23 }, { 21, 22, 23 }, { 21, 22, 23 }, { 21, 22, 23 } } }, +// .state_reads = { { { 24, 25 }, { 24, 25 }, { 24, 25 }, { 24, 25 } } }, +// .public_call_stack = { 26, 27, 28, 29 }, +// .contract_deployment_call_stack = { 30, 31 }, +// .partial_l1_call_stack = { 32, 33 }, +// .old_private_data_tree_root = 38, +// }; + +// info("public_circuit_public_inputs: ", public_inputs); +// } + +// TEST(abi_tests, test_native_to_circuit_public_circuit_public_inputs) +// { +// PublicCircuitPublicInputs native_public_inputs = { +// .custom_inputs = { 1, 2, 3, 4, 5, 6, 7, 8 }, +// .custom_outputs = { 9, 10, 11, 12 }, +// .emitted_events = { 13, 14, 15, 16 }, +// .state_transitions = { { { 21, 22, 23 }, { 21, 22, 23 }, { 21, 22, 23 }, { 21, 22, 23 } } }, +// .state_reads = { { { 24, 25 }, { 24, 25 }, { 24, 25 }, { 24, 25 } } }, +// .public_call_stack = { 26, 27, 28, 29 }, +// .contract_deployment_call_stack = { 30, 31 }, +// .partial_l1_call_stack = { 32, 33 }, +// .old_private_data_tree_root = 38, +// }; + +// info("public_circuit_public_inputs: ", native_public_inputs); + +// TurboComposer turbo_composer; +// PublicCircuitPublicInputs circuit_public_inputs = native_public_inputs.to_circuit_type(turbo_composer); + +// info("public_circuit_public_inputs: ", circuit_public_inputs); +// } + +// TEST(abi_tests, test_native_call_stack_item) +// { +// PublicCircuitPublicInputs public_inputs = { +// .custom_inputs = { 1, 2, 3, 4, 5, 6, 7, 8 }, +// .custom_outputs = { 9, 10, 11, 12 }, +// .emitted_events = { 13, 14, 15, 16 }, +// .state_transitions = { { { 21, 22, 23 }, { 21, 22, 23 }, { 21, 22, 23 }, { 21, 22, 23 } } }, +// .state_reads = { { { 24, 25 }, { 24, 25 }, { 24, 25 }, { 24, 25 } } }, +// .public_call_stack = { 26, 27, 28, 29 }, +// .contract_deployment_call_stack = { 30, 31 }, +// .partial_l1_call_stack = { 32, 33 }, +// .old_private_data_tree_root = 38, +// }; + +// CallStackItem call_stack_item = { +// .function_signature = { +// // .contract_address = 10, +// .vk_index = 11, +// .is_private = false, +// .is_constructor = false, +// }, +// .public_inputs = public_inputs, +// .call_context = { +// .msg_sender = 13, +// .storage_contract_address = 14, +// }, +// .is_delegate_call = false, +// .is_static_call = false, +// }; + +// info("call stack item: ", call_stack_item); +// } + +// TEST(abi_tests, test_native_to_circuit_call_stack_item) +// { +// PublicCircuitPublicInputs public_inputs = { +// .custom_inputs = { 1, 2, 3, 4, 5, 6, 7, 8 }, +// .custom_outputs = { 9, 10, 11, 12 }, +// .emitted_events = { 13, 14, 15, 16 }, +// .state_transitions = { { { 21, 22, 23 }, { 21, 22, 23 }, { 21, 22, 23 }, { 21, 22, 23 } } }, +// .state_reads = { { { 24, 25 }, { 24, 25 }, { 24, 25 }, { 24, 25 } } }, +// .public_call_stack = { 26, 27, 28, 29 }, +// .contract_deployment_call_stack = { 30, 31 }, +// .partial_l1_call_stack = { 32, 33 }, +// .old_private_data_tree_root = 38, +// }; + +// CallStackItem native_call_stack_item = { +// .function_signature = { +// // .contract_address = 10, +// .vk_index = 11, +// .is_private = false, +// .is_constructor = false, +// }, +// .public_inputs = public_inputs, +// .call_context = { +// .msg_sender = 13, +// .storage_contract_address = 14, +// }, +// .is_delegate_call = false, +// .is_static_call = false, +// }; + +// info("call stack item: ", native_call_stack_item); + +// TurboComposer turbo_composer; +// CallStackItem circuit_call_stack_item = +// native_call_stack_item.to_circuit_type(turbo_composer); + +// info("call stack item: ", circuit_call_stack_item); +// } + +} // namespace aztec3::circuits::abis \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/abis/abis.test.cpp b/circuits/src/aztec3/circuits/abis/abis.test.cpp deleted file mode 100644 index 126bc0b873c..00000000000 --- a/circuits/src/aztec3/circuits/abis/abis.test.cpp +++ /dev/null @@ -1,252 +0,0 @@ -#include -#include -#include -// #include -#include "index.hpp" -#include - -namespace aztec3::circuits::abis { - -using TurboComposer = plonk::stdlib::types::turbo::Composer; -using CT = plonk::stdlib::types::CircuitTypes; -using NT = plonk::stdlib::types::NativeTypes; - -class abi_tests : public ::testing::Test {}; - -TEST(abi_tests, test_native_function_signature) -{ - FunctionSignature function_signature = { - // .contract_address = 10, - .vk_index = 11, - .is_private = false, - .is_constructor = false, - }; - - info("function signature: ", function_signature); - - auto buffer = to_buffer(function_signature); - auto function_signature_2 = from_buffer>(buffer.data()); - - EXPECT_EQ(function_signature, function_signature_2); -} - -TEST(abi_tests, test_native_to_circuit_function_signature) -{ - FunctionSignature native_function_signature = { - // .contract_address = 10, - .vk_index = 11, - .is_private = false, - .is_constructor = false, - }; - - info("function signature: ", native_function_signature); - - TurboComposer turbo_composer; - FunctionSignature circuit_function_signature = native_function_signature.to_circuit_type(turbo_composer); - - info("function signature: ", circuit_function_signature); -} - -TEST(abi_tests, test_native_call_context) -{ - CallContext call_context = { - .msg_sender = 10, - .storage_contract_address = 11, - }; - - info("call context: ", call_context); -} - -TEST(abi_tests, test_native_to_circuit_call_context) -{ - CallContext native_call_context = { - .msg_sender = 10, - .storage_contract_address = 11, - }; - - info("call context: ", native_call_context); - - TurboComposer turbo_composer; - CallContext circuit_call_context = native_call_context.to_circuit_type(turbo_composer); - - info("call context: ", circuit_call_context); -} - -TEST(abi_tests, test_native_public_inputs) -{ - PublicCircuitPublicInputs public_inputs = { - .custom_inputs = { 1, 2, 3, 4, 5, 6, 7, 8 }, - .custom_outputs = { 9, 10, 11, 12 }, - .emitted_public_inputs = { 13, 14, 15, 16 }, - .emitted_outputs = { 17, 18, 19, 20 }, - .executed_callback = ExecutedCallback::empty(), - .state_transitions = { { { 21, 22, 23 }, { 21, 22, 23 }, { 21, 22, 23 }, { 21, 22, 23 } } }, - .state_reads = { { { 24, 25 }, { 24, 25 }, { 24, 25 }, { 24, 25 } } }, - .public_call_stack = { 26, 27, 28, 29 }, - .contract_deployment_call_stack = { 30, 31 }, - .partial_l1_call_stack = { 32, 33 }, - .callback_stack = { { { 34, 35, 36, 37 }, { 34, 35, 36, 37 } } }, - .old_private_data_tree_root = 38, - }; - - info("public_circuit_public_inputs: ", public_inputs); -} - -TEST(abi_tests, test_native_to_circuit_public_circuit_public_inputs) -{ - PublicCircuitPublicInputs native_public_inputs = { - .custom_inputs = { 1, 2, 3, 4, 5, 6, 7, 8 }, - .custom_outputs = { 9, 10, 11, 12 }, - .emitted_public_inputs = { 13, 14, 15, 16 }, - .emitted_outputs = { 17, 18, 19, 20 }, - .executed_callback = ExecutedCallback::empty(), - .state_transitions = { { { 21, 22, 23 }, { 21, 22, 23 }, { 21, 22, 23 }, { 21, 22, 23 } } }, - .state_reads = { { { 24, 25 }, { 24, 25 }, { 24, 25 }, { 24, 25 } } }, - .public_call_stack = { 26, 27, 28, 29 }, - .contract_deployment_call_stack = { 30, 31 }, - .partial_l1_call_stack = { 32, 33 }, - .callback_stack = { { { 34, 35, 36, 37 }, { 34, 35, 36, 37 } } }, - .old_private_data_tree_root = 38, - }; - - info("public_circuit_public_inputs: ", native_public_inputs); - - TurboComposer turbo_composer; - PublicCircuitPublicInputs circuit_public_inputs = native_public_inputs.to_circuit_type(turbo_composer); - - info("public_circuit_public_inputs: ", circuit_public_inputs); -} - -TEST(abi_tests, test_native_call_stack_item) -{ - PublicCircuitPublicInputs public_inputs = { - .custom_inputs = { 1, 2, 3, 4, 5, 6, 7, 8 }, - .custom_outputs = { 9, 10, 11, 12 }, - .emitted_public_inputs = { 13, 14, 15, 16 }, - .emitted_outputs = { 17, 18, 19, 20 }, - .executed_callback = ExecutedCallback::empty(), - .state_transitions = { { { 21, 22, 23 }, { 21, 22, 23 }, { 21, 22, 23 }, { 21, 22, 23 } } }, - .state_reads = { { { 24, 25 }, { 24, 25 }, { 24, 25 }, { 24, 25 } } }, - .public_call_stack = { 26, 27, 28, 29 }, - .contract_deployment_call_stack = { 30, 31 }, - .partial_l1_call_stack = { 32, 33 }, - .callback_stack = { { { 34, 35, 36, 37 }, { 34, 35, 36, 37 } } }, - .old_private_data_tree_root = 38, - }; - - CallStackItem call_stack_item = { - .function_signature = { - // .contract_address = 10, - .vk_index = 11, - .is_private = false, - .is_constructor = false, - }, - .public_inputs = public_inputs, - .call_context = { - .msg_sender = 13, - .storage_contract_address = 14, - }, - .is_delegate_call = false, - .is_static_call = false, - }; - - info("call stack item: ", call_stack_item); -} - -TEST(abi_tests, test_native_to_circuit_call_stack_item) -{ - PublicCircuitPublicInputs public_inputs = { - .custom_inputs = { 1, 2, 3, 4, 5, 6, 7, 8 }, - .custom_outputs = { 9, 10, 11, 12 }, - .emitted_public_inputs = { 13, 14, 15, 16 }, - .emitted_outputs = { 17, 18, 19, 20 }, - .executed_callback = ExecutedCallback::empty(), - .state_transitions = { { { 21, 22, 23 }, { 21, 22, 23 }, { 21, 22, 23 }, { 21, 22, 23 } } }, - .state_reads = { { { 24, 25 }, { 24, 25 }, { 24, 25 }, { 24, 25 } } }, - .public_call_stack = { 26, 27, 28, 29 }, - .contract_deployment_call_stack = { 30, 31 }, - .partial_l1_call_stack = { 32, 33 }, - .callback_stack = { { { 34, 35, 36, 37 }, { 34, 35, 36, 37 } } }, - .old_private_data_tree_root = 38, - }; - - CallStackItem native_call_stack_item = { - .function_signature = { - // .contract_address = 10, - .vk_index = 11, - .is_private = false, - .is_constructor = false, - }, - .public_inputs = public_inputs, - .call_context = { - .msg_sender = 13, - .storage_contract_address = 14, - }, - .is_delegate_call = false, - .is_static_call = false, - }; - - info("call stack item: ", native_call_stack_item); - - TurboComposer turbo_composer; - CallStackItem circuit_call_stack_item = - native_call_stack_item.to_circuit_type(turbo_composer); - - info("call stack item: ", circuit_call_stack_item); -} - -TEST(abi_tests, test_native_callback_stack_item) -{ - CallbackStackItem callback_stack_item = { - .callback_public_key = 1, - .success_callback_call_hash = 2, - .failure_callback_call_hash = 3, - .success_result_arg_map_acc = 4, - }; - - info("callback stack item: ", callback_stack_item); -} - -TEST(abi_tests, test_native_to_circuit_callback_stack_item) -{ - CallbackStackItem native_callback_stack_item = { - .callback_public_key = 1, - .success_callback_call_hash = 2, - .failure_callback_call_hash = 3, - .success_result_arg_map_acc = 4, - }; - - info("callback stack item: ", native_callback_stack_item); - - TurboComposer turbo_composer; - CallbackStackItem circuit_callback_stack_item = native_callback_stack_item.to_circuit_type(turbo_composer); - - info("callback stack item: ", circuit_callback_stack_item); -} - -TEST(abi_tests, test_native_executed_callback) -{ - ExecutedCallback executed_callback = { - .l1_result_hash = 1, - .l1_results_tree_leaf_index = 2, - }; - - info("executed callback: ", executed_callback); -} - -TEST(abi_tests, test_native_to_circuit_executed_callback) -{ - ExecutedCallback native_executed_callback = { - .l1_result_hash = 1, - .l1_results_tree_leaf_index = 2, - }; - - info("executed callback: ", native_executed_callback); - - TurboComposer turbo_composer; - ExecutedCallback circuit_executed_callback = native_executed_callback.to_circuit_type(turbo_composer); - - info("executed callback: ", circuit_executed_callback); -} - -} // namespace aztec3::circuits::abis \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/abis/call_context.hpp b/circuits/src/aztec3/circuits/abis/call_context.hpp index a9f766a6b84..e98b508ac34 100644 --- a/circuits/src/aztec3/circuits/abis/call_context.hpp +++ b/circuits/src/aztec3/circuits/abis/call_context.hpp @@ -1,10 +1,11 @@ #pragma once + +#include +#include #include -#include #include #include -#include -#include +#include namespace aztec3::circuits::abis { @@ -25,24 +26,16 @@ template struct CallContext { boolean is_delegate_call; boolean is_static_call; - boolean is_callback; - - boolean is_fee_payment; - boolean pay_fee_from_l1; - boolean pay_fee_from_public_l2; - boolean called_from_l1; - boolean called_from_public_l2; + fr reference_block_num; boolean operator==(CallContext const& other) const { return msg_sender == other.msg_sender && storage_contract_address == other.storage_contract_address && tx_origin == other.tx_origin && is_delegate_call == other.is_delegate_call && - is_static_call == other.is_static_call && is_callback == other.is_callback && - is_fee_payment == other.is_fee_payment && pay_fee_from_l1 == other.pay_fee_from_l1 && - called_from_public_l2 == other.called_from_public_l2; + is_static_call == other.is_static_call && reference_block_num == other.reference_block_num; }; - static CallContext empty() { return { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; }; + static CallContext empty() { return { 0, 0, 0, 0, 0, 0 }; }; template CallContext> to_circuit_type(Composer& composer) const { @@ -53,9 +46,7 @@ template struct CallContext { CallContext> call_context = { to_ct(msg_sender), to_ct(storage_contract_address), to_ct(tx_origin), - to_ct(is_delegate_call), to_ct(is_static_call), to_ct(is_callback), - to_ct(is_fee_payment), to_ct(pay_fee_from_l1), to_ct(pay_fee_from_public_l2), - to_ct(called_from_l1), to_ct(called_from_public_l2), + to_ct(is_delegate_call), to_ct(is_static_call), to_ct(reference_block_num), }; @@ -69,9 +60,7 @@ template struct CallContext { CallContext call_context = { to_nt(msg_sender), to_nt(storage_contract_address), to_nt(tx_origin), - to_nt(is_delegate_call), to_nt(is_static_call), to_nt(is_callback), - to_nt(is_fee_payment), to_nt(pay_fee_from_l1), to_nt(pay_fee_from_public_l2), - to_nt(called_from_l1), to_nt(called_from_public_l2), + to_nt(is_delegate_call), to_nt(is_static_call), to_nt(reference_block_num), }; return call_context; @@ -80,12 +69,9 @@ template struct CallContext { fr hash() const { std::vector inputs = { - msg_sender.to_field(), storage_contract_address.to_field(), - tx_origin.to_field(), fr(is_delegate_call), - fr(is_static_call), fr(is_callback), - fr(is_fee_payment), fr(pay_fee_from_l1), - fr(pay_fee_from_public_l2), fr(called_from_l1), - fr(called_from_public_l2), + msg_sender.to_field(), storage_contract_address.to_field(), + tx_origin.to_field(), fr(is_delegate_call), + fr(is_static_call), reference_block_num, }; return NCT::compress(inputs, GeneratorIndex::CALL_CONTEXT); @@ -100,12 +86,7 @@ template struct CallContext { tx_origin.to_field().assert_is_zero(); fr(is_delegate_call).assert_is_zero(); fr(is_static_call).assert_is_zero(); - fr(is_callback).assert_is_zero(); - fr(is_fee_payment).assert_is_zero(); - fr(pay_fee_from_l1).assert_is_zero(); - fr(pay_fee_from_public_l2).assert_is_zero(); - fr(called_from_l1).assert_is_zero(); - fr(called_from_public_l2).assert_is_zero(); + reference_block_num.assert_is_zero(); } void set_public() @@ -117,12 +98,7 @@ template struct CallContext { tx_origin.to_field().set_public(); fr(is_delegate_call).set_public(); fr(is_static_call).set_public(); - fr(is_callback).set_public(); - fr(is_fee_payment).set_public(); - fr(pay_fee_from_l1).set_public(); - fr(pay_fee_from_public_l2).set_public(); - fr(called_from_l1).set_public(); - fr(called_from_public_l2).set_public(); + reference_block_num.set_public(); } }; @@ -135,12 +111,7 @@ template void read(uint8_t const*& it, CallContext& call_con read(it, call_context.tx_origin); read(it, call_context.is_delegate_call); read(it, call_context.is_static_call); - read(it, call_context.is_callback); - read(it, call_context.is_fee_payment); - read(it, call_context.pay_fee_from_l1); - read(it, call_context.pay_fee_from_public_l2); - read(it, call_context.called_from_l1); - read(it, call_context.called_from_public_l2); + read(it, call_context.reference_block_num); }; template void write(std::vector& buf, CallContext const& call_context) @@ -152,12 +123,7 @@ template void write(std::vector& buf, CallContext c write(buf, call_context.tx_origin); write(buf, call_context.is_delegate_call); write(buf, call_context.is_static_call); - write(buf, call_context.is_callback); - write(buf, call_context.is_fee_payment); - write(buf, call_context.pay_fee_from_l1); - write(buf, call_context.pay_fee_from_public_l2); - write(buf, call_context.called_from_l1); - write(buf, call_context.called_from_public_l2); + write(buf, call_context.reference_block_num); }; template std::ostream& operator<<(std::ostream& os, CallContext const& call_context) @@ -167,12 +133,7 @@ template std::ostream& operator<<(std::ostream& os, CallContext -#include #include #include +#include namespace aztec3::circuits::abis { @@ -22,6 +21,7 @@ enum class CallType { }; template struct CallStackItem { + typedef typename NCT::address address; typedef typename NCT::boolean boolean; typedef typename NCT::fr fr; @@ -29,17 +29,15 @@ template struct CallStackItem { using PublicInputs = typename std:: conditional, PrivateCircuitPublicInputs>::type; + address contract_address; FunctionSignature function_signature; PublicInputs public_inputs; - CallContext call_context; - boolean is_delegate_call = false; - boolean is_static_call = false; bool operator==(CallStackItem const&) const = default; template static CallStackItem empty() { - return { FunctionSignature::empty(), PublicInputs::empty(), CallContext::empty(), 0, 0 }; + return { 0, FunctionSignature::empty(), PublicInputs::empty() }; }; template @@ -51,11 +49,9 @@ template struct CallStackItem { auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; CallStackItem, call_type> call_stack_item = { + to_ct(contract_address), function_signature.to_circuit_type(composer), public_inputs.to_circuit_type(composer), - call_context.to_circuit_type(composer), - to_ct(is_delegate_call), - to_ct(is_static_call), }; return call_stack_item; @@ -64,24 +60,32 @@ template struct CallStackItem { fr hash() const { std::vector inputs = { - function_signature.hash(), public_inputs.hash(), call_context.hash(), - fr(is_delegate_call), fr(is_static_call), + contract_address.to_field(), + function_signature.hash(), + public_inputs + .hash(), // Note: this public_inputs.hash() omits hashing of the public_inputs.call_context, because we + // want to 'unwrap' it with the fewest hashes possible in the kernel circuit. }; - return NCT::compress(inputs, GeneratorIndex::CALL_STACK_ITEM); + fr call_stack_item_hash_no_context = NCT::compress(inputs, GeneratorIndex::CALL_STACK_ITEM); + + fr call_context_hash = public_inputs.call_context.hash(); + + fr call_stack_item_hash = + NCT::compress({ call_context_hash, call_stack_item_hash_no_context }, GeneratorIndex::CALL_STACK_ITEM_2); + + return call_stack_item_hash; } -}; +}; // namespace aztec3::circuits::abis template void read(uint8_t const*& it, CallStackItem& call_stack_item) { using serialize::read; + read(it, call_stack_item.contract_address); read(it, call_stack_item.function_signature); read(it, call_stack_item.public_inputs_hash); - read(it, call_stack_item.call_context); - read(it, call_stack_item.is_delegate_call); - read(it, call_stack_item.is_callback); }; template @@ -89,21 +93,17 @@ void write(std::vector& buf, CallStackItem const& call_ { using serialize::write; + write(buf, call_stack_item.contract_address); write(buf, call_stack_item.function_signature); write(buf, call_stack_item.public_inputs_hash); - write(buf, call_stack_item.call_context); - write(buf, call_stack_item.is_delegate_call); - write(buf, call_stack_item.is_static_call); }; template std::ostream& operator<<(std::ostream& os, CallStackItem const& call_stack_item) { - return os << "function_signature: " << call_stack_item.function_signature << "\n" - << "public_inputs: " << call_stack_item.public_inputs << "\n" - << "call_context: " << call_stack_item.call_context << "\n" - << "is_delegate_call: " << call_stack_item.is_delegate_call << "\n" - << "is_static_call: " << call_stack_item.is_static_call << "\n"; + return os << "contract_address: " << call_stack_item.contract_address << "\n" + << "function_signature: " << call_stack_item.function_signature << "\n" + << "public_inputs: " << call_stack_item.public_inputs << "\n"; } } // namespace aztec3::circuits::abis \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/abis/callback_stack_item.hpp b/circuits/src/aztec3/circuits/abis/callback_stack_item.hpp deleted file mode 100644 index 110edaac2bf..00000000000 --- a/circuits/src/aztec3/circuits/abis/callback_stack_item.hpp +++ /dev/null @@ -1,121 +0,0 @@ -#pragma once -#include -#include -#include -#include - -namespace aztec3::circuits::abis { - -using plonk::stdlib::witness_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; - -template struct CallbackStackItem { - typedef typename NCT::address address; - typedef typename NCT::fr fr; - - address callback_public_key; - fr success_callback_call_hash; - fr failure_callback_call_hash; - fr success_result_arg_map_acc; - - bool operator==(CallbackStackItem const&) const = default; - - static CallbackStackItem empty() { return { 0, 0, 0, 0 }; }; - - template CallbackStackItem> to_circuit_type(Composer& composer) const - { - static_assert((std::is_same::value)); - - // Capture the composer: - auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; - - CallbackStackItem> callback_stack_item = { - to_ct(callback_public_key), - to_ct(success_callback_call_hash), - to_ct(failure_callback_call_hash), - to_ct(success_result_arg_map_acc), - }; - - return callback_stack_item; - }; - - template CallbackStackItem to_native_type() const - { - static_assert(std::is_same, NCT>::value); - auto to_nt = [&](auto& e) { return plonk::stdlib::types::to_nt(e); }; - - CallbackStackItem callback_stack_item = { - to_nt(callback_public_key), - to_nt(success_callback_call_hash), - to_nt(failure_callback_call_hash), - to_nt(success_result_arg_map_acc), - }; - - return callback_stack_item; - }; - - template void assert_is_zero() - { - static_assert((std::is_same, NCT>::value)); - - callback_public_key.to_field().assert_is_zero(); - success_callback_call_hash.assert_is_zero(); - failure_callback_call_hash.assert_is_zero(); - success_result_arg_map_acc.assert_is_zero(); - } - - template void set_public() - { - static_assert((std::is_same, NCT>::value)); - - callback_public_key.to_field().set_public(); - success_callback_call_hash.set_public(); - failure_callback_call_hash.set_public(); - success_result_arg_map_acc.set_public(); - } - - fr hash() const - { - std::vector inputs = { - callback_public_key.to_field(), - success_callback_call_hash, - failure_callback_call_hash, - success_result_arg_map_acc, - }; - - return NCT::compress(inputs, GeneratorIndex::CALLBACK_STACK_ITEM); - } -}; - -template void read(uint8_t const*& it, CallbackStackItem& callback_stack_item) -{ - using serialize::read; - - read(it, callback_stack_item.callback_public_key); - read(it, callback_stack_item.success_callback_call_hash); - read(it, callback_stack_item.failure_callback_call_hash); - read(it, callback_stack_item.success_result_arg_map_acc); - read(it, callback_stack_item.is_callback); -}; - -template void write(std::vector& buf, CallbackStackItem const& callback_stack_item) -{ - using serialize::write; - - write(buf, callback_stack_item.callback_public_key); - write(buf, callback_stack_item.success_callback_call_hash); - write(buf, callback_stack_item.failure_callback_call_hash); - write(buf, callback_stack_item.success_result_arg_map_acc); - write(buf, callback_stack_item.is_static_call); -}; - -template std::ostream& operator<<(std::ostream& os, CallbackStackItem const& callback_stack_item) -{ - return os << "callback_public_key: " << callback_stack_item.callback_public_key << "\n" - << "success_callback_call_hash: " << callback_stack_item.success_callback_call_hash << "\n" - << "failure_callback_call_hash: " << callback_stack_item.failure_callback_call_hash << "\n" - << "success_result_arg_map_acc: " << callback_stack_item.success_result_arg_map_acc << "\n"; -} - -} // namespace aztec3::circuits::abis \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/abis/contract_deployment_call_public_inputs.hpp b/circuits/src/aztec3/circuits/abis/contract_deployment_call_public_inputs.hpp index e34563ca316..90b148b60b9 100644 --- a/circuits/src/aztec3/circuits/abis/contract_deployment_call_public_inputs.hpp +++ b/circuits/src/aztec3/circuits/abis/contract_deployment_call_public_inputs.hpp @@ -1,13 +1,11 @@ #pragma once // #include +#include "../../constants.hpp" #include #include #include #include #include -#include "../../constants.hpp" -#include "executed_callback.hpp" -#include "callback_stack_item.hpp" namespace aztec3::circuits::abis { diff --git a/circuits/src/aztec3/circuits/abis/executed_callback.hpp b/circuits/src/aztec3/circuits/abis/executed_callback.hpp deleted file mode 100644 index c7af4217da1..00000000000 --- a/circuits/src/aztec3/circuits/abis/executed_callback.hpp +++ /dev/null @@ -1,101 +0,0 @@ -#pragma once -#include -#include -#include -#include - -namespace aztec3::circuits::abis { - -using plonk::stdlib::witness_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; - -template struct ExecutedCallback { - typedef typename NCT::fr fr; - typedef typename NCT::uint32 uint32; - - fr l1_result_hash; - uint32 l1_results_tree_leaf_index; - - bool operator==(ExecutedCallback const&) const = default; - - static ExecutedCallback empty() { return { 0, 0 }; }; - - template ExecutedCallback> to_circuit_type(Composer& composer) const - { - static_assert((std::is_same::value)); - - // Capture the composer: - auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; - - ExecutedCallback> executed_callback = { - to_ct(l1_result_hash), - to_ct(l1_results_tree_leaf_index), - }; - - return executed_callback; - }; - - template ExecutedCallback to_native_type() const - { - static_assert(std::is_same, NCT>::value); - auto to_nt = [&](auto& e) { return plonk::stdlib::types::to_nt(e); }; - - ExecutedCallback executed_callback = { - to_nt(l1_result_hash), - to_nt(l1_results_tree_leaf_index), - }; - - return executed_callback; - }; - - fr hash() const - { - std::vector inputs = { - l1_result_hash, - fr(l1_results_tree_leaf_index), - }; - - return NCT::compress(inputs, GeneratorIndex::EXECUTED_CALLBACK); - } - - template void assert_is_zero() - { - static_assert((std::is_same, NCT>::value)); - - l1_result_hash.assert_is_zero(); - fr(l1_results_tree_leaf_index).assert_is_zero(); - } - - void set_public() - { - static_assert(!(std::is_same::value)); - - l1_result_hash.set_public(); - fr(l1_results_tree_leaf_index).set_public(); - } -}; - -template void read(uint8_t const*& it, ExecutedCallback& executed_callback) -{ - using serialize::read; - - read(it, executed_callback.l1_result_hash); - read(it, executed_callback.l1_results_tree_leaf_index); -}; - -template void write(std::vector& buf, ExecutedCallback const& executed_callback) -{ - using serialize::write; - - write(buf, executed_callback.l1_result_hash); - write(buf, executed_callback.l1_results_tree_leaf_index); -}; - -template std::ostream& operator<<(std::ostream& os, ExecutedCallback const& executed_callback) -{ - return os << "l1_result_hash: " << executed_callback.l1_result_hash << "\n" - << "l1_results_tree_leaf_index: " << executed_callback.l1_results_tree_leaf_index << "\n"; -} - -} // namespace aztec3::circuits::abis \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/abis/function_signature.hpp b/circuits/src/aztec3/circuits/abis/function_signature.hpp index dad71107ed8..7a2a7e94dc2 100644 --- a/circuits/src/aztec3/circuits/abis/function_signature.hpp +++ b/circuits/src/aztec3/circuits/abis/function_signature.hpp @@ -1,10 +1,10 @@ #pragma once +#include +#include #include -#include #include #include -#include -#include +#include namespace aztec3::circuits::abis { @@ -14,14 +14,12 @@ using plonk::stdlib::types::NativeTypes; using std::is_same; template struct FunctionSignature { - typedef typename NCT::address address; + // typedef typename NCT::address address; typedef typename NCT::uint32 uint32; typedef typename NCT::boolean boolean; typedef typename NCT::grumpkin_point grumpkin_point; typedef typename NCT::fr fr; - // address contract_address; // TODO: remove contract_address from function_signature? The other stuff is all known - // before deployment. uint32 vk_index; boolean is_private = false; boolean is_constructor = false; @@ -38,7 +36,6 @@ template struct FunctionSignature { auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; FunctionSignature> function_signature = { - // to_ct(contract_address), to_ct(vk_index), to_ct(is_private), to_ct(is_constructor), @@ -51,7 +48,6 @@ template struct FunctionSignature { { static_assert(!(std::is_same::value)); - // contract_address.to_field().set_public(); fr(vk_index).set_public(); fr(is_private).set_public(); fr(is_constructor).set_public(); @@ -60,7 +56,6 @@ template struct FunctionSignature { fr hash() const { std::vector inputs = { - // contract_address.to_field(), fr(vk_index), fr(is_private), fr(is_constructor), @@ -74,7 +69,6 @@ template void read(uint8_t const*& it, FunctionSignature& fu { using serialize::read; - // read(it, function_signature.contract_address); read(it, function_signature.vk_index); read(it, function_signature.is_private); read(it, function_signature.is_constructor); @@ -84,7 +78,6 @@ template void write(std::vector& buf, FunctionSignature< { using serialize::write; - // write(buf, function_signature.contract_address); write(buf, function_signature.vk_index); write(buf, function_signature.is_private); write(buf, function_signature.is_constructor); diff --git a/circuits/src/aztec3/circuits/abis/index.hpp b/circuits/src/aztec3/circuits/abis/index.hpp index 652cf95ae00..8ffe84571a4 100644 --- a/circuits/src/aztec3/circuits/abis/index.hpp +++ b/circuits/src/aztec3/circuits/abis/index.hpp @@ -1,8 +1,6 @@ #include "call_context.hpp" #include "call_stack_item.hpp" -#include "callback_stack_item.hpp" #include "contract_deployment_call_public_inputs.hpp" -#include "executed_callback.hpp" #include "function_signature.hpp" #include "private_circuit_public_inputs.hpp" #include "private_circuit_public_inputs.hpp" diff --git a/circuits/src/aztec3/circuits/abis/optionally_revealed_data.hpp b/circuits/src/aztec3/circuits/abis/optionally_revealed_data.hpp index be6ccb2c76c..79c36b86989 100644 --- a/circuits/src/aztec3/circuits/abis/optionally_revealed_data.hpp +++ b/circuits/src/aztec3/circuits/abis/optionally_revealed_data.hpp @@ -1,10 +1,9 @@ #pragma once +#include "function_signature.hpp" #include #include #include #include -#include "function_signature.hpp" - namespace aztec3::circuits::abis { using plonk::stdlib::witness_t; @@ -17,7 +16,7 @@ template struct OptionallyRevealedData { fr call_stack_item_hash; FunctionSignature function_signature; - std::array emitted_public_inputs; + std::array emitted_events; fr vk_hash; fr portal_contract_address; // an ETH address boolean pay_fee_from_l1; @@ -35,7 +34,7 @@ template struct OptionallyRevealedData { OptionallyRevealedData> data = { to_ct(call_stack_item_hash), function_signature.to_circuit_type(composer), - to_ct(emitted_public_inputs), to_ct(vk_hash), + to_ct(emitted_events), to_ct(vk_hash), to_ct(portal_contract_address), to_ct(pay_fee_from_l1), to_ct(pay_fee_from_public_l2), to_ct(called_from_l1), to_ct(called_from_public_l2), @@ -50,7 +49,7 @@ template struct OptionallyRevealedData { call_stack_item_hash.set_public(); function_signature.set_public(); - set_array_public(emitted_public_inputs); + set_array_public(emitted_events); vk_hash.set_public(); portal_contract_address.set_public(); fr(pay_fee_from_l1).set_public(); diff --git a/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp b/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp index 94ec221c606..4680a09e58f 100644 --- a/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp +++ b/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp @@ -1,16 +1,16 @@ #pragma once -// #include + +#include "call_context.hpp" +#include "../../constants.hpp" + #include +#include +#include #include -#include #include #include -#include "../../constants.hpp" -#include "call_context.hpp" -#include "executed_callback.hpp" -#include "callback_stack_item.hpp" -#include -#include +#include + namespace aztec3::circuits::abis { using plonk::stdlib::witness_t; @@ -27,9 +27,7 @@ template class PrivateCircuitPublicInputs { std::array custom_inputs; std::array custom_outputs; - std::array emitted_public_inputs; - - ExecutedCallback executed_callback; + std::array emitted_events; std::array output_commitments; std::array input_nullifiers; @@ -38,9 +36,10 @@ template class PrivateCircuitPublicInputs { std::array public_call_stack; std::array contract_deployment_call_stack; std::array partial_l1_call_stack; - std::array, CALLBACK_STACK_LENGTH> callback_stack; fr old_private_data_tree_root; + fr old_nullifier_tree_root; + fr old_contract_tree_root; template PrivateCircuitPublicInputs> to_circuit_type(Composer& composer) const @@ -57,9 +56,7 @@ template class PrivateCircuitPublicInputs { to_ct(custom_inputs), to_ct(custom_outputs), - to_ct(emitted_public_inputs), - - to_circuit_type(executed_callback), + to_ct(emitted_events), to_ct(output_commitments), to_ct(input_nullifiers), @@ -68,9 +65,10 @@ template class PrivateCircuitPublicInputs { to_ct(public_call_stack), to_ct(contract_deployment_call_stack), to_ct(partial_l1_call_stack), - map(callback_stack, to_circuit_type), to_ct(old_private_data_tree_root), + to_ct(old_nullifier_tree_root), + to_ct(old_contract_tree_root), }; return pis; @@ -78,7 +76,7 @@ template class PrivateCircuitPublicInputs { fr hash() const { - auto to_hashes = [](const T& e) { return e.hash(); }; + // auto to_hashes = [](const T& e) { return e.hash(); }; std::vector inputs; @@ -87,9 +85,7 @@ template class PrivateCircuitPublicInputs { spread_arr_into_vec(custom_inputs, inputs); spread_arr_into_vec(custom_outputs, inputs); - spread_arr_into_vec(emitted_public_inputs, inputs); - - inputs.push_back(executed_callback.hash()); + spread_arr_into_vec(emitted_events, inputs); spread_arr_into_vec(output_commitments, inputs); spread_arr_into_vec(input_nullifiers, inputs); @@ -98,9 +94,10 @@ template class PrivateCircuitPublicInputs { spread_arr_into_vec(public_call_stack, inputs); spread_arr_into_vec(contract_deployment_call_stack, inputs); spread_arr_into_vec(partial_l1_call_stack, inputs); - spread_arr_into_vec(map(callback_stack, to_hashes), inputs); inputs.push_back(old_private_data_tree_root); + inputs.push_back(old_nullifier_tree_root); + inputs.push_back(old_contract_tree_root); return NCT::compress(inputs, GeneratorIndex::PRIVATE_CIRCUIT_PUBLIC_INPUTS); } @@ -128,9 +125,7 @@ template class OptionalPrivateCircuitPublicInputs { std::array custom_inputs; std::array custom_outputs; - std::array emitted_public_inputs; - - std::optional> executed_callback; + std::array emitted_events; std::array output_commitments; std::array input_nullifiers; @@ -139,9 +134,10 @@ template class OptionalPrivateCircuitPublicInputs { std::array public_call_stack; std::array contract_deployment_call_stack; std::array partial_l1_call_stack; - std::array>, CALLBACK_STACK_LENGTH> callback_stack; opt_fr old_private_data_tree_root; + opt_fr old_nullifier_tree_root; + opt_fr old_contract_tree_root; OptionalPrivateCircuitPublicInputs(){}; @@ -151,9 +147,7 @@ template class OptionalPrivateCircuitPublicInputs { std::array const& custom_inputs, std::array const& custom_outputs, - std::array const& emitted_public_inputs, - - std::optional> const& executed_callback, + std::array const& emitted_events, std::array const& output_commitments, std::array const& input_nullifiers, @@ -162,22 +156,23 @@ template class OptionalPrivateCircuitPublicInputs { std::array const& public_call_stack, std::array const& contract_deployment_call_stack, std::array const& partial_l1_call_stack, - std::array>, CALLBACK_STACK_LENGTH> const& callback_stack, - opt_fr const& old_private_data_tree_root) + opt_fr const& old_private_data_tree_root, + opt_fr const& old_nullifier_tree_root, + opt_fr const& old_contract_tree_root) : call_context(call_context) , custom_inputs(custom_inputs) , custom_outputs(custom_outputs) - , emitted_public_inputs(emitted_public_inputs) - , executed_callback(executed_callback) + , emitted_events(emitted_events) , output_commitments(output_commitments) , input_nullifiers(input_nullifiers) , private_call_stack(private_call_stack) , public_call_stack(public_call_stack) , contract_deployment_call_stack(contract_deployment_call_stack) , partial_l1_call_stack(partial_l1_call_stack) - , callback_stack(callback_stack) - , old_private_data_tree_root(old_private_data_tree_root){}; + , old_private_data_tree_root(old_private_data_tree_root) + , old_nullifier_tree_root(old_nullifier_tree_root) + , old_contract_tree_root(old_contract_tree_root){}; bool operator==(OptionalPrivateCircuitPublicInputs const&) const = default; @@ -191,9 +186,7 @@ template class OptionalPrivateCircuitPublicInputs { new_inputs.custom_inputs.fill(std::nullopt); new_inputs.custom_outputs.fill(std::nullopt); - new_inputs.emitted_public_inputs.fill(std::nullopt); - - new_inputs.executed_callback = std::nullopt; + new_inputs.emitted_events.fill(std::nullopt); new_inputs.output_commitments.fill(std::nullopt); new_inputs.input_nullifiers.fill(std::nullopt); @@ -202,9 +195,10 @@ template class OptionalPrivateCircuitPublicInputs { new_inputs.public_call_stack.fill(std::nullopt); new_inputs.contract_deployment_call_stack.fill(std::nullopt); new_inputs.partial_l1_call_stack.fill(std::nullopt); - new_inputs.callback_stack.fill(std::nullopt); new_inputs.old_private_data_tree_root = std::nullopt; + new_inputs.old_nullifier_tree_root = std::nullopt; + new_inputs.old_contract_tree_root = std::nullopt; return new_inputs; }; @@ -238,9 +232,7 @@ template class OptionalPrivateCircuitPublicInputs { make_unused_array_elements_zero(composer, custom_inputs); make_unused_array_elements_zero(composer, custom_outputs); - make_unused_array_elements_zero(composer, emitted_public_inputs); - - make_unused_element_zero(composer, executed_callback); + make_unused_array_elements_zero(composer, emitted_events); make_unused_array_elements_zero(composer, output_commitments); make_unused_array_elements_zero(composer, input_nullifiers); @@ -249,9 +241,10 @@ template class OptionalPrivateCircuitPublicInputs { make_unused_array_elements_zero(composer, public_call_stack); make_unused_array_elements_zero(composer, contract_deployment_call_stack); make_unused_array_elements_zero(composer, partial_l1_call_stack); - make_unused_array_elements_zero(composer, callback_stack); make_unused_element_zero(composer, old_private_data_tree_root); + make_unused_element_zero(composer, old_nullifier_tree_root); + make_unused_element_zero(composer, old_contract_tree_root); all_elements_populated = true; } @@ -269,9 +262,7 @@ template class OptionalPrivateCircuitPublicInputs { set_array_public(custom_inputs); set_array_public(custom_outputs); - set_array_public(emitted_public_inputs); - - (*executed_callback).set_public(); + set_array_public(emitted_events); set_array_public(output_commitments); set_array_public(input_nullifiers); @@ -280,9 +271,10 @@ template class OptionalPrivateCircuitPublicInputs { set_array_public(public_call_stack); set_array_public(contract_deployment_call_stack); set_array_public(partial_l1_call_stack); - set_array_public(callback_stack); (*old_private_data_tree_root).set_public(); + (*old_nullifier_tree_root).set_public(); + (*old_contract_tree_root).set_public(); } template @@ -302,9 +294,7 @@ template class OptionalPrivateCircuitPublicInputs { to_ct(custom_inputs), to_ct(custom_outputs), - to_ct(emitted_public_inputs), - - to_circuit_type(executed_callback), + to_ct(emitted_events), to_ct(output_commitments), to_ct(input_nullifiers), @@ -313,9 +303,10 @@ template class OptionalPrivateCircuitPublicInputs { to_ct(public_call_stack), to_ct(contract_deployment_call_stack), to_ct(partial_l1_call_stack), - map(callback_stack, to_circuit_type), to_ct(old_private_data_tree_root), + to_ct(old_nullifier_tree_root), + to_ct(old_contract_tree_root), }; return pis; @@ -336,9 +327,7 @@ template class OptionalPrivateCircuitPublicInputs { to_nt(custom_inputs), to_nt(custom_outputs), - to_nt(emitted_public_inputs), - - to_native_type(executed_callback), + to_nt(emitted_events), to_nt(output_commitments), to_nt(input_nullifiers), @@ -347,9 +336,10 @@ template class OptionalPrivateCircuitPublicInputs { to_nt(public_call_stack), to_nt(contract_deployment_call_stack), to_nt(partial_l1_call_stack), - map(callback_stack, to_native_type), to_nt(old_private_data_tree_root), + to_nt(old_nullifier_tree_root), + to_nt(old_contract_tree_root), }; return pis; @@ -357,12 +347,12 @@ template class OptionalPrivateCircuitPublicInputs { fr hash() const { - auto to_hashes = [](const std::optional& e) { - if (!e) { - throw_or_abort("Value is nullopt"); - } - return (*e).hash(); - }; + // auto to_hashes = [](const std::optional& e) { + // if (!e) { + // throw_or_abort("Value is nullopt"); + // } + // return (*e).hash(); + // }; std::vector inputs; @@ -371,9 +361,7 @@ template class OptionalPrivateCircuitPublicInputs { spread_arr_opt_into_vec(custom_inputs, inputs); spread_arr_opt_into_vec(custom_outputs, inputs); - spread_arr_opt_into_vec(emitted_public_inputs, inputs); - - inputs.push_back((*executed_callback).hash()); + spread_arr_opt_into_vec(emitted_events, inputs); spread_arr_opt_into_vec(output_commitments, inputs); spread_arr_opt_into_vec(input_nullifiers, inputs); @@ -382,9 +370,10 @@ template class OptionalPrivateCircuitPublicInputs { spread_arr_opt_into_vec(public_call_stack, inputs); spread_arr_opt_into_vec(contract_deployment_call_stack, inputs); spread_arr_opt_into_vec(partial_l1_call_stack, inputs); - spread_arr_into_vec(map(callback_stack, to_hashes), inputs); inputs.push_back(*old_private_data_tree_root); + inputs.push_back(*old_nullifier_tree_root); + inputs.push_back(*old_contract_tree_root); return NCT::compress(inputs, GeneratorIndex::PRIVATE_CIRCUIT_PUBLIC_INPUTS); } @@ -400,9 +389,7 @@ template class OptionalPrivateCircuitPublicInputs { .custom_inputs = map(custom_inputs, get_value), .custom_outputs = map(custom_outputs, get_value), - .emitted_public_inputs = map(emitted_public_inputs, get_value), - - .executed_callback = executed_callback.value(), + .emitted_events = map(emitted_events, get_value), .output_commitments = map(output_commitments, get_value), .input_nullifiers = map(input_nullifiers, get_value), @@ -411,9 +398,10 @@ template class OptionalPrivateCircuitPublicInputs { .public_call_stack = map(public_call_stack, get_value), .contract_deployment_call_stack = map(contract_deployment_call_stack, get_value), .partial_l1_call_stack = map(partial_l1_call_stack, get_value), - .callback_stack = map(callback_stack, get_value), .old_private_data_tree_root = old_private_data_tree_root.value(), + .old_nullifier_tree_root = old_nullifier_tree_root.value(), + .old_contract_tree_root = old_contract_tree_root.value(), }; } @@ -463,40 +451,19 @@ template class OptionalPrivateCircuitPublicInputs { } } - template - void make_unused_element_zero(Composer& composer, std::optional>>& element) + // ABIStruct is a template for any of the structs in the abis/ dir. E.g. ExecutedCallback, CallbackStackItem. + template class ABIStruct> + void make_unused_element_zero(Composer& composer, std::optional>>& element) { static_assert((std::is_same, NCT>::value)); if (!element) { - element = CallbackStackItem::empty().to_circuit_type( + element = ABIStruct::empty().to_circuit_type( composer); // convert the nullopt value to a circuit witness value of `0` (*element).template assert_is_zero(); } } - template - void make_unused_element_zero(Composer& composer, std::optional>>& element) - { - static_assert((std::is_same, NCT>::value)); - - if (!element) { - element = CallContext::empty().to_circuit_type(composer); - (*element).template assert_is_zero(); - } - } - - template - void make_unused_element_zero(Composer& composer, std::optional>>& element) - { - static_assert((std::is_same, NCT>::value)); - - if (!element) { - element = ExecutedCallback::empty().to_circuit_type(composer); - (*element).template assert_is_zero(); - } - } - // Make sure this is only called by functions which have implemented a "CT only" check. template void set_array_public(std::array, SIZE>& arr) { @@ -504,14 +471,6 @@ template class OptionalPrivateCircuitPublicInputs { fr(*e).set_public(); } } - - template - void set_array_public(std::array>>, SIZE>& arr) - { - for (auto& e : arr) { - (*e).template set_public(); - } - } }; // namespace aztec3::circuits::abis template @@ -523,16 +482,16 @@ void read(uint8_t const*& it, OptionalPrivateCircuitPublicInputs& private_c read(it, pis.call_context); read(it, pis.custom_inputs); read(it, pis.custom_outputs); - read(it, pis.emitted_public_inputs); - read(it, pis.executed_callback); + read(it, pis.emitted_events); read(it, pis.output_commitments); read(it, pis.input_nullifiers); read(it, pis.private_call_stack); read(it, pis.public_call_stack); read(it, pis.contract_deployment_call_stack); read(it, pis.partial_l1_call_stack); - read(it, pis.callback_stack); read(it, pis.old_private_data_tree_root); + read(it, pis.old_nullifier_tree_root); + read(it, pis.old_contract_tree_root); }; template @@ -545,16 +504,16 @@ void write(std::vector& buf, OptionalPrivateCircuitPublicInputs co write(buf, pis.call_context); write(buf, pis.custom_inputs); write(buf, pis.custom_outputs); - write(buf, pis.emitted_public_inputs); - write(buf, pis.executed_callback); + write(buf, pis.emitted_events); write(buf, pis.output_commitments); write(buf, pis.input_nullifiers); write(buf, pis.private_call_stack); write(buf, pis.public_call_stack); write(buf, pis.contract_deployment_call_stack); write(buf, pis.partial_l1_call_stack); - write(buf, pis.callback_stack); write(buf, pis.old_private_data_tree_root); + write(buf, pis.old_nullifier_tree_root); + write(buf, pis.old_contract_tree_root); }; template @@ -565,16 +524,16 @@ std::ostream& operator<<(std::ostream& os, OptionalPrivateCircuitPublicInputs #include #include #include #include -#include "../optionally_revealed_data.hpp" namespace aztec3::circuits::abis::private_kernel { @@ -18,15 +18,18 @@ template struct AccumulatedData { typedef typename NCT::AggregationObject AggregationObject; AggregationObject aggregation_object; + fr private_call_count; + + std::array output_commitments; + std::array input_nullifiers; + std::array private_call_stack; std::array public_call_stack; std::array contract_deployment_call_stack; std::array l1_call_stack; - std::array callback_stack; + std::array, KERNEL_OPTIONALLY_REVEALED_DATA_LENGTH> optionally_revealed_data; - std::array output_commitments; - std::array input_nullifiers; template AccumulatedData> to_circuit_type(Composer& composer) const { @@ -45,15 +48,18 @@ template struct AccumulatedData { aggregation_object.proof_witness_indices, aggregation_object.has_data, }, + to_ct(private_call_count), + + to_ct(output_commitments), + to_ct(input_nullifiers), + to_ct(private_call_stack), to_ct(public_call_stack), to_ct(contract_deployment_call_stack), to_ct(l1_call_stack), - to_ct(callback_stack), + map(optionally_revealed_data, to_circuit_type), - to_ct(output_commitments), - to_ct(input_nullifiers), }; return acc_data; @@ -64,15 +70,18 @@ template struct AccumulatedData { static_assert(!(std::is_same::value)); aggregation_object.add_proof_outputs_as_public_inputs(); + private_call_count.set_public(); + + set_array_public(output_commitments); + set_array_public(input_nullifiers); + set_array_public(private_call_stack); set_array_public(public_call_stack); set_array_public(contract_deployment_call_stack); set_array_public(l1_call_stack); - set_array_public(callback_stack); + set_array_public(optionally_revealed_data); - set_array_public(output_commitments); - set_array_public(input_nullifiers); } template void set_array_public(std::array& arr) diff --git a/circuits/src/aztec3/circuits/abis/private_kernel/call_context_reconciliation_data.hpp b/circuits/src/aztec3/circuits/abis/private_kernel/call_context_reconciliation_data.hpp new file mode 100644 index 00000000000..3ebf949b132 --- /dev/null +++ b/circuits/src/aztec3/circuits/abis/private_kernel/call_context_reconciliation_data.hpp @@ -0,0 +1,58 @@ +#pragma once + +#include "../call_context.hpp" + +#include +#include +#include +#include +#include + +namespace aztec3::circuits::abis::private_kernel { + +using plonk::stdlib::witness_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; +using std::is_same; + +template struct CallContextReconciliationData { + typedef typename NCT::fr fr; + + /** + * This class needs an explanation... + * + */ + std::array, PRIVATE_CALL_STACK_LENGTH> private_call_contexts; + std::array private_counterparts; + + std::array, PUBLIC_CALL_STACK_LENGTH> public_call_contexts; + std::array public_counterparts; + + // std::array contract_deployment_call_stack; + + std::array, PARTIAL_L1_CALL_STACK_LENGTH> l1_call_contexts; + std::array l1_counterparts; // TODO: this is probably wrong. + + template + CallContextReconciliationData> to_circuit_type(Composer& composer) const + { + static_assert((std::is_same::value)); + + // Capture the composer: + auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + auto to_circuit_type = [&](auto& e) { return e.to_circuit_type(composer); }; + + CallContextReconciliationData> data = { + + map(private_call_contexts, to_circuit_type), to_ct(private_counterparts), + + map(public_call_contexts, to_circuit_type), to_ct(public_counterparts), + + map(l1_call_contexts, to_circuit_type), to_ct(l1_counterparts), + }; + + return data; + }; +}; + +} // namespace aztec3::circuits::abis::private_kernel \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/abis/private_kernel/constant_data.hpp b/circuits/src/aztec3/circuits/abis/private_kernel/constant_data.hpp index 6ccceb19971..d627f1f370a 100644 --- a/circuits/src/aztec3/circuits/abis/private_kernel/constant_data.hpp +++ b/circuits/src/aztec3/circuits/abis/private_kernel/constant_data.hpp @@ -1,11 +1,12 @@ #pragma once +// #include "globals.hpp" +#include "old_tree_roots.hpp" +#include "../tx_context.hpp" + #include #include #include #include -#include "../executed_callback.hpp" -#include "old_tree_roots.hpp" -#include "globals.hpp" namespace aztec3::circuits::abis::private_kernel { @@ -19,24 +20,19 @@ template struct ConstantData { typedef typename NCT::boolean boolean; OldTreeRoots old_tree_roots; - boolean is_constructor_recursion = false; - boolean is_callback_recursion = false; - ExecutedCallback executed_callback; - Globals globals; + TxContext tx_context; + // Globals globals; template ConstantData> to_circuit_type(Composer& composer) const { static_assert((std::is_same::value)); // Capture the composer: - auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + // auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; ConstantData> constant_data = { old_tree_roots.to_circuit_type(composer), - to_ct(is_constructor_recursion), - to_ct(is_callback_recursion), - executed_callback.to_circuit_type(composer), - globals.to_circuit_type(composer), + tx_context.to_circuit_type(composer), }; return constant_data; @@ -47,10 +43,7 @@ template struct ConstantData { static_assert(!(std::is_same::value)); old_tree_roots.set_public(); - fr(is_constructor_recursion).set_public(); - fr(is_callback_recursion).set_public(); - executed_callback.set_public(); - globals.set_public(); + tx_context.set_public(); } // template void set_private_data_tree_root(typename CircuitTypes::fr const& value) diff --git a/circuits/src/aztec3/circuits/abis/private_kernel/old_tree_roots.hpp b/circuits/src/aztec3/circuits/abis/private_kernel/old_tree_roots.hpp index a1eae426b31..a71fbeecbc2 100644 --- a/circuits/src/aztec3/circuits/abis/private_kernel/old_tree_roots.hpp +++ b/circuits/src/aztec3/circuits/abis/private_kernel/old_tree_roots.hpp @@ -15,8 +15,8 @@ template struct OldTreeRoots { typedef typename NCT::fr fr; fr private_data_tree_root; + fr nullifier_tree_root; fr contract_tree_root; - fr l1_results_tree_root; fr private_kernel_vk_tree_root; // TODO: future enhancement template OldTreeRoots> to_circuit_type(Composer& composer) const @@ -28,8 +28,8 @@ template struct OldTreeRoots { OldTreeRoots> data = { to_ct(private_data_tree_root), + to_ct(nullifier_tree_root), to_ct(contract_tree_root), - to_ct(l1_results_tree_root), to_ct(private_kernel_vk_tree_root), }; @@ -41,8 +41,8 @@ template struct OldTreeRoots { static_assert(!(std::is_same::value)); private_data_tree_root.set_public(); + nullifier_tree_root.set_public(); contract_tree_root.set_public(); - l1_results_tree_root.set_public(); private_kernel_vk_tree_root.set_public(); } }; diff --git a/circuits/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp b/circuits/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp index f56dceb5b52..32648930e4a 100644 --- a/circuits/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp +++ b/circuits/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp @@ -1,9 +1,9 @@ #pragma once +#include "public_inputs.hpp" #include #include #include #include -#include "public_inputs.hpp" namespace aztec3::circuits::abis::private_kernel { @@ -13,10 +13,6 @@ using plonk::stdlib::types::NativeTypes; using std::is_same; template struct PreviousKernelData { - typedef typename NCT::address address; - typedef typename NCT::uint32 uint32; - typedef typename NCT::boolean boolean; - typedef typename NCT::grumpkin_point grumpkin_point; typedef typename NCT::fr fr; typedef typename NCT::VK VK; diff --git a/circuits/src/aztec3/circuits/abis/private_kernel/private_call_data.hpp b/circuits/src/aztec3/circuits/abis/private_kernel/private_call_data.hpp index f8489903d82..443e9222d16 100644 --- a/circuits/src/aztec3/circuits/abis/private_kernel/private_call_data.hpp +++ b/circuits/src/aztec3/circuits/abis/private_kernel/private_call_data.hpp @@ -1,9 +1,12 @@ #pragma once + +#include "call_context_reconciliation_data.hpp" +#include "../call_stack_item.hpp" + #include #include #include #include -#include "../call_stack_item.hpp" namespace aztec3::circuits::abis::private_kernel { @@ -14,20 +17,21 @@ using std::is_same; template struct PrivateCallData { typedef typename NCT::address address; - typedef typename NCT::uint32 uint32; - typedef typename NCT::boolean boolean; - typedef typename NCT::grumpkin_point grumpkin_point; typedef typename NCT::fr fr; typedef typename NCT::VK VK; CallStackItem call_stack_item; + CallContextReconciliationData call_context_reconciliation_data; + NativeTypes::Proof proof; // TODO: how to express proof as native/circuit type when it gets used as a buffer? std::shared_ptr vk; std::array vk_path; - fr portal_contract_address; // an ETH address + + fr contract_tree_root; fr contract_leaf_index; std::array contract_path; - // PrivatelyExecutedCallback???? + + fr portal_contract_address; // an ETH address // WARNING: the `proof` does NOT get converted! template PrivateCallData> to_circuit_type(Composer& composer) const @@ -40,12 +44,18 @@ template struct PrivateCallData { PrivateCallData> data = { call_stack_item.to_circuit_type(composer), - proof, // Notice: not converted! Stays as native. + call_context_reconciliation_data.to_circuit_type(composer), + + proof, // Notice: not converted! Stays as native. This is because of how the verify_proof function currently + // works. CT::VK::from_witness(&composer, vk), to_ct(vk_path), - to_ct(portal_contract_address), + + to_ct(contract_tree_root), to_ct(contract_leaf_index), to_ct(contract_path), + + to_ct(portal_contract_address), }; return data; diff --git a/circuits/src/aztec3/circuits/abis/private_kernel/private_inputs.hpp b/circuits/src/aztec3/circuits/abis/private_kernel/private_inputs.hpp index 0f432167631..b7eff761d6d 100644 --- a/circuits/src/aztec3/circuits/abis/private_kernel/private_inputs.hpp +++ b/circuits/src/aztec3/circuits/abis/private_kernel/private_inputs.hpp @@ -1,11 +1,14 @@ #pragma once + +#include "accumulated_data.hpp" +#include "previous_kernel_data.hpp" +#include "private_call_data.hpp" +#include "../signed_tx_object.hpp" + #include #include #include #include -#include "accumulated_data.hpp" -#include "previous_kernel_data.hpp" -#include "private_call_data.hpp" namespace aztec3::circuits::abis::private_kernel { @@ -18,8 +21,7 @@ template struct PrivateInputs { typedef typename NCT::fr fr; // typedef typename NCT::signature Signature; - // Signature signature; - // AccumulatedData start; + SignedTxObject signed_tx_object; PreviousKernelData previous_kernel; PrivateCallData private_call; @@ -29,7 +31,7 @@ template struct PrivateInputs { PrivateInputs> private_inputs = { // plonk::stdlib::schnorr::convert_signature(&composer, signature), - // start.to_circuit_type(composer), + signed_tx_object.to_circuit_type(composer), previous_kernel.to_circuit_type(composer), private_call.to_circuit_type(composer), }; diff --git a/circuits/src/aztec3/circuits/abis/private_kernel/public_inputs.hpp b/circuits/src/aztec3/circuits/abis/private_kernel/public_inputs.hpp index d6295224ca6..09d7a7422dc 100644 --- a/circuits/src/aztec3/circuits/abis/private_kernel/public_inputs.hpp +++ b/circuits/src/aztec3/circuits/abis/private_kernel/public_inputs.hpp @@ -1,10 +1,10 @@ #pragma once +#include "accumulated_data.hpp" +#include "constant_data.hpp" #include #include #include #include -#include "accumulated_data.hpp" -#include "constant_data.hpp" namespace aztec3::circuits::abis::private_kernel { @@ -19,6 +19,7 @@ template struct PublicInputs { AccumulatedData end; ConstantData constants; + boolean is_private = true; // TODO: might need to instantiate from witness! boolean is_public = false; boolean is_contract_deployment = false; @@ -31,7 +32,11 @@ template struct PublicInputs { auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; PublicInputs> private_inputs = { - end.to_circuit_type(composer), constants.to_circuit_type(composer), to_ct(is_private), to_ct(is_public), + end.to_circuit_type(composer), + constants.to_circuit_type(composer), + + to_ct(is_private), + to_ct(is_public), to_ct(is_contract_deployment), }; diff --git a/circuits/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp b/circuits/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp index c013a27c611..590b6dc1db9 100644 --- a/circuits/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp +++ b/circuits/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp @@ -1,14 +1,14 @@ #pragma once -// #include + +#include "call_context.hpp" +#include "state_transition.hpp" +#include "state_read.hpp" +#include "../../constants.hpp" + +#include #include #include #include -#include -#include "../../constants.hpp" -#include "state_transition.hpp" -#include "state_read.hpp" -// #include "./executed_callback.hpp" -// #include "./callback_stack_item.hpp" namespace aztec3::circuits::abis { @@ -21,15 +21,12 @@ template struct PublicCircuitPublicInputs { typedef typename NCT::boolean boolean; typedef typename NCT::address address; - // address msg_sender; // TODO! + CallContext call_context; std::array custom_inputs; std::array custom_outputs; - std::array emitted_public_inputs; - std::array emitted_outputs; - - ExecutedCallback executed_callback; + std::array emitted_events; std::array, STATE_TRANSITIONS_LENGTH> state_transitions; std::array, STATE_READS_LENGTH> state_reads; @@ -37,42 +34,36 @@ template struct PublicCircuitPublicInputs { std::array public_call_stack; std::array contract_deployment_call_stack; std::array partial_l1_call_stack; - std::array, CALLBACK_STACK_LENGTH> callback_stack; fr old_private_data_tree_root; - address prover_address = 0; + address prover_address; - boolean is_fee_payment = false; - boolean pay_fee_from_l1 = false; - boolean called_from_l1 = false; + // bool operator==(PublicCircuitPublicInputs const&) const = default; - bool operator==(PublicCircuitPublicInputs const&) const = default; + // static PublicCircuitPublicInputs empty() + // { + // PublicCircuitPublicInputs pis = { + // std::array::fill(0), + // std::array::fill(0), - static PublicCircuitPublicInputs empty() - { - PublicCircuitPublicInputs pis = { - std::array::fill(0), - std::array::fill(0), + // std::array::fill(0), - std::array::fill(0), - std::array::fill(0), + // std::array, STATE_TRANSITIONS_LENGTH>::fill(StateTransition::empty()), + // std::array, STATE_READS_LENGTH>::fill(StateRead::empty()), - ExecutedCallback::empty(), + // std::array::fill(0), - std::array, STATE_TRANSITIONS_LENGTH>::fill(StateTransition::empty()), - std::array, STATE_READS_LENGTH>::fill(StateRead::empty()), + // std::array::fill(0), + // std::array::fill(0), - std::array::fill(0), + // .old_private_data_tree_root = 0, - std::array::fill(0), - std::array::fill(0), - std::array, CALLBACK_STACK_LENGTH>::fill(CallbackStackItem::empty()), + // .prover_address = 0, + // }; - .old_private_data_tree_root = 0, - }; - return pis; - }; + // return pis; + // }; template PublicCircuitPublicInputs> to_circuit_type(Composer& composer) const @@ -84,12 +75,12 @@ template struct PublicCircuitPublicInputs { auto to_circuit_type = [&](auto& e) { return e.to_circuit_type(composer); }; PublicCircuitPublicInputs> pis = { + to_circuit_type(call_context), + .custom_inputs = to_ct(custom_inputs), .custom_outputs = to_ct(custom_outputs), - .emitted_public_inputs = to_ct(emitted_public_inputs), - .emitted_outputs = to_ct(emitted_outputs), - .executed_callback = to_circuit_type(executed_callback), + .emitted_events = to_ct(emitted_events), .state_transitions = map(state_transitions, to_circuit_type), .state_reads = map(state_reads, to_circuit_type), @@ -97,18 +88,48 @@ template struct PublicCircuitPublicInputs { .public_call_stack = to_ct(public_call_stack), .contract_deployment_call_stack = to_ct(contract_deployment_call_stack), .partial_l1_call_stack = to_ct(partial_l1_call_stack), - .callback_stack = map(callback_stack, to_circuit_type), - .prover_address = to_ct(prover_address), + .old_private_data_tree_root = to_ct(old_private_data_tree_root), - .is_fee_payment = to_ct(is_fee_payment), - .pay_fee_from_l1 = to_ct(pay_fee_from_l1), - .called_from_l1 = to_ct(called_from_l1), + .prover_address = to_ct(prover_address), }; return pis; }; -}; + + fr hash() const + { + auto to_hashes = [](const T& e) { return e.hash(); }; + + std::vector inputs; + + // NOTE: we omit the call_context from this hash function, and instead hash it within CallStackItem, for + // efficiency, so that fewer hashes are needed to 'unwrap' the call_context in the kernel circuit. + // inputs.push_back(call_context.hash()); + + spread_arr_into_vec(custom_inputs, inputs); + spread_arr_into_vec(custom_outputs, inputs); + + spread_arr_into_vec(emitted_events, inputs); + + spread_arr_into_vec(map(state_transitions, to_hashes), inputs); + spread_arr_into_vec(map(state_reads, to_hashes), inputs); + + spread_arr_into_vec(public_call_stack, inputs); + spread_arr_into_vec(contract_deployment_call_stack, inputs); + spread_arr_into_vec(partial_l1_call_stack, inputs); + + inputs.push_back(old_private_data_tree_root); + + return NCT::compress(inputs, GeneratorIndex::PRIVATE_CIRCUIT_PUBLIC_INPUTS); + } + + template void spread_arr_into_vec(std::array const& arr, std::vector& vec) const + { + const auto arr_size = sizeof(arr) / sizeof(fr); + vec.insert(vec.end(), &arr[0], &arr[0] + arr_size); + } +}; // namespace aztec3::circuits::abis template void read(uint8_t const*& it, PublicCircuitPublicInputs& private_circuit_public_inputs) { @@ -117,19 +138,19 @@ template void read(uint8_t const*& it, PublicCircuitPublicInputs< PublicCircuitPublicInputs& pis = private_circuit_public_inputs; read(it, pis.custom_inputs); read(it, pis.custom_outputs); - read(it, pis.emitted_public_inputs); + read(it, pis.emitted_events); read(it, pis.emitted_ouputs); - read(it, pis.executed_callback); + read(it, pis.state_transitions); read(it, pis.state_reads); + read(it, pis.public_call_stack); read(it, pis.contract_deployment_call_stack); read(it, pis.partial_l1_call_stack); - read(it, pis.callback_stack); + read(it, pis.old_private_data_tree_root); - read(it, pis.is_fee_payment); - read(it, pis.pay_fee_from_l1); - read(it, pis.called_from_l1); + + read(it, pis.prover_address); }; template @@ -141,19 +162,19 @@ void write(std::vector& buf, PublicCircuitPublicInputs const& priv write(buf, pis.custom_inputs); write(buf, pis.custom_outputs); - write(buf, pis.emitted_public_inputs); + write(buf, pis.emitted_events); write(buf, pis.emitted_ouputs); - write(buf, pis.executed_callback); + write(buf, pis.state_transitions); write(buf, pis.state_reads); + write(buf, pis.public_call_stack); write(buf, pis.contract_deployment_call_stack); write(buf, pis.partial_l1_call_stack); - write(buf, pis.callback_stack); + write(buf, pis.old_private_data_tree_root); - write(buf, pis.is_fee_payment); - write(buf, pis.pay_fee_from_l1); - write(buf, pis.called_from_l1); + + write(buf, pis.prover_address); }; template @@ -163,19 +184,18 @@ std::ostream& operator<<(std::ostream& os, PublicCircuitPublicInputs const& PublicCircuitPublicInputs const& pis = private_circuit_public_inputs; return os << "custom_inputs: " << pis.custom_inputs << "\n" << "custom_outputs: " << pis.custom_outputs << "\n" - << "emitted_public_inputs: " << pis.emitted_public_inputs << "\n" - << "emitted_outputs: " << pis.emitted_outputs << "\n" - << "executed_callback: " << pis.executed_callback << "\n" + << "emitted_events: " << pis.emitted_events << "\n" + << "state_transitions: " << pis.state_transitions << "\n" << "state_reads: " << pis.state_reads << "\n" + << "public_call_stack: " << pis.public_call_stack << "\n" << "contract_deployment_call_stack: " << pis.contract_deployment_call_stack << "\n" << "partial_l1_call_stack: " << pis.partial_l1_call_stack << "\n" - << "callback_stack: " << pis.callback_stack << "\n" + << "old_private_data_tree_root: " << pis.old_private_data_tree_root << "\n" - << "is_fee_payment: " << pis.is_fee_payment << "\n" - << "pay_fee_from_l1: " << pis.pay_fee_from_l1 << "\n" - << "called_from_l1: " << pis.called_from_l1 << "\n"; + + << "prover_address: " << pis.prover_address << "\n"; } } // namespace aztec3::circuits::abis \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/abis/signed_tx_object.hpp b/circuits/src/aztec3/circuits/abis/signed_tx_object.hpp new file mode 100644 index 00000000000..2c7047a7d8f --- /dev/null +++ b/circuits/src/aztec3/circuits/abis/signed_tx_object.hpp @@ -0,0 +1,55 @@ +#pragma once + +#include "tx_object.hpp" + +#include +#include +#include +#include + +namespace aztec3::circuits::abis { + +using plonk::stdlib::witness_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; + +template struct SignedTxObject { + TxObject tx_object; + // Signature signature; // TODO: import some kind of signature + + template SignedTxObject> to_circuit_type(Composer& composer) const + { + static_assert((std::is_same::value)); + + // Capture the composer: + // auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + auto to_circuit_type = [&](auto& e) { return e.to_circuit_type(composer); }; + + SignedTxObject> signed_tx_object = { + to_circuit_type(tx_object), + }; + + return signed_tx_object; + }; +}; + +template void read(uint8_t const*& it, SignedTxObject& signed_tx_object) +{ + using serialize::read; + + read(it, signed_tx_object.tx_object); +}; + +template void write(std::vector& buf, SignedTxObject const& signed_tx_object) +{ + using serialize::write; + + write(buf, signed_tx_object.tx_object); +}; + +template std::ostream& operator<<(std::ostream& os, SignedTxObject const& signed_tx_object) +{ + return os << "tx_object: " << signed_tx_object.tx_object << "\n"; +} + +} // namespace aztec3::circuits::abis \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/abis/state_read.hpp b/circuits/src/aztec3/circuits/abis/state_read.hpp index fcb85aaf3de..2c7167ab540 100644 --- a/circuits/src/aztec3/circuits/abis/state_read.hpp +++ b/circuits/src/aztec3/circuits/abis/state_read.hpp @@ -34,6 +34,16 @@ template struct StateRead { return state_read; }; + + fr hash() const + { + std::vector inputs = { + storage_slot, + current_value, + }; + + return NCT::compress(inputs, GeneratorIndex::STATE_READ); + } }; template void read(uint8_t const*& it, StateRead& state_read) diff --git a/circuits/src/aztec3/circuits/abis/state_transition.hpp b/circuits/src/aztec3/circuits/abis/state_transition.hpp index 58f91d89a54..ecafc975754 100644 --- a/circuits/src/aztec3/circuits/abis/state_transition.hpp +++ b/circuits/src/aztec3/circuits/abis/state_transition.hpp @@ -36,6 +36,17 @@ template struct StateTransition { return state_transition; }; + + fr hash() const + { + std::vector inputs = { + storage_slot, + old_value, + new_value, + }; + + return NCT::compress(inputs, GeneratorIndex::STATE_TRANSITION); + } }; template void read(uint8_t const*& it, StateTransition& state_transition) diff --git a/circuits/src/aztec3/circuits/abis/tx_context.hpp b/circuits/src/aztec3/circuits/abis/tx_context.hpp new file mode 100644 index 00000000000..aad6ae396d6 --- /dev/null +++ b/circuits/src/aztec3/circuits/abis/tx_context.hpp @@ -0,0 +1,85 @@ +#pragma once +#include "function_signature.hpp" +#include +#include +#include +#include +#include +#include + +namespace aztec3::circuits::abis { + +using plonk::stdlib::witness_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; + +template struct TxContext { + typedef typename NCT::address address; + // typedef typename NCT::grumpkin_point grumpkin_point; + typedef typename NCT::fr fr; + typedef typename NCT::boolean boolean; + + boolean called_from_l1; + boolean called_from_public_l2; + boolean is_fee_payment_tx; + // FeeData fee_data; + fr reference_block_num; + + template TxContext> to_circuit_type(Composer& composer) const + { + static_assert((std::is_same::value)); + + // Capture the composer: + auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + // auto to_circuit_type = [&](auto& e) { return e.to_circuit_type(composer); }; + + TxContext> tx_context = { + to_ct(called_from_l1), + to_ct(called_from_public_l2), + to_ct(is_fee_payment_tx), + to_ct(reference_block_num), + }; + + return tx_context; + }; + + void set_public() + { + static_assert(!(std::is_same::value)); + + fr(called_from_l1).set_public(); + fr(called_from_public_l2).set_public(); + fr(is_fee_payment_tx).set_public(); + reference_block_num.set_public(); + } +}; + +template void read(uint8_t const*& it, TxContext& tx_context) +{ + using serialize::read; + + read(it, tx_context.called_from_l1); + read(it, tx_context.called_from_public_l2); + read(it, tx_context.is_fee_payment_tx); + read(it, tx_context.reference_block_num); +}; + +template void write(std::vector& buf, TxContext const& tx_context) +{ + using serialize::write; + + write(buf, tx_context.called_from_l1); + write(buf, tx_context.called_from_public_l2); + write(buf, tx_context.is_fee_payment_tx); + write(buf, tx_context.reference_block_num); +}; + +template std::ostream& operator<<(std::ostream& os, TxContext const& tx_context) +{ + return os << "called_from_l1: " << tx_context.called_from_l1 << "\n" + << "called_from_public_l2: " << tx_context.called_from_public_l2 << "\n" + << "is_fee_payment_tx: " << tx_context.is_fee_payment_tx << "\n" + << "reference_block_num: " << tx_context.reference_block_num << "\n"; +} + +} // namespace aztec3::circuits::abis \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/abis/tx_object.hpp b/circuits/src/aztec3/circuits/abis/tx_object.hpp new file mode 100644 index 00000000000..51987aeb12d --- /dev/null +++ b/circuits/src/aztec3/circuits/abis/tx_object.hpp @@ -0,0 +1,84 @@ +#pragma once +#include "function_signature.hpp" +#include "tx_context.hpp" +#include +#include +#include +#include + +namespace aztec3::circuits::abis { + +using plonk::stdlib::witness_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; + +template struct TxObject { + typedef typename NCT::address address; + // typedef typename NCT::grumpkin_point grumpkin_point; + typedef typename NCT::fr fr; + typedef typename NCT::boolean boolean; + + address from; + address to; + FunctionSignature function_signature; + std::array custom_inputs; + fr nonce; + TxContext tx_context; + fr chain_id; + + template TxObject> to_circuit_type(Composer& composer) const + { + static_assert((std::is_same::value)); + + // Capture the composer: + auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + auto to_circuit_type = [&](auto& e) { return e.to_circuit_type(composer); }; + + TxObject> tx_object = { + to_ct(from), to_ct(to), to_circuit_type(function_signature), + to_ct(custom_inputs), to_ct(nonce), to_circuit_type(tx_context), + to_ct(chain_id), + }; + + return tx_object; + }; +}; + +template void read(uint8_t const*& it, TxObject& tx_object) +{ + using serialize::read; + + read(it, tx_object.from); + read(it, tx_object.to); + read(it, tx_object.function_signature); + read(it, tx_object.custom_inputs); + read(it, tx_object.nonce); + read(it, tx_object.tx_context); + read(it, tx_object.chain_id); +}; + +template void write(std::vector& buf, TxObject const& tx_object) +{ + using serialize::write; + + write(buf, tx_object.from); + write(buf, tx_object.to); + write(buf, tx_object.function_signature); + write(buf, tx_object.custom_inputs); + write(buf, tx_object.nonce); + write(buf, tx_object.tx_context); + write(buf, tx_object.chain_id); +}; + +template std::ostream& operator<<(std::ostream& os, TxObject const& tx_object) +{ + return os << "from: " << tx_object.from << "\n" + << "to: " << tx_object.to << "\n" + << "function_signature: " << tx_object.function_signature << "\n" + << "custom_inputs: " << tx_object.custom_inputs << "\n" + << "nonce: " << tx_object.nonce << "\n" + << "tx_context: " << tx_object.tx_context << "\n" + << "chain_id: " << tx_object.chain_id << "\n"; +} + +} // namespace aztec3::circuits::abis \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/contract.hpp b/circuits/src/aztec3/circuits/apps/contract.hpp index 09fcfd42a94..8acd32c39ff 100644 --- a/circuits/src/aztec3/circuits/apps/contract.hpp +++ b/circuits/src/aztec3/circuits/apps/contract.hpp @@ -1,12 +1,11 @@ #pragma once // #include // #include -#include #include "function_declaration.hpp" #include "private_state_var.hpp" #include "l1_function_interface.hpp" -// #include "oracle_wrapper.hpp" +#include namespace aztec3::circuits::apps { diff --git a/circuits/src/aztec3/circuits/apps/contract.tpp b/circuits/src/aztec3/circuits/apps/contract.tpp index fb7a1ab743e..9438c3757aa 100644 --- a/circuits/src/aztec3/circuits/apps/contract.tpp +++ b/circuits/src/aztec3/circuits/apps/contract.tpp @@ -1,12 +1,12 @@ #pragma once -#include -#include -#include -#include #include "function_execution_context.hpp" #include "private_state_var.hpp" #include "function_declaration.hpp" #include "l1_function_interface.hpp" +#include +#include +#include +#include namespace aztec3::circuits::apps { diff --git a/circuits/src/aztec3/circuits/apps/function_execution_context.hpp b/circuits/src/aztec3/circuits/apps/function_execution_context.hpp index 1b70b15649d..39956be6bcd 100644 --- a/circuits/src/aztec3/circuits/apps/function_execution_context.hpp +++ b/circuits/src/aztec3/circuits/apps/function_execution_context.hpp @@ -1,13 +1,17 @@ #pragma once -#include -#include -#include -#include -#include #include "contract.hpp" #include "nullifier_preimage.hpp" #include "oracle_wrapper.hpp" #include "private_state_note.hpp" + +#include +#include +#include + +#include + +#include + // #include "private_state_var.hpp" // #include "function_declaration.hpp" // #include "l1_function_interface.hpp" diff --git a/circuits/src/aztec3/circuits/apps/index.hpp b/circuits/src/aztec3/circuits/apps/index.hpp index 8b0ce1a872e..0ae8d268c7f 100644 --- a/circuits/src/aztec3/circuits/apps/index.hpp +++ b/circuits/src/aztec3/circuits/apps/index.hpp @@ -1,4 +1,3 @@ -#include "private_state_factory.hpp" #include "private_state_var.hpp" #include "private_state_note.hpp" #include "private_state_note_preimage.hpp" diff --git a/circuits/src/aztec3/circuits/apps/l1_call.hpp b/circuits/src/aztec3/circuits/apps/l1_call.hpp index 39d39c6c02a..37a66ad94f9 100644 --- a/circuits/src/aztec3/circuits/apps/l1_call.hpp +++ b/circuits/src/aztec3/circuits/apps/l1_call.hpp @@ -1,9 +1,9 @@ #pragma once +#include "l1_function_interface.hpp" #include #include #include #include -#include "l1_function_interface.hpp" // #include // #include diff --git a/circuits/src/aztec3/circuits/apps/l1_function_interface.hpp b/circuits/src/aztec3/circuits/apps/l1_function_interface.hpp index 2f84dac1b43..835ea3ecf0c 100644 --- a/circuits/src/aztec3/circuits/apps/l1_function_interface.hpp +++ b/circuits/src/aztec3/circuits/apps/l1_function_interface.hpp @@ -3,8 +3,6 @@ #include #include #include -#include "l1_promise.hpp" -#include "l1_result.hpp" namespace aztec3::circuits::apps { @@ -48,15 +46,10 @@ template class L1FunctionInterface { // , num_params(l1_function.num_params) // {} - std::pair, L1Result> call(std::vector args) + void call(std::vector args) { - if (args.size() != num_params) { - throw_or_abort("Incorrect number of args"); - } - - auto promise = L1Promise(*contract); - L1Result result; - return std::make_pair(promise, result); + // TODO: implement this function. + (void)args; // So the compiler doesn't complain about an unused var. } }; diff --git a/circuits/src/aztec3/circuits/apps/l1_promise.hpp b/circuits/src/aztec3/circuits/apps/l1_promise.hpp deleted file mode 100644 index 4f2e2d44ff2..00000000000 --- a/circuits/src/aztec3/circuits/apps/l1_promise.hpp +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include "l1_result.hpp" - -namespace aztec3::circuits::apps { - -using aztec3::circuits::abis::CallbackStackItem; -using plonk::stdlib::witness_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; - -template class Contract; - -template class L1Promise { - typedef CircuitTypes CT; - typedef typename CT::fr fr; - typedef typename CT::grumpkin_point grumpkin_point; - typedef typename CT::boolean boolean; - - public: - Contract& contract; - CallbackStackItem callback_stack_item; - - L1Promise(Contract& contract) - : contract(contract) - {} - - void on_success(std::string const& function_name, std::vector> const& args); - void on_failure(std::string const& function_name, std::vector const& args); -}; - -} // namespace aztec3::circuits::apps - -#include "l1_promise.tpp" \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/l1_promise.tpp b/circuits/src/aztec3/circuits/apps/l1_promise.tpp deleted file mode 100644 index 11bce93fcbc..00000000000 --- a/circuits/src/aztec3/circuits/apps/l1_promise.tpp +++ /dev/null @@ -1,84 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include "contract.hpp" -#include "l1_result.hpp" - -namespace aztec3::circuits::apps { - -using aztec3::circuits::abis::FunctionSignature; -using plonk::stdlib::witness_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; - -template -void L1Promise::on_success(std::string const& function_name, - std::vector> const& args) -{ - // construct success_callback_call_hash and success_result_arg_map_acc - - std::vector> arg_input_pairs; - - for (size_t i = 0; i < args.size(); ++i) { - if (std::holds_alternative(args[i])) { - const fr arg = std::get(args[i]); - arg_input_pairs.push_back(std::make_pair(arg, generator_index_t({ GeneratorIndex::CALL_ARGS, i }))); - } else { - // For L1ResultArgIndex types, we won't know the result's value until after the L1 tx, so we hash using a - // placeholder generator which represents a particular index of the result array: - const size_t& result_arg_index = std::get(args[i]); - arg_input_pairs.push_back( - std::make_pair(fr(1), generator_index_t({ GeneratorIndex::L1_RESULT_PLACEHOLDER, result_arg_index }))); - } - } - - // TODO: do this calc in the CallStackItem struct instead, once we know whether we can simply hash args instead of - // the whole set of public inputs. - - auto function_signature = contract.get_function_signature_by_name(function_name); - - fr function_signature_hash = function_signature.hash(); - fr arg_hash = CT::compress(arg_input_pairs); - - std::vector success_callback_call_hash_inputs = { - function_signature_hash, - arg_hash, - }; - - callback_stack_item.success_callback_call_hash = - CT::compress(success_callback_call_hash_inputs, GeneratorIndex::CALLBACK_STACK_ITEM); -}; - -template -void L1Promise::on_failure(std::string const& function_name, std::vector const& args) -{ - // construct failure_callback_call_hash - - std::vector> arg_input_pairs; - - for (size_t i = 0; i < args.size(); ++i) { - arg_input_pairs.push_back(std::make_pair(args[i], generator_index_t({ GeneratorIndex::CALL_ARGS, i }))); - } - - // TODO: do this calc in the CallStackItem struct instead, once we know whether we can simply hash args instead of - // the whole set of public inputs. - auto function_signature = contract.get_function_signature_by_name(function_name); - - fr function_signature_hash = function_signature.hash(); - fr arg_hash = CT::compress(arg_input_pairs); - - std::vector failure_callback_call_hash_inputs = { - function_signature_hash, - arg_hash, - }; - - callback_stack_item.failure_callback_call_hash = - CT::compress(failure_callback_call_hash_inputs, GeneratorIndex::CALLBACK_STACK_ITEM); -}; - -} // namespace aztec3::circuits::apps \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/l1_result.hpp b/circuits/src/aztec3/circuits/apps/l1_result.hpp deleted file mode 100644 index ec0fa140e13..00000000000 --- a/circuits/src/aztec3/circuits/apps/l1_result.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once -#include -#include -#include -#include - -namespace aztec3::circuits::apps { - -using plonk::stdlib::witness_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; - -// struct L1ResultArgIndex { -// size_t arg_index; -// }; - -/** - * This just allows some syntactic sugar when writing test circuits. - * This is really just something which returns the index you feed it via `[]`. - */ -class L1Result { - public: - L1Result() {} - - size_t operator[](size_t i) const { return i; } -}; - -} // namespace aztec3::circuits::apps \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/oracle_wrapper.hpp b/circuits/src/aztec3/circuits/apps/oracle_wrapper.hpp index cae7458892d..3132f5fba6d 100644 --- a/circuits/src/aztec3/circuits/apps/oracle_wrapper.hpp +++ b/circuits/src/aztec3/circuits/apps/oracle_wrapper.hpp @@ -1,10 +1,11 @@ #pragma once #include #include +#include + #include #include #include -#include namespace aztec3::circuits::apps { diff --git a/circuits/src/aztec3/circuits/apps/private_state.test.cpp b/circuits/src/aztec3/circuits/apps/private_state.test.cpp index c472f53b077..0fcde74de33 100644 --- a/circuits/src/aztec3/circuits/apps/private_state.test.cpp +++ b/circuits/src/aztec3/circuits/apps/private_state.test.cpp @@ -1,8 +1,9 @@ +#include "index.hpp" + #include #include #include // #include -#include "index.hpp" #include // #include // #include diff --git a/circuits/src/aztec3/circuits/apps/private_state_factory.hpp b/circuits/src/aztec3/circuits/apps/private_state_factory.hpp deleted file mode 100644 index fac2f8d561c..00000000000 --- a/circuits/src/aztec3/circuits/apps/private_state_factory.hpp +++ /dev/null @@ -1,33 +0,0 @@ -// #pragma once -// #include -// #include -// #include "nullifier_preimage.hpp" -// #include "private_state_note.hpp" -// #include "private_state_var.hpp" -// #include "oracle_wrapper.hpp" - -// namespace aztec3::circuits::apps { - -// // using plonk::stdlib::witness_t; -// using plonk::stdlib::types::CircuitTypes; -// using NT = plonk::stdlib::types::NativeTypes; - -// template class PrivateStateFactory { -// typedef CircuitTypes CT; -// typedef typename CT::fr fr; - -// public: -// Composer& composer; // TODO: can we remove this? -// OracleWrapperInterface& oracle; -// const std::string contract_name; -// fr private_state_counter = 0; - -// std::map> private_state_vars; -// // std::vector> new_private_state_notes; -// // std::vector new_commitments; -// // std::vector> new_nullifier_preimages; -// // std::vector new_nullifiers; - -// }; - -// } // namespace aztec3::circuits::apps \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/private_state_note.hpp b/circuits/src/aztec3/circuits/apps/private_state_note.hpp index f3b51e94c5f..10d846ec81f 100644 --- a/circuits/src/aztec3/circuits/apps/private_state_note.hpp +++ b/circuits/src/aztec3/circuits/apps/private_state_note.hpp @@ -1,7 +1,7 @@ #pragma once +#include "nullifier_preimage.hpp" #include #include -#include "nullifier_preimage.hpp" namespace aztec3::circuits::apps { diff --git a/circuits/src/aztec3/circuits/apps/private_state_note.tpp b/circuits/src/aztec3/circuits/apps/private_state_note.tpp index 697ce3b56cc..b8e297b0589 100644 --- a/circuits/src/aztec3/circuits/apps/private_state_note.tpp +++ b/circuits/src/aztec3/circuits/apps/private_state_note.tpp @@ -1,5 +1,10 @@ // TODO: remove unused inclusions // #include "private_state_note.hpp" +#include "oracle_wrapper.hpp" +#include "private_state_var.hpp" +#include "private_state_note_preimage.hpp" +#include "plonk/composer/turbo_composer.hpp" + #include #include #include @@ -7,10 +12,6 @@ #include #include #include -#include "oracle_wrapper.hpp" -#include "private_state_var.hpp" -#include "private_state_note_preimage.hpp" -#include "plonk/composer/turbo_composer.hpp" namespace aztec3::circuits::apps { diff --git a/circuits/src/aztec3/circuits/apps/private_state_var.hpp b/circuits/src/aztec3/circuits/apps/private_state_var.hpp index 71b4cddd2de..8bb1aa3b10b 100644 --- a/circuits/src/aztec3/circuits/apps/private_state_var.hpp +++ b/circuits/src/aztec3/circuits/apps/private_state_var.hpp @@ -1,11 +1,13 @@ #pragma once -#include -#include #include "private_state_note.hpp" #include "private_state_note_preimage.hpp" #include "private_state_operand.hpp" + #include +#include +#include + namespace aztec3::circuits::apps { using plonk::stdlib::types::CircuitTypes; diff --git a/circuits/src/aztec3/circuits/apps/private_state_var.tpp b/circuits/src/aztec3/circuits/apps/private_state_var.tpp index c63ac36772c..350742c6349 100644 --- a/circuits/src/aztec3/circuits/apps/private_state_var.tpp +++ b/circuits/src/aztec3/circuits/apps/private_state_var.tpp @@ -1,5 +1,11 @@ #pragma once // #include +#include "oracle_wrapper.hpp" +#include "private_state_note.hpp" +#include "private_state_note_preimage.hpp" +#include "private_state_operand.hpp" +#include "plonk/composer/turbo_composer.hpp" + #include #include #include @@ -7,11 +13,6 @@ #include #include #include -#include "oracle_wrapper.hpp" -#include "private_state_note.hpp" -#include "private_state_note_preimage.hpp" -#include "private_state_operand.hpp" -#include "plonk/composer/turbo_composer.hpp" namespace aztec3::circuits::apps { diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp index 97b60869d06..1befc032c25 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp @@ -59,7 +59,8 @@ TEST(escrow_tests, test_transfer) .msg_sender = msg_sender, .storage_contract_address = contract_address, .tx_origin = msg_sender, - .is_fee_payment = true, + .is_delegate_call = false, + .is_static_call = false, }; NativeOracle oracle = NativeOracle(db, call_context, msg_sender_private_key); @@ -100,7 +101,8 @@ TEST(escrow_tests, test_withdraw) .msg_sender = msg_sender, .storage_contract_address = contract_address, .tx_origin = msg_sender, - .is_fee_payment = true, + .is_delegate_call = false, + .is_static_call = false, }; NativeOracle oracle = NativeOracle(db, call_context, msg_sender_private_key); diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp index 84eb7457a65..b81684f785a 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp @@ -1,8 +1,9 @@ #pragma once +#include "init.hpp" + #include #include #include -#include "init.hpp" namespace aztec3::circuits::apps::test_apps::escrow { diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp index 44deb65417a..b0f0034532b 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp @@ -1,7 +1,9 @@ #include "deposit.hpp" + +#include "contract.hpp" + #include #include -#include "contract.hpp" namespace aztec3::circuits::apps::test_apps::escrow { diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.hpp index ca23a1115c7..a4d066b12c3 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.hpp @@ -1,7 +1,9 @@ #pragma once + +#include "init.hpp" + #include #include -#include "init.hpp" namespace aztec3::circuits::apps::test_apps::escrow { diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/index.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/index.hpp index 45fe9be7192..4cf1909486f 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/index.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/index.hpp @@ -2,5 +2,4 @@ #include "contract.hpp" #include "deposit.hpp" #include "transfer.hpp" -#include "withdraw.hpp" -#include "withdraw_failure_callback.hpp" \ No newline at end of file +#include "withdraw.hpp" \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/init.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/init.hpp index b10e631df8d..082e19395ec 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/init.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/init.hpp @@ -1,11 +1,13 @@ #pragma once + +#include +#include +#include + #include #include #include #include -#include -#include -#include namespace aztec3::circuits::apps::test_apps::escrow { diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp index 616fd754962..0082220edb8 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp @@ -1,9 +1,11 @@ #include "transfer.hpp" + +#include "contract.hpp" + #include #include #include // #include -#include "contract.hpp" namespace aztec3::circuits::apps::test_apps::escrow { @@ -70,8 +72,8 @@ OptionalPrivateCircuitPublicInputs transfer(FunctionExecutionContext #include -#include "init.hpp" namespace aztec3::circuits::apps::test_apps::escrow { diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp index 30245ff901a..a969dc74b3f 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp @@ -1,9 +1,9 @@ #include "withdraw.hpp" + +#include "contract.hpp" + #include -#include -#include #include -#include "contract.hpp" namespace aztec3::circuits::apps::test_apps::escrow { @@ -48,20 +48,8 @@ OptionalPrivateCircuitPublicInputs withdraw(FunctionExecutionContext withdraw(FunctionExecutionContext -#include -#include "deposit.hpp" -#include "contract.hpp" - -namespace aztec3::circuits::apps::test_apps::escrow { - -using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; - -void withdraw_failure_callback(FunctionExecutionContext& exec_ctx, - NT::fr const& _asset_id, - NT::fr const& _amount, - NT::address const& _owner_address, - NT::fr const& _memo) -{ - auto& composer = exec_ctx.composer; - auto& oracle = exec_ctx.oracle; - Contract contract = init_contract(exec_ctx); - - CT::fr asset_id = to_ct(composer, _asset_id); - CT::fr amount = to_ct(composer, _amount); - CT::address owner_address = to_ct(composer, _owner_address); - CT::fr memo = to_ct(composer, _memo); - - CT::address msg_sender = oracle.get_msg_sender(); - - auto& balances = contract.get_private_state("balances"); - - balances.at({ owner_address.to_field(), asset_id }) - .add({ - .value = amount, - .owner_address = owner_address, - .creator_address = msg_sender, - .memo = memo, - }); - - auto& public_inputs = exec_ctx.private_circuit_public_inputs; - - public_inputs.custom_inputs[0] = asset_id; - public_inputs.custom_inputs[1] = amount; - public_inputs.custom_inputs[2] = owner_address.to_field(); - public_inputs.custom_inputs[3] = memo; - - exec_ctx.finalise(); - - info("public inputs: ", public_inputs); -}; - -} // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw_failure_callback.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw_failure_callback.hpp deleted file mode 100644 index ed86630ff8c..00000000000 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw_failure_callback.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include -#include "init.hpp" - -namespace aztec3::circuits::apps::test_apps::escrow { - -void withdraw_failure_callback(FunctionExecutionContext& exec_ctx, - NT::fr const& _asset_id, - NT::fr const& _amount, - NT::address const& _owner_address, - NT::fr const& _memo); - -} // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/kernel/private/.test.cpp b/circuits/src/aztec3/circuits/kernel/private/.test.cpp index b94e94ee7ee..a2b822d8552 100644 --- a/circuits/src/aztec3/circuits/kernel/private/.test.cpp +++ b/circuits/src/aztec3/circuits/kernel/private/.test.cpp @@ -1,5 +1,3 @@ -#include -#include // #include // #include // #include @@ -12,6 +10,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -19,12 +20,15 @@ #include #include #include -#include // #include // #include // #include -#include +#include + +#include +#include +#include // #include // #include @@ -35,9 +39,13 @@ namespace { using aztec3::circuits::abis::CallContext; using aztec3::circuits::abis::CallStackItem; using aztec3::circuits::abis::CallType; -using aztec3::circuits::abis::ExecutedCallback; using aztec3::circuits::abis::FunctionSignature; using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; +using aztec3::circuits::abis::PrivateCircuitPublicInputs; +using aztec3::circuits::abis::SignedTxObject; +using aztec3::circuits::abis::TxContext; +using aztec3::circuits::abis::TxObject; + using aztec3::circuits::abis::private_kernel::AccumulatedData; using aztec3::circuits::abis::private_kernel::ConstantData; using aztec3::circuits::abis::private_kernel::Globals; @@ -50,7 +58,7 @@ using aztec3::circuits::abis::private_kernel::PublicInputs; using aztec3::circuits::apps::test_apps::escrow::deposit; // using aztec3::circuits::mock::mock_circuit; -using aztec3::circuits::mock::mock_circuit_2; +using aztec3::circuits::mock::mock_kernel_circuit; } // namespace @@ -60,6 +68,10 @@ class private_kernel_tests : public ::testing::Test {}; TEST(private_kernel_tests, test_deposit) { + //*************************************************************************** + // Some private circuit proof (`deposit`, in this case) + //*************************************************************************** + const NT::address escrow_contract_address = 12345; const NT::fr escrow_contract_leaf_index = 1; const NT::fr escrow_portal_contract_address = 23456; @@ -82,7 +94,8 @@ TEST(private_kernel_tests, test_deposit) auto asset_id = NT::fr(1); auto memo = NT::fr(999); - OptionalPrivateCircuitPublicInputs deposit_public_inputs = deposit(deposit_ctx, amount, asset_id, memo); + OptionalPrivateCircuitPublicInputs opt_deposit_public_inputs = deposit(deposit_ctx, amount, asset_id, memo); + PrivateCircuitPublicInputs deposit_public_inputs = opt_deposit_public_inputs.remove_optionality(); UnrolledProver deposit_prover = deposit_composer.create_unrolled_prover(); NT::Proof deposit_proof = deposit_prover.construct_proof(); @@ -90,118 +103,131 @@ TEST(private_kernel_tests, test_deposit) std::shared_ptr deposit_vk = deposit_composer.compute_verification_key(); - //************************************************** + //*************************************************************************** + // We can create a TxObject from some of the above data. Users must sign a TxObject in order to give permission for + // a tx to take place - creating a SignedTxObject. + //*************************************************************************** + + TxObject deposit_tx_object = TxObject{ + .from = tx_origin, + .to = escrow_contract_address, + .function_signature = + FunctionSignature{ + .vk_index = 0, // TODO: deduce this from the contract, somehow. + .is_private = true, + .is_constructor = false, + }, + .custom_inputs = deposit_public_inputs.custom_inputs, + .nonce = 0, + .tx_context = + TxContext{ + .called_from_l1 = false, + .called_from_public_l2 = false, + .is_fee_payment_tx = false, + .reference_block_num = 0, + }, + .chain_id = 1, + }; + + SignedTxObject signed_deposit_tx_object = SignedTxObject{ + .tx_object = deposit_tx_object, + + // .signature = TODO: need a method for signing a TxObject. + }; + + //*************************************************************************** + // We mock a kernel circuit proof for the base case of kernel recursion (because even the first iteration of the + // kernel circuit expects to verify some previous kernel circuit). + //*************************************************************************** + + Composer mock_kernel_composer; + + // TODO: we have a choice to make: + // Either the `end` state of the mock kernel's public inputs can be set equal to the public call we _want_ to + // verify in the first round of recursion, OR, we have some fiddly conditional logic in the circuit to ignore + // certain checks if we're handling the 'base case' of the recursion. + // I've chosen the former, for now. + const CallStackItem deposit_call_stack_item{ + .contract_address = deposit_tx_object.to, + + .function_signature = deposit_tx_object.function_signature, + + .public_inputs = deposit_public_inputs, + }; + + std::array initial_kernel_private_call_stack{}; + initial_kernel_private_call_stack[0] = deposit_call_stack_item.hash(); - // MIKE! Need to create a dummy kernel circuit and generate a proof and vk to feed into the below!!! + // Some test data: + auto mock_kernel_public_inputs = PublicInputs{ + .end = + AccumulatedData{ + .private_call_stack = initial_kernel_private_call_stack, + }, - Composer mock_composer; - auto mock_public_inputs = PublicInputs{ - .end = AccumulatedData{}, + // These will be constant throughout all recursions, so can be set to those of the first function call - the + // deposit tx. .constants = ConstantData{ .old_tree_roots = OldTreeRoots{ - // TODO: this needs to be populated from the start, if the roots - // are used in any of the functions being recursed-through. - // .private_data_tree_root = + .private_data_tree_root = deposit_public_inputs.old_private_data_tree_root, + // .nullifier_tree_root = // .contract_tree_root = - // .l1_results_tree_root = // .private_kernel_vk_tree_root = }, - // .is_constructor_recursion = false, - // .is_callback_recursion = false, - .executed_callback = ExecutedCallback{}, - .globals = Globals{}, + .tx_context = deposit_tx_object.tx_context, }, + .is_private = true, // .is_public = false, // .is_contract_deployment = false, }; - mock_circuit_2(mock_composer, mock_public_inputs); - UnrolledProver mock_prover = mock_composer.create_unrolled_prover(); - NT::Proof mock_proof = mock_prover.construct_proof(); - // info("\nmock_proof: ", mock_proof.proof_data); + mock_kernel_circuit(mock_kernel_composer, mock_kernel_public_inputs); - std::shared_ptr mock_vk = mock_composer.compute_verification_key(); + UnrolledProver mock_kernel_prover = mock_kernel_composer.create_unrolled_prover(); + NT::Proof mock_kernel_proof = mock_kernel_prover.construct_proof(); + // info("\nmock_kernel_proof: ", mock_kernel_proof.proof_data); - //************************************************** + std::shared_ptr mock_kernel_vk = mock_kernel_composer.compute_verification_key(); + + //*************************************************************************** + // Now we can execute and prove the first kernel iteration, with all the data generated above: + // - app proof, public inputs, etc. + // - mock kernel proof, public inputs, etc. + //*************************************************************************** Composer private_kernel_composer; + // TODO: I think we need a different kind of oracle for the kernel circuits... NativeOracle private_kernel_oracle = NativeOracle(db, escrow_contract_address, msg_sender, msg_sender_private_key); OracleWrapper private_kernel_oracle_wrapper = OracleWrapper(private_kernel_composer, private_kernel_oracle); - const CallStackItem deposit_call_stack_item{ - .function_signature = - FunctionSignature{ - // .contract_address = escrow_contract_address, - .vk_index = 0, // TODO: deduce this from a NT state_factory. - .is_private = true, - // .is_constructor = false, - // .is_callback = false, - }, - .public_inputs = deposit_public_inputs.remove_optionality(), - .call_context = *deposit_public_inputs.call_context, - // .is_delegate_call = false, - // .is_static_call = false, - }; + PrivateInputs private_inputs = PrivateInputs{ + .signed_tx_object = signed_deposit_tx_object, - // PrivateInputs private_inputs; - PrivateInputs private_inputs = { - // .start = - // AccumulatedData{ - // .private_call_stack = - // std::array{ - // deposit_call_stack_item.hash(), 0, 0, 0, 0, 0, 0, 0 } }, // AccumulatedData starts out mostly - // // empty, since nothing has been - // // accumulated through kernel - // recursion - // // yet. .previous_kernel = PreviousKernelData{ - .public_inputs = - PublicInputs{ - .end = - AccumulatedData{ - .private_call_stack = - std::array{ - deposit_call_stack_item.hash(), 0, 0, 0, 0, 0, 0, 0 } }, // AccumulatedData - // starts out mostly - // empty, since nothing - // has been accumulated - // through kernel - // recursion yet. - .constants = - ConstantData{ - .old_tree_roots = - OldTreeRoots{ - // .private_data_tree_root = - // .contract_tree_root = - // .l1_results_tree_root = - // .private_kernel_vk_tree_root = - }, - // .is_constructor_recursion = false, - // .is_callback_recursion = false, - .executed_callback = ExecutedCallback{}, - .globals = Globals{}, - }, - // .is_private = true, - // .is_public = false, - // .is_contract_deployment = false, - }, - .proof = mock_proof, - .vk = mock_vk, + .public_inputs = mock_kernel_public_inputs, + .proof = mock_kernel_proof, + .vk = mock_kernel_vk, }, + .private_call = PrivateCallData{ .call_stack_item = deposit_call_stack_item, + // .call_context_reconciliation_data = TODO + .proof = deposit_proof, .vk = deposit_vk, // .vk_path TODO - .portal_contract_address = escrow_portal_contract_address, + + // .contract_tree_root TODO .contract_leaf_index = escrow_contract_leaf_index, // .contract_path TODO + + .portal_contract_address = escrow_portal_contract_address, }, }; @@ -211,6 +237,9 @@ TEST(private_kernel_tests, test_deposit) info("witness: ", private_kernel_composer.witness); // info("constant variables: ", private_kernel_composer.constant_variables); // info("variables: ", private_kernel_composer.variables); + + // TODO: this fails intermittently, with: + // bigfield multiply range check failed info("failed?: ", private_kernel_composer.failed); info("err: ", private_kernel_composer.err); info("n: ", private_kernel_composer.n); diff --git a/circuits/src/aztec3/circuits/kernel/private/init.hpp b/circuits/src/aztec3/circuits/kernel/private/init.hpp index 7de5e57449f..0de9fc6ecfd 100644 --- a/circuits/src/aztec3/circuits/kernel/private/init.hpp +++ b/circuits/src/aztec3/circuits/kernel/private/init.hpp @@ -1,9 +1,4 @@ #pragma once -#include -#include -#include -#include - #include #include #include @@ -12,6 +7,11 @@ #include +#include +#include +#include +#include + namespace aztec3::circuits::kernel::private_kernel { // Turbo specific, at the moment: diff --git a/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp b/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp index 9b318228810..df636538723 100644 --- a/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp +++ b/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp @@ -1,4 +1,5 @@ #include "init.hpp" + #include #include @@ -7,6 +8,11 @@ namespace aztec3::circuits::kernel::private_kernel { using aztec3::circuits::abis::private_kernel::PrivateInputs; using aztec3::circuits::abis::private_kernel::PublicInputs; +/****************************************************************************************************************** + * Calcs on circuit arrays. + * TODO: move these array calcs to a common/circuit_array.hpp file. + *****************************************************************************************************************/ + /** * Gets the number of contiguous nonzero values of an array. * Note: this assumes `0` always means 'not used', so be careful. If you actually want `0` to be counted, you'll need @@ -58,6 +64,37 @@ template CT::boolean is_array_empty(std::array return !nonzero_found; }; +/** + * Inserts the `source` array at the first zero-valued index of the `target` array. + * Fails if the `source` array is too large vs the remaining capacity of the `target` array. + */ +template +void push_array_to_array(std::array const& source, std::array& target) +{ + CT::fr target_length = array_length(target); + CT::fr source_length = array_length(source); + + CT::fr target_capacity = CT::fr(target.size()); + // TODO: using safe_fr for an underflow check, do: + // remaining_target_capacity = target_capacity.subtract(target_length + source_length); + + CT::fr t_i = 0; + CT::fr next_index = target_length; + for (const auto& s : source) { + for (auto& t : target) { + next_index.assert_not_equal(target_capacity, "Target array capacity exceeded"); + CT::boolean at_index = t_i == next_index; + t = CT::fr::conditional_assign(at_index, s, t); + next_index = CT::fr::conditional_assign(at_index, next_index + 1, next_index); + ++t_i; + } + } +} + +/*************************************************************************************************************** + * End of array calcs. + **************************************************************************************************************/ + // TODO: NEED TO RECONCILE THE `proof`'s public inputs (which are uint8's) with the // private_call.call_stack_item.public_inputs! CT::AggregationObject verify_proofs(Composer& composer, @@ -77,16 +114,7 @@ CT::AggregationObject verify_proofs(Composer& composer, return aggregation_object; } -void validate_private_call_hash(PrivateInputs const& private_inputs) -{ - const auto& start = private_inputs.previous_kernel.public_inputs.end; - const auto private_call_hash = array_pop(start.private_call_stack); - const auto calculated_private_call_hash = private_inputs.private_call.call_stack_item.hash(); - - private_call_hash.assert_equal(calculated_private_call_hash, "private_call_hash does not reconcile"); -}; - -void ensure_consistency_between_kernels(PrivateInputs const& private_inputs, PublicInputs& public_inputs) +void initialise_end_values(PrivateInputs const& private_inputs, PublicInputs& public_inputs) { public_inputs.constants = private_inputs.previous_kernel.public_inputs.constants; @@ -94,99 +122,15 @@ void ensure_consistency_between_kernels(PrivateInputs const& private_inputs, auto& end = public_inputs.end; const auto& start = private_inputs.previous_kernel.public_inputs.end; + end.output_commitments = start.output_commitments; + end.input_nullifiers = start.input_nullifiers; + end.private_call_stack = start.private_call_stack; end.public_call_stack = start.public_call_stack; end.contract_deployment_call_stack = start.contract_deployment_call_stack; end.l1_call_stack = start.l1_call_stack; - end.callback_stack = start.callback_stack; - end.optionally_revealed_data = start.optionally_revealed_data; - end.output_commitments = start.output_commitments; - end.input_nullifiers = start.input_nullifiers; -} - -void validate_inputs(PrivateInputs const& private_inputs, PublicInputs& public_inputs) -{ - private_inputs.private_call.call_stack_item.function_signature.is_private.assert_equal( - true, "Cannot execute a non-private function with the private kernel circuit"); - - const auto& start = private_inputs.previous_kernel.public_inputs.end; - - const CT::boolean is_base_case = start.private_call_count == 0; - const CT::boolean is_recursive_case = !is_base_case; - - CT::fr start_private_call_stack_length = array_length(start.private_call_stack); - CT::fr start_public_call_stack_length = array_length(start.public_call_stack); - CT::fr start_contract_deployment_call_stack_length = array_length(start.contract_deployment_call_stack); - CT::fr start_l1_call_stack_length = array_length(start.l1_call_stack); - - { - is_base_case.must_imply(start_private_call_stack_length == - 1 // TODO: might change to allow 2, so a fee can be paid. - && start_public_call_stack_length == 0 && - start_contract_deployment_call_stack_length == 0 && start_l1_call_stack_length == 0, - "Invalid arrays for base case."); - - is_base_case.must_imply(private_inputs.private_call.call_stack_item.is_delegate_call == false && - private_inputs.private_call.call_stack_item.is_static_call == false, - "A user cannot make a delegatecall or staticcall"); - - // The below also prevents delegatecall/staticcall - // is_base_case.must_imply(private_inputs.private_call.call_stack_item.call_context.storage_contract_address == - // private_inputs.private_call.call_stack_item.function_signature.contract_address, - // "Storage contract address must be that of the called contract in the base case"); - - // TODO: privatelyExecutedCallback logic and checks - } - - { - is_recursive_case.must_imply(private_inputs.previous_kernel.public_inputs.is_private == true, - "Cannot verify a non-private kernel snark in the private kernel circuit"); - is_recursive_case.must_imply(private_inputs.private_call.call_stack_item.call_context.is_callback == false, - "A callback must be executed as the first tx in the recursion"); - is_recursive_case.must_imply(private_inputs.private_call.call_stack_item.function_signature.is_constructor == - false, - "A constructor must be executed as the first tx in the recursion"); - is_recursive_case.must_imply(start_private_call_stack_length != 0); - } - - ensure_consistency_between_kernels(private_inputs, public_inputs); - validate_private_call_hash(private_inputs); - - // TODO: need to make this assertion somewhere, or only have call_context exist in one of these places (it _has_ to - // be in the private_inputs.private_call.call_stack_item.public_inputs... and actually, when making a call, I think - // it has to be in the call_stack_item, since the public inputs of the thing being called aren't known yet... so it - // has to be in both places!!!)! - - (private_inputs.private_call.call_stack_item.call_context == - private_inputs.private_call.call_stack_item.public_inputs.call_context) - .assert_equal(true, "Call context mismatches"); -} - -/** - * Inserts the `source` array at the first zero-valued index of the `target` array. - * Fails if the `source` array is too large vs the remaining capacity of the `target` array. - */ -template -void push_array_to_array(std::array const& source, std::array& target) -{ - CT::fr target_length = array_length(target); - CT::fr source_length = array_length(source); - CT::fr target_capacity = CT::fr(target.size()); - // TODO: using safe_fr for an underflow check, do: - // remaining_target_capacity = target_capacity.subtract(target_length + source_length); - - CT::fr t_i = 0; - CT::fr next_index = target_length; - for (const auto& s : source) { - for (auto& t : target) { - next_index.assert_not_equal(target_capacity, "Target array capacity exceeded"); - CT::boolean at_index = t_i == next_index; - t = CT::fr::conditional_assign(at_index, s, t); - next_index = CT::fr::conditional_assign(at_index, next_index + 1, next_index); - ++t_i; - } - } + end.optionally_revealed_data = start.optionally_revealed_data; } void update_end_values(PrivateInputs const& private_inputs, PublicInputs& public_inputs) @@ -196,14 +140,14 @@ void update_end_values(PrivateInputs const& private_inputs, PublicInputs const auto& output_commitments = private_call_public_inputs.output_commitments; const auto& input_nullifiers = private_call_public_inputs.input_nullifiers; - const auto& is_static_call = private_inputs.private_call.call_stack_item.is_static_call; + const auto& is_static_call = private_inputs.private_call.call_stack_item.public_inputs.call_context.is_static_call; // No state changes are allowed for static calls: is_static_call.must_imply(is_array_empty(output_commitments) == true); is_static_call.must_imply(is_array_empty(input_nullifiers) == true); const auto& storage_contract_address = - private_inputs.private_call.call_stack_item.call_context.storage_contract_address; + private_inputs.private_call.call_stack_item.public_inputs.call_context.storage_contract_address; { // commitments & nullifiers std::array siloed_output_commitments; @@ -229,7 +173,7 @@ void update_end_values(PrivateInputs const& private_inputs, PublicInputs { // TODO: we need to pass in UNPACKED stack data. I.e. the preimages of the call_stack_item hashes, so that data - // in the stack can be validated as being correct. (e.g. call_contexts of calls made by the public_call + // in the stack can be validated as being correct. (e.g. call_contexts of calls made by the private_call // currently being validated). // So we'll need to ensure our test_apps return not only a PrivateCircuitPublicInputs object, but also an object @@ -238,6 +182,10 @@ void update_end_values(PrivateInputs const& private_inputs, PublicInputs // - Commitment and nullifier preimages // - Hash paths and leaf indices // - Any and all preimage data derived by the circuit or through oracle calls. + + // Update on this topic: I've created call_context_reconciliation_data, which allows the call_context to be + // efficiently unpacked from a call_stack_item_hash. We'll need some "functions calling functions" tests cases + // to see how best to move this data around neatly. } const auto& portal_contract_address = private_inputs.private_call.portal_contract_address; @@ -256,18 +204,82 @@ void update_end_values(PrivateInputs const& private_inputs, PublicInputs } } +void validate_private_call_hash(PrivateInputs const& private_inputs) +{ + const auto& start = private_inputs.previous_kernel.public_inputs.end; + const auto private_call_hash = array_pop(start.private_call_stack); + const auto calculated_private_call_hash = private_inputs.private_call.call_stack_item.hash(); + + private_call_hash.assert_equal(calculated_private_call_hash, "private_call_hash does not reconcile"); +}; + +void validate_inputs(PrivateInputs const& private_inputs) +{ + + const auto& next_call = private_inputs.private_call.call_stack_item; + + next_call.function_signature.is_private.assert_equal( + true, "Cannot execute a non-private function with the private kernel circuit"); + + const auto& start = private_inputs.previous_kernel.public_inputs.end; + + const CT::boolean is_base_case = start.private_call_count == 0; + const CT::boolean is_recursive_case = !is_base_case; + + CT::fr start_private_call_stack_length = array_length(start.private_call_stack); + CT::fr start_public_call_stack_length = array_length(start.public_call_stack); + CT::fr start_contract_deployment_call_stack_length = array_length(start.contract_deployment_call_stack); + CT::fr start_l1_call_stack_length = array_length(start.l1_call_stack); + + // Base Case + { + // Validate callstack lengths: + is_base_case.must_imply(start_private_call_stack_length == + 1 // TODO: might change to allow 2, so a fee can be paid. + && start_public_call_stack_length == 0 && + start_contract_deployment_call_stack_length == 0 && start_l1_call_stack_length == 0, + "Invalid callstacks for base case."); + + is_base_case.must_imply(next_call.public_inputs.call_context.is_delegate_call == false && + next_call.public_inputs.call_context.is_static_call == false, + "A user cannot make a delegatecall or staticcall"); + + // The below also prevents delegatecall/staticcall + is_base_case.must_imply(next_call.public_inputs.call_context.storage_contract_address == + next_call.contract_address, + "Storage contract address must be that of the called contract in the base case"); + } + + // Recursive Case + { + is_recursive_case.must_imply(private_inputs.previous_kernel.public_inputs.is_private == true, + "Cannot verify a non-private kernel snark in the private kernel circuit"); + + is_recursive_case.must_imply(next_call.function_signature.is_constructor == false, + "A constructor must be executed as the first tx in the recursion"); + + is_recursive_case.must_imply(start_private_call_stack_length != 0); + } + + validate_private_call_hash(private_inputs); +} + // TODO: decide what to return. void private_kernel_circuit(Composer& composer, OracleWrapper& oracle, PrivateInputs const& _private_inputs) { + (void)oracle; // To avoid unused variable compiler errors whilst building. + const PrivateInputs private_inputs = _private_inputs.to_circuit_type(composer); PublicInputs public_inputs; - const auto& start = private_inputs.previous_kernel.public_inputs.end; + // const auto& start = private_inputs.previous_kernel.public_inputs.end; - const CT::boolean is_base_case = start.private_call_count == 0; + // const CT::boolean is_base_case = start.private_call_count == 0; // const CT::boolean is_recursive_case = !is_base_case; - validate_inputs(private_inputs, public_inputs); + validate_inputs(private_inputs); + + initialise_end_values(private_inputs, public_inputs); auto aggregation_object = verify_proofs(composer, private_inputs, @@ -276,19 +288,6 @@ void private_kernel_circuit(Composer& composer, OracleWrapper& oracle, PrivateIn // TODO: kernel vk membership check! - // This line is just to stop the compiler complaining about `oracle` being unused whilst building. - oracle.generate_random_element().assert_is_not_zero(); - - public_inputs.constants.is_constructor_recursion = CT::boolean::conditional_assign( - is_base_case, - private_inputs.private_call.call_stack_item.function_signature.is_constructor, - private_inputs.previous_kernel.public_inputs.constants.is_constructor_recursion); - - public_inputs.constants.is_callback_recursion = - CT::boolean::conditional_assign(is_base_case, - private_inputs.private_call.call_stack_item.call_context.is_callback, - private_inputs.previous_kernel.public_inputs.constants.is_callback_recursion); - public_inputs.end.aggregation_object = aggregation_object; // public_inputs.set_public(); diff --git a/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.hpp b/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.hpp index 4007d0ca844..4b6f6b4b3b3 100644 --- a/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.hpp +++ b/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.hpp @@ -1,5 +1,7 @@ #pragma once + #include "init.hpp" + #include // #include diff --git a/circuits/src/aztec3/circuits/mock/mock_circuit_2.hpp b/circuits/src/aztec3/circuits/mock/mock_kernel_circuit.hpp similarity index 92% rename from circuits/src/aztec3/circuits/mock/mock_circuit_2.hpp rename to circuits/src/aztec3/circuits/mock/mock_kernel_circuit.hpp index 6e782b7c967..a35698c76b8 100644 --- a/circuits/src/aztec3/circuits/mock/mock_circuit_2.hpp +++ b/circuits/src/aztec3/circuits/mock/mock_kernel_circuit.hpp @@ -16,7 +16,7 @@ using plonk::stdlib::pedersen; using plonk::stdlib::witness_t; using plonk::stdlib::types::CircuitTypes; -template void mock_circuit_2(Composer& composer, PublicInputs const& _public_inputs) +template void mock_kernel_circuit(Composer& composer, PublicInputs const& _public_inputs) { typedef CircuitTypes CT; typedef typename CT::fr fr; diff --git a/circuits/src/aztec3/constants.hpp b/circuits/src/aztec3/constants.hpp index e8565cbec0f..601fbb9284a 100644 --- a/circuits/src/aztec3/constants.hpp +++ b/circuits/src/aztec3/constants.hpp @@ -5,8 +5,7 @@ namespace aztec3 { constexpr size_t CUSTOM_INPUTS_LENGTH = 8; constexpr size_t CUSTOM_OUTPUTS_LENGTH = 4; -constexpr size_t EMITTED_PUBLIC_INPUTS_LENGTH = 4; -constexpr size_t EMITTED_OUTPUTS_LENGTH = 4; +constexpr size_t EMITTED_EVENTS_LENGTH = 4; constexpr size_t OUTPUT_COMMITMENTS_LENGTH = 4; constexpr size_t INPUT_NULLIFIERS_LENGTH = 4; @@ -18,7 +17,6 @@ constexpr size_t PRIVATE_CALL_STACK_LENGTH = 4; constexpr size_t PUBLIC_CALL_STACK_LENGTH = 4; constexpr size_t CONTRACT_DEPLOYMENT_CALL_STACK_LENGTH = 2; constexpr size_t PARTIAL_L1_CALL_STACK_LENGTH = 2; -constexpr size_t CALLBACK_STACK_LENGTH = PARTIAL_L1_CALL_STACK_LENGTH; constexpr size_t KERNEL_OUTPUT_COMMITMENTS_LENGTH = 16; constexpr size_t KERNEL_INPUT_NULLIFIERS_LENGTH = 16; @@ -26,7 +24,6 @@ constexpr size_t KERNEL_PRIVATE_CALL_STACK_LENGTH = 8; constexpr size_t KERNEL_PUBLIC_CALL_STACK_LENGTH = 8; constexpr size_t KERNEL_CONTRACT_DEPLOYMENT_CALL_STACK_LENGTH = 4; constexpr size_t KERNEL_L1_CALL_STACK_LENGTH = 4; -constexpr size_t KERNEL_CALLBACK_STACK_LENGTH = KERNEL_L1_CALL_STACK_LENGTH; constexpr size_t KERNEL_OPTIONALLY_REVEALED_DATA_LENGTH = 4; constexpr size_t VK_TREE_HEIGHT = 3; @@ -43,16 +40,15 @@ enum GeneratorIndex { NULLIFIER_HASHED_PRIVATE_KEY, NULLIFIER, OUTER_NULLIFIER, + STATE_READ, + STATE_TRANSITION, CONTRACT_ADDRESS, FUNCTION_SIGNATURE, - CALL_ARGS, - EXECUTED_CALLBACK, CALL_CONTEXT, CALL_STACK_ITEM, - CALLBACK_STACK_ITEM, + CALL_STACK_ITEM_2, // see function where it's used for explanation PARTIAL_L1_CALL_STACK_ITEM, L1_CALL_STACK_ITEM, - L1_RESULT_PLACEHOLDER, PRIVATE_CIRCUIT_PUBLIC_INPUTS, PUBLIC_CIRCUIT_PUBLIC_INPUTS, }; diff --git a/circuits/src/aztec3/oracle/oracle.hpp b/circuits/src/aztec3/oracle/oracle.hpp index e9be5db6b21..1986a402f64 100644 --- a/circuits/src/aztec3/oracle/oracle.hpp +++ b/circuits/src/aztec3/oracle/oracle.hpp @@ -23,11 +23,7 @@ template class NativeOracleInterface { NT::address const& tx_origin, NT::boolean const& is_delegate_call = false, NT::boolean const& is_static_call = false, - NT::boolean const& is_fee_payment = false, - NT::boolean const& pay_fee_from_l1 = false, - NT::boolean const& pay_fee_from_public_l2 = false, - NT::boolean const& called_from_l1 = false, - NT::boolean const& called_from_public_l2 = false) + NT::fr const& reference_block_num = 0) : db(db) , call_context({ .msg_sender = msg_sender, @@ -35,11 +31,7 @@ template class NativeOracleInterface { .tx_origin = tx_origin, .is_delegate_call = is_delegate_call, .is_static_call = is_static_call, - .is_fee_payment = is_fee_payment, - .pay_fee_from_l1 = pay_fee_from_l1, - .pay_fee_from_public_l2 = pay_fee_from_public_l2, - .called_from_l1 = called_from_l1, - .called_from_public_l2 = called_from_public_l2, + .reference_block_num = reference_block_num, }) // , portal_contract_address(portal_contract_address) {}; @@ -53,11 +45,7 @@ template class NativeOracleInterface { std::optional msg_sender_private_key, NT::boolean const& is_delegate_call = false, NT::boolean const& is_static_call = false, - NT::boolean const& is_fee_payment = false, - NT::boolean const& pay_fee_from_l1 = false, - NT::boolean const& pay_fee_from_public_l2 = false, - NT::boolean const& called_from_l1 = false, - NT::boolean const& called_from_public_l2 = false) + NT::fr const& reference_block_num = 0) : db(db) , call_context({ .msg_sender = msg_sender, @@ -65,11 +53,7 @@ template class NativeOracleInterface { .tx_origin = tx_origin, .is_delegate_call = is_delegate_call, .is_static_call = is_static_call, - .is_fee_payment = is_fee_payment, - .pay_fee_from_l1 = pay_fee_from_l1, - .pay_fee_from_public_l2 = pay_fee_from_public_l2, - .called_from_l1 = called_from_l1, - .called_from_public_l2 = called_from_public_l2, + .reference_block_num = reference_block_num, }) // , portal_contract_address(portal_contract_address) , msg_sender_private_key(msg_sender_private_key){}; From c854807883907dde594b1ce7b3159b4500c88ae7 Mon Sep 17 00:00:00 2001 From: iAmMichaelConnor Date: Wed, 14 Dec 2022 09:42:27 +0000 Subject: [PATCH 015/166] update private abi & kernel docs --- circuits/specs/src/QUESTIONS.md | 60 ---- .../app-circuits/public-input-abis.md | 156 +++++---- .../src/architecture/contracts/deployment.md | 2 +- .../architecture/contracts/transactions.md | 153 ++++++--- .../contract-deployment-kernel.md | 4 + .../kernel-circuits/kernel-circuits.md | 2 +- .../kernel-circuits/private-kernel.md | 321 ++++++++---------- .../kernel-circuits/public-kernel.md | 2 + .../specs/src/noir-stuff/extremes/call-l1.md | 8 +- .../src/noir-stuff/extremes/call-private.md | 4 +- .../noir-stuff/extremes/decr-private-owned.md | 4 +- .../noir-stuff/extremes/deploy-contract.md | 4 +- .../src/noir-stuff/extremes/emit-event.md | 6 +- .../extremes/incr-private-not-owned.md | 2 +- .../noir-stuff/extremes/incr-private-owned.md | 4 +- 15 files changed, 361 insertions(+), 371 deletions(-) delete mode 100644 circuits/specs/src/QUESTIONS.md diff --git a/circuits/specs/src/QUESTIONS.md b/circuits/specs/src/QUESTIONS.md deleted file mode 100644 index 9718fa3523f..00000000000 --- a/circuits/specs/src/QUESTIONS.md +++ /dev/null @@ -1,60 +0,0 @@ -# Questions - -A list of random thoughts and questions that haven't been fully considered yet. - -This isn't a comprehensive list of questions - there are loads dotted around these pages. - -- Where to develop the code? - - Will need to make significant edits to Falafel. - - Aztec Connect circuits aren't needed. -- How should I proceeed? - - I could plan out lots of distinct tasks. - - Roadmap: - - Releases with milestones of functionality? - - One final big release at the end? - - E.g. Charlie suggested ignoring Public circuit functionality altogether initially. - - I can start writing kernel circuits, rollup circuits, making changes to falafel, writing smart contracts. -- Components: - - Smart contract language: Noir? - - Testing framework: also Noir? - - Rollup provider full node: Falafel? - - Receives tx requests - - Creates rollups - - Coordinates delegation of proofs (future enhancement) - - Tracks the entire L2 state - - Rollup delegate node: Falafel in different 'mode'. - - Can be given / takes instructions to generate proofs for the rollup. - - Incentivisation mechanism needed? I think we can avoid this. - - User node: Also Falafel in a different 'mode', or separate? - - For generating client-side proofs - - Submitting proofs to the Rollup Provider pool - - For keeping minimal user state witnesses and querying stuff. - - User node: non-browser version? - - web3.js/ethers.js pacakge to convert JS tx requests into the Aztec 3 ABI format. -- Noir - how 'high-level' should it be? - - One extreme: it 'abstracts away' all of Aztec 3's architecture from the developer. - - Problem: one API for developer, and another ABI for the underlying circuit. - - Either need Noir plugged into a DB (but I'd prefer it to be stateless) - - Or need an ethers.js program to take a JS tx, query the falafel DB, then send an ABI-style tx to Noir. - - If we make architecture changes to the Public Inputs ABIs (which we will when optimising), Noir would need corresponding changes. - - Other extreme: a developer needs to write, in detail, circuits which conform to the Aztec 3 spec. -- Once the HONK backend is ready, will we be able to simply 'swap' our kernel circuits' backend from PLONK to HONK? -- Ask about callbacks: - - One-time-use callbacks (my preference) vs callback behaviour designed by each dev. - - Dedicated, decorated callback functions vs general functions that don't even _know_ they're a callback. - - If decorated as callback, the function can contain L1 result reconciliation logic. - - If general functions, then the L1 result reconciliation must happen in the kernel circuit / base rollup circuit. -- Meh: Take a look at an [alternative suggestion for callbacks](./architecture/contracts/l1-calls.md#alternative-approach-to-callbacks), and decide which is best. -- Decentralisation Roadmap: - - Rollup provider selection process? - - Aztec Token tokenomics. - - Tx pool - p2p messaging layer? Or direct messaging (if the Rollup Provider is the same for a period of time)? -- Revisit discussion on fees and attributing L2 fees payments to provers based on their proving work. -- Use ETH as L2 gas payment currency, or allow any general function to be labelled as a 'fee paying' currency? - - If we have specific gas costs relating to SLOAD / GEN_PROOF, then these will need to be paid in ETH surely? -- Ask about dynamic arrays and what the limitations are in UltraPlonk. - - Pushing to all of these callStacks is going to expensive (constraint-wise), especially if we want to tightly pack pushes. Lots of O(n^2) searching for correct positions in arrays. - - Unless we can do some clever dynamic array stuff with ultraplonk / honk? -- Do we need to emit all events to a special log that can be parsed? Like an L2 version of Ethereum's logs? - - E.g. how can app-specific javascript code 'react' to an event emitted by an L2 function? - - How does Ethereum do it? diff --git a/circuits/specs/src/architecture/app-circuits/public-input-abis.md b/circuits/specs/src/architecture/app-circuits/public-input-abis.md index 88d3230e631..f072342f6c9 100644 --- a/circuits/specs/src/architecture/app-circuits/public-input-abis.md +++ b/circuits/specs/src/architecture/app-circuits/public-input-abis.md @@ -3,37 +3,70 @@ The following describes how many public inputs each public/private circuit will have and how they will be interpreted. -## Private Circuit ABI +## `CallContext` + +Much of the CallContext comes from the [`TxContext`](../contracts/transactions.md#txcontext) over which the user signs. + +| Value | Description | +| --- | --- | +| `txOrigin`: `aztecAddress` | The user who signed over this tx. We'll need this when making nested function calls, because private keys for nested circuits might need to be grabbed from the Private Client's DB based on this address -- not from the calling contract's address (since a contract cannot have private keys). | +| `msgSender`: `aztecAddress` | - If doing a `call` or `staticCall`: Either the user address or the address of the contract that created the call. (Can be set to `0` for private -> public calls)
- If doing a `delegateCall`: the address of the calling contract's own `callContext.msgSender` (since delegate calls can be chained). | +| `storageContractAddress`: [`ContractAddress`](../contracts/transactions.md#contractaddress) | - If doing a `call` or `staticCall`: the address of the contract being called.
- If doing a `delegateCall`: the address of the calling contract's own `callContext.storageContractAddress` (since delegate calls can be chained). +| `isDelegateCall` : `Bool` | Used by the kernel snark to validate that the `callContext` of newly-pushed `callStackItems` is consistent with the contract making the call. | +| `isStaticCall` : `Bool` | Informs the kernel snark that it MUST fail if the function being called modifies state.

A state modification includes: creating a new contract; emitting events; writing to trees; making a 'call' to another contract. :question: Not sure why 'delegatecall' is not included as a potentially state-modifying tx in ethereum specs?

Note: static calls to private circuits might not make sense. 'Reads' from the privateDataTree require a write of equal value, but the kernel snark cannot 'see' what has been written (it's a private tx), and so cannot validate that a state change didn't take place. So there would be no output commitments or nullifiers for a private static call. But a private call's only use is (I think :question:) to read/modify private state. So I'm thinking a staticCall to a private circuit doesn't make sense. | +| `reference_block_num`: Field | The rollup number which should be used if referring to any historic tree values. Useful if the proof needs to use a particular tree state snapshot of a particular historic rollup. | + +## `StateTransition` + +Describes a single `publicDataTree` read+write operation. + +A 'state transition' is expressed as: +- `[storageSlot, old_value, new_value]`. + +:heavy_exclamation_mark: For state transitions, the caller might not know the `old_value` nor the `new_value` when they make the call (i.e. when they add the call to their callStack), since the value will depend on the current state of the publicDataTree. (Imagine if the storage slot represented total liquidity in some pool which changes frequently. Then the old and new values are only known at the time the rollup processor actually organises the ordering of txs in their block). + +Conclusion: the `publicInputs` data which is included in a [`PublicCallStackItem`](../contracts/transactions.md#publiccallstackitem) cannot include the `old_value` nor `new_value` inputs. Therefore, the `stateTransitions` that are populated by a user when generating the `PublicCallStackItemHash` will have `0`-valued placeholders for `old_value` and `new_value`. Pure reads can be emulated by setting a new write value to equal the read value. However, for this tree, we could halve the amount of hashing for pure reads by having a separate `reads` set of inputs. A read can be done without a write for this tree (see next field). + +| Value | Description | +| --- | --- | +| `storageSlot`: `Field` | The slot that the circuit wants to modify. | +| `oldValue`: `Field` | Old value is checked by the kernel circuit to be correct. | +| `newValue`: `Field` | New value inserted by the kernel circuit. | + +## `StateRead` + +For efficiency (vs a StateTransition), we can read public state without writing. As explained above, the `current_value` won't necessarily be known by the user when they generate the call, so `current_value` is replaced with `0` when the `PublicCallStackItem` is generated for calls to a public function. + +| Value | Description | +| --- | --- | +| `storageSlot`: `Field` | The slot that the circuit wants to modify. | +| `currentValue`: `Field` | Current value is checked by the kernel circuit to be correct. | + +# Private Circuit ABI All private contract circuits have a fixed number of public inputs. Most of these public inputs will eventually be swallowed by the [private kernel circuit](../kernel-circuits/private-kernel.md). Under some circumstances, some public inputs will be optionally revealed to the 'public world, depending on the various booleans in this table. > Note: some of these inputs might be packed into 1 field for efficiencies in the implementation, but for ease of understanding they're kept separate here. +## `PrivateCircuitPublicInputs` | Data type | Description | | -------- | -------- | -| *`customPublicInputs` | Up to 32 circuit-specific inputs passed into this circuit. All of these inputs will be 'swallowed' by the private kernel snark. Hence any private args can safely be put here, which enables private circuits to call other private circuits, and pass private data to them. To reveal data to the 'public world', either call a public function or emit an event. | -| *`customPublicOutputs` | Up to 32 circuit-specific values _returned by_ circuit. All of these inputs will be 'swallowed' by the private kernel snark. Hence any private outputs can safely be put here, which enables private circuits to call other private circuits, and pass private data to them. | -| `emittedPublicInputs` | Public inputs which will be revealed to the 'public world' (L1 or L2). E.g. allowing certain inputs to be more-easily extracted by the RollupProcessor contract (rather than having to unpack this vast ABI object of inputs, which would cost too much hash-wise). An example of its usefulness is passing a value from L1 to L2 when doing an L1->L2 tx (see 'deposit' example in the other doc). TODO: consider whether this could be a single value, for simplicity. It could be a hash of data if more values need to be exposed. If so, we'll rename to `emittedPublicInputsHash`. | -| *`executedCallback: {` | Populated if this circuit is a callback, so that the purported L1 Result to which this circuit is responding can be validated against the l1ResultsTree. | -| `- l1ResultHash`, | If this function is a callback function, following some L1 call, then it needs to expose the `l1ResultHash` to ensure the callback is actually using data emitted by L1. The preimage of the `l1ResultHash` will need to be passed in as private inputs to the circuit. Note: the `l1ResultHash` MUST be computed with a sha256 hash, because that's what the RollupProcessor will have used. This is unfortunate, as it forces apps to adhere to a specific calculation within their circuits. DISAGREE NOW - we don't need to calcualte this within the app circuit: we can just hash the custom_inputs and compare that hash against the L1ResultHash. | -| `- l1ResultsTreeLeafIndex`, | Communicates to the rollup provider the correct leaf to prove membership against in the l1ResultsTree. Only if we don't want to hide the callback will the rollup provider perform the membership check (within the Base Rollup Circuit). Otherwise it'll be performed in the Private Kernel Circuit. | -| `}`| -| `outputCommitments` | output notes to be added into the `privateDataTree` (up to 16) | -| `inputNullifiers` | input nullifiers to be added into the `nullifierTree` (up to 16) | -| `privateCallStack` | additional private calls created by this transaction (up to 16) | -| `publicCallStack` | additional public calls created by this transaction (up to 16) | -| `contractDeploymentCallStack` | additional calls which _deploy contracts_, created by this transaction (up to 1?) | -| `partialL1CallStack` | additional calls to L1 created by this transaction (up to 16). "Partial" because the kernel circuit will add the correct portal contract address to 'complete' the call into a proper L1 CallStack Item. See [here](../contracts/l1-calls.md). | -|
callbackStack = [{
  callbackPublicKey,
  successCallbackCallHash,
  failureCallbackCallHash,
  successResultArgMapAcc,
},...]
| An element in the array for each new L1 call on the `l1CallStack`. See [more](../contracts/l1-calls.md). We need to expose all of this data so that the kernel snark ensures the callback is a function of the same contract which made the call. | -| *`oldPrivateDataTreeRoot` | used to query the `privateDataTree` | -| Booleans: | | -| *`bool isFeePayment` | Notifies the kernel circuit that the following public inputs of this private circuit MUST be revealed to the public kernel circuit:
  • `functionSignature` - so that the rollup provider can see how they're to be paid
  • `emittedPublicInputs` - so that the rollup provider can validate the amount they'll be paid (they'll need to be provided with the underlying public inputs separately, to validate the hash).
| -| *`bool payFeeFromL1`| Provides a way of paying for private L2 function execution from L1 (the RollupProcessor.sol could provide the interface for ETH or ERC20... but we could generalise this by somehow pointing to a particular 'other' payment L1 contract state?). "Submit on-chain the callHash and state a fee (in L1 currency) for the L2 tx, and then when the L2 tx is executed, the rollup provider may redeem the previously-published fee".

Notifies the kernel circuit that the following public inputs of this private circuit MUST be revealed to the public kernel circuit:
  • `callHash` - no other data is needed (in order to allow the user to keep the function they've actually executed private).
| -| *`bool payFeeFromPublicL2`| Provides a way of paying for private L2 function execution from a public L2 circuit. This input being `true` will cause the rollup provider to look for an `isFeePayment` tx in the _public_ callStack. | -| *`bool calledFromL1` | If the L1 contract wants to call a specific L2 circuit, then the function signature needs to be revealed on-chain so that it can be checked that the correct, intended function was executed.

Notifies the private kernel circuit that an L1 contract wants to call this specific private L2 circuit, and so the following MUST be revealed to the public kernel circuit:
  • `functionSignature` - needed so the L1 contract can confirm the intended function was executed on L2. Although a callHash contains the functionSignature, the L1 contract wouldn't (cheaply) be able to unpack the callHash. So we expose the function signature as well to keep costs down. Although this leaks the function which was called, there's no way around that; this is an L1 -> L2 call after all.
  • `callHash` - used as a 'lookup' key. The RollupProcessor will store this `callHash`, and await an L2 tx with this `callHash` before triggering a callback to the L1 contract which made this L1 -> L2 call in the first place.
  • `emittedPublicInputs` - needed so that a set of values can be emitted by an L2 function and exposed to L1. It would be too expensive to unpack the callHash and extract all of the custom public inputs of a circuit. This is much cheaper, and is very similar to how the EVM exposes only a few values (via event emissions) to JavaScript (for example).


We need this convoluted process, because the RollupProcessor has to be _sure_ an L1 fee has been set-aside for them, before they add any corresponding L2 states. | -| Global vars: | | -| *`minTimestamp` | a timestamp value that must be exceeded when the block containing this txn is mined | +| `callContext`: [`CallContext`](#callcontext) | Information about what this function used as its call context, so that the kernel circuit may validate that the correct context was indeed used. | +| `args`: `Array[Field]` | Arguments passed into this circuit. All of these inputs will be 'swallowed' by the private kernel snark. Hence any private args can safely be put here, which enables private circuits to call other private circuits, and pass private data to them. To reveal data to the 'public world', either call a public function or emit an event. | +| `returnValues`: `Array[Field]` | Values _returned by_ circuit. All of these outputs will be 'swallowed' by the private kernel snark. Hence any private outputs can safely be put here, which enables private circuits to call other private circuits, and receive return data from them. | +| `emittedEvents`: `Array[Field]` | Public inputs which will be revealed to the 'public world' (L1 or L2). E.g. allowing certain inputs to be more-easily extracted by the RollupProcessor contract (rather than having to unpack this vast ABI object of inputs, which would cost too much hash-wise). An example of its usefulness is passing a value from L1 to L2 when doing an L1->L2 tx. | +| `newCommitments`: `Array[Field]` | new commitments to be added into the `privateDataTree` | +| `newNullifiers`: `Array[Field]` | new nullifiers to be added into the `nullifierTree` | +| `privateCallStack`: `Array[Field]` | Additional private calls made by this function. The `Field` is a hash of a [`PrivateCallStackItem`](../contracts/transactions.md#privatecallstackitem). | +| `publicCallStack`: `Array[Field]` | Additional public calls created by this transaction. The `Field` is a hash of a [`PublicCallStackItem`](../contracts/transactions.md#publiccallstackitem). | +| `contractDeploymentCallStack`: `Array[Field]` | Additional calls which _deploy contracts_, created by this transaction. The `Field` is a hash of a [`ContractDeploymentCallStackItem`](../contracts/transactions.md#contractdeploymentcallstackitem). | +| `partialL1CallStack`: [`Array[PartialL1CallStackItem]`](../contracts/transactions.md#l1callstackitem) | Additional calls to L1 created by this transaction. "Partial" because the kernel circuit will add the correct portal contract address to 'complete' the call into a proper L1 CallStack Item. See [here](../contracts/l1-calls.md). We need to expose all of this data (rather than hashing it to a `Field`), because the kernel snark needs to pass this data to L1, and unlike the earlier callstacks, we'll never have another opportunity to pass this 'unpacked' data into any other kernel snark. | +| `oldPrivateDataTreeRoot`: `Field` | The root that has been used to query the `privateDataTree` | +| `oldNullifierTreeRoot`: `Field` | The root that has been used to query the `nullifierDataTree` | +| `oldConstPublicDataTreeRoot`: `Field` | The root that has been used to query the `constPublicDataTree` (if we choose to have one). | +| `oldContractTreeRoot`: `Field` | The root that has been used to query the `contractTree` | + Apart from the public input API, the structure of a private contract circuit is undefined by the Aztec 3 architecture. @@ -55,83 +88,70 @@ Apart from the public input API, the structure of a private contract circuit is >- What _can_ be done is a defi-bridge-like chain of events: a private circuit generates a partial commitment, and then the public circuit completes that partial commitment with some public state and adds it to the privateDataTree. But that doesn't require explicit public -> private calls. -> **Aside:** we don't think we need chained transactions for Aztec 3. Recall: chained transactions give the ability to nullify a newly-created commitment _within_ the same rollup; before it's been added to the dataTree. This isn't needed. For a user to chain state to themselves, they can just create a callstack. The notion of chaining _between_ users is really complicated, and possibly not useful in practice. In particular, chaining doesn't play well with the idea of binary rollup trees, since the number of 'chaining' comparisons would blow up exponentially with the level of the rollup tree (meaning we'd need to build differently-sized rollup circuits per level). Recall: linked transactions give the ability to 'await' the inclusion of 'other' transactions in the rollup, before processing 'this' transaction. Unsure whether that's needed. - - - - -## Public Circuit ABI +# Public Circuit ABI The public contract ABI is similar to the private one. Whilst the _user_ provides all the values specified by this Public Circuit ABI, it's the _rollup provider_ who actually generates public contract proofs. This is because the rollup provider is the only party with perfect knowledge of the current Merkle roots, meaning only they can access/update the public data tree, as well as know the exact block number etc. +## `PublicCircuitPublicInputs` + +**NOTE** This section is out of date. Public function execution might differ drastically from this old draft. Not worth even reading this section anymore. | Data Type | Description | | -------- | -------- | -| `customPublicInputs` | Up to 32 circuit-specific inputs passed into this circuit. All of these inputs will be 'swallowed' by the public kernel circuit. | -| `customOutputs` | Up to 32 variables 'returned' by calling this function. All of these inputs will be 'swallowed' by the public kernel circuit. Note, unlike the private circuit ABI (which doesn't have a `customOutputs` field like this), it's possible for public circuit execution to output values which were derived from the current state of the public data tree - such values cannot have been known by the caller of the function, and hence can truly be considered 'outputs'. Note, since the caller won't necessarily known what these outputs will be when they make the call, this entire `customOutputs` field is omitted from the `callStackItemHash` when the user makes the call. | -| `emittedPublicInputs` | Public inputs which may be revealed to L1. E.g. allowing certain inputs to be more-easily extracted by the RollupProcessor contract (rather than having to unpack this vast ABI object of inputs, which would cost too much hash-wise). An example of its usefulness is passing a value from L1 to L2 when doing an L1->L2 tx (see 'deposit' example in the other doc). | -| `emittedOutputs` | As above, except these values won't necessarily be known when the call is made; only when the rollup provider is generating the witness for this function's execution. Note, since the caller won't necessarily known what these outputs will be when they make the call, this entire `customOutputs` field is omitted from the `callStackItemHash` when the user makes the call. | -| `executedCallback: {` | Populated if this circuit is a callback, so that the purported L1 Result to which this circuit is responding can be validated against the l1ResultsTree. | -| `- l1ResultHash`, | If this function is a callback function, following some L1 call, then it needs to expose the `l1ResultHash` to ensure the callback is actually using data emitted by L1. The preimage of the `l1ResultHash` will need to be passed in as private inputs to the circuit. Note: the `l1ResultHash` MUST be computed with a sha256 hash, because that's what the RollupProcessor will have used. This is unfortunate, as it forces apps to adhere to a specific calculation within their circuits. | -| `- l1ResultsTreeLeafIndex`, | Communicates to the rollup provider the correct leaf to prove membership against in the l1ResultsTree. Only if we don't want to hide the callback will the rollup provider perform the membership check (within the Base Rollup Circuit). Otherwise it'll be performed in the Private Kernel Circuit. | -| `}`| -| 256 `stateTransitions` | Describes up to 256 `publicDataTree` read+write operations.
A 'state transition' is expressed as:
`[storageSlot, old_value, new_value]`.
:heavy_exclamation_mark: For state transitions, the caller might not know the `old_value` nor the `new_value` when they make the call (i.e. when they add the call to their callStack), since the value will depend on the current state of the publicDataTree. (Imagine if the storage slot represented total liquidity in some pool which changes frequently. Then the old and new values are only known at the time the rollup processor actually organises the ordering of txs in their block). Conclusion: the `publicInputsHash` which is included in a public call's `callStackItemHash` cannot include the `old_value` nor `new_value` inputs.

Therefore, the `stateTransitions` that are populated by a user and hashed when generating the `callStackItemHash` will have `0`-valued placeholders for `old_value` and `new_value`.

Pure reads can be emulated by setting a new write value to equal the read value. However, for this tree, we could halve the amount of hashing for pure reads by having a separate `reads` set of inputs. A read can be done without a write for this tree (see next field). | -| `stateReads` | Pure reads. Each 'read' request is simply the `[storageSlot, current_value]`. As explained above, the `current_value` won't necessarily be known by the user when they generate the call, so `current_value` is replaced with `0` when the `callStackItemHash` is generated for calls to a public function. | -| `publicCallStack` | additional public calls to be made by this transaction (up to 16) | -| `contractDeploymentCallStack` | additional calls which _deploy contracts_, created by this transaction (up to 1?) | -| `partialL1CallStack` | Additional L1 calls to be made by this transaction (up to 16). "Partial" because the kernel circuit will add the correct portal contract address to 'complete' the call into a proper L1 CallStack Item. See [here](../contracts/l1-calls.md). | -|
callbackStack = [{
  callbackPublicKey,
  successCallbackCallHash,
  failureCallbackCallHash,
  successResultArgMapAcc,
},...]
| An element in the array for each new L1 call on the `partialL1CallStack`. See [more](../contracts/l1-calls.md). We need to expose all of this data so that the kernel snark ensures the callback is a function of the same contract which made the call. | -| `oldPrivateDataTreeRoot` | used to query the `privateDataTree` | -| `proverAddress` | Who is going to be generating the proof for this circuit (any value can be injected here by the prover). :question: IS THIS ALLOWED HERE? It can be allowed here as long as Noir abstracts its existence away from the circuit developer. | -| Booleans: | | -| `bool isFeePayment` | Notifies the rollup provider that this function pays them their fee. The rollup provider will need a way to interpret the many ways it can be paid. :question: Perhaps a fee payment ABI is required for the structure of the `emittedPublicInputs`, for example? | -| `bool payFeeFromL1`| Provides a way of paying for L2 function execution from L1 (the RollupProcessor.sol could provide the interface for ETH or ERC20... but we could generalise this by somehow pointing to a particular 'other' payment L1 contract state?). "Submit on-chain the callHash and state a fee (in L1 currency) for the L2 tx, and then when the L2 tx is executed, the rollup provider may redeem the previously-published fee".

Notifies the kernel circuit that the following public inputs of this public circuit MUST also be revealed by the public kernel circuit:
  • `callHash`
| -| `bool calledFromL1` | If the L1 contract wants to call a specific L2 circuit, then the function signature needs to be revealed on-chain so that it can be checked that the correct, intended function was executed.

Notifies the public kernel circuit that an L1 contract wants to call this specific public L2 circuit, and so the following MUST be revealed by the public kernel circuit:
  • `functionSignature`
  • `callHash`
  • `emittedPublicInputs` (possibly)


We need this convoluted process, because the RollupProcessor has to be _sure_ an L1 fee has been set-aside for them, before they add any corresponding L2 states. | -| Global vars: | | -| `block.timestamp` | aztec block timestamp | -| `block.number` | aztec block number | -| `prevBlock.ethTimestamp` | Ethereum timestamp of block that contained previous Aztec 3 block | -| `prevBlock.ethNumber` | block number of Ethereum block that contained previous Aztec 3 block | +| *`callContext`: [`CallContext`](#callcontext) | Information about what this function used as its call context, so that the kernel circuit may validate that the correct context was indeed used. | +| *`args` | Circuit-specific inputs passed into this circuit. | +| `returnValues` | Values 'returned' by calling this function. Note: it's possible for public circuit execution to output values which were derived from the current state of the public data tree - such values cannot have been known by the caller of the function. Note, since the caller won't necessarily known what these outputs will be when they make the call, this entire `returnValues` field is omitted from the [`PublicCallStackItem`](../contracts/transactions.md#publiccallstackitem) when the user makes the call. | +| `emittedEvents` | Public inputs which may be revealed to L1. E.g. allowing certain inputs to be more-easily extracted by the RollupProcessor contract (rather than having to unpack this vast ABI object of inputs, which would cost too much hash-wise). An example of its usefulness is passing a value from L1 to L2 when doing an L1->L2 tx (see 'deposit' example in the other doc). Note: some of these values won't necessarily be known when the call is made; only when the rollup provider is generating the witness for this function's execution. Note, since the caller won't necessarily know what these outputs will be when they make the call, this entire `emittedEvents` field is omitted from the [`PublicCallStackItem`](../contracts/transactions.md#publiccallstackitem) when the user makes the call. | +| `stateTransitions`: [`Array[StateTransition]`](#statetransition) | Public state changes. | +| `stateReads`: [`Array[StateRead]`](#stateread) | Public state reads. | +| `publicCallStack`: `Array[Field]` | Additional public calls created by this transaction. The `Field` is a hash of a [`PublicCallStackItem`](../contracts/transactions.md#publiccallstackitem). | +| `contractDeploymentCallStack`: `Array[Field]` | Additional calls which _deploy contracts_, created by this transaction. The `Field` is a hash of a [`ContractDeploymentCallStackItem`](../contracts/transactions.md#contractdeploymentcallstackitem). | +| `partialL1CallStack`: `Array[Field]` | Additional calls to L1 created by this transaction. "Partial" because the kernel circuit will add the correct portal contract address to 'complete' the call into a proper L1 CallStack Item. See [here](../contracts/l1-calls.md). The `Field` is a hash of a [`PartialL1CallStackItem`](../contracts/transactions.md#partiall1callstackitem). | +| *`oldPrivateDataTreeRoot`: `Field` | The root that has been used to query the `privateDataTree` | +| *`oldNullifierTreeRoot`: `Field` | The root that has been used to query the `nullifierDataTree` | +| *`oldConstPublicDataTreeRoot`: `Field` | The root that has been used to query the `constPublicDataTree` (if we choose to have one). | +| *`oldContractTreeRoot`: `Field` | The root that has been used to query the `contractTree` | +| *`proverAddress`: `aztecAddress` | Who is going to be generating the proof for this circuit (any value can be injected here by the prover). | -### publicInputsHash -As explained briefly in the table above, for calls to a public circuit, certain inputs are _not_ known when the user makes the call (since their values might depend on the state of the public data tree at the time of proof generation (rather than at the time of making the call)). Therefore, the `publicInputsHash` for public calls is defined as the hash of the above ABI data, _except_ for the following modifications to the preimage: -- `customOutputs` fields are completely omitted from the preimage. -- `emittedOutputs` fields are completely omitted from the preimage. -- Each state transition is truncated to be `storageSlot` (instead of `[storageSlot, old_value, new_value]`). -- Each state read is truncated to be `storageSlot` (instead of `[storageSlot, current_value]`). +**Note**: For calls to a public circuit, certain inputs are _not_ known when the user makes the call (since their values might depend on the state of the public data tree at the time of proof generation (rather than at the time of making the call)). Therefore, the `publicInputs` provided when making public calls (i.e. when creating a [`PublicCallStackItem`](../contracts/transactions.md#publiccallstackitem)) sets-to-0 some of the above data. +- `returnValues` +- `emittedEvents` +- `stateTransitions`' old and new values. +- `stateReads`' current values. +- All call stacks (as the calls could be made based on some dynamic state read of some address, for example) - - - - -## Contract Deployment ABI +# Contract Deployment ABI Recall: Contracts can be deployed to Aztec's Layer 2. A contract comprises: - a set of functions, each encapsulated by a `(vk, proving_key, circuit)` tuple, with the hash of the `vk` being a succinct and unique representation of each function. - state variables, split across these trees: - - `publicDataTree` + - `publicDataTree` (maybe also a const public data tree) - `privateDataTree` A contract deployment ABI, therefore, needs to communicate this information to the rollup provider. -This is the ABI for the public inputs that must be specified when making a call to deploy a new contract. These public inputs will then be hashed into a `publicInputsHash` which will form part of the [`callStackItemHash`](../contracts/transactions.md#callstackitemhash) which will get added to the `contractDeploymentCallStack`. +This is the ABI for the public inputs that must be specified when making a call to deploy a new contract. These public inputs will form part of the [`ContractDeploymentCallStackItem`](../contracts/transactions.md#contractdeploymentcallstackitem) which will get added to the `contractDeploymentCallStack`. **Important note**: Unlike for the above Public Input ABIs for private circuits and public circuits, we don't actually have a 'contract deployment' _circuit_. These public inputs are simply defined so that a callStackItem can be created. These public inputs (and others) are then fed directly into a [Contract Deployment _Kernel_ Circuit](../kernel-circuits/contract-deployment-kernel.md). TODO: we might be able to remove some of these public inputs and provide them privately instead; but such optimisations can happen _much_ later in this project. +PROBLEM: we might wish to _prove_ that a set of ACIR++ opcodes compiles to a particular vkHash. This would be very complex to do inside a circuit, but might be essential. + +## `ContractDeploymentPublicInputs` + | Data Type | Description | | -------- | -------- | | `privateConstructorPublicInputsHash` | So that vested parties (with access to the underlying public inputs) can confirm the constructor was executed with the correct params. Note: a user (or contract) cannot provide a conventional callStackItem to make a call to a private constructor, because the constructor's function signature isn't known until the contract address is known, but the contract address needs to contain the constructor arguments (i.e. the privateConstructorPublicInputsHash), so we'd get a cyclic dependency. | @@ -151,7 +171,7 @@ TODO: we might be able to remove some of these public inputs and provide them pr ## Custom inputs ABI -Circuits have up to 32 custom 'inputs' (and 'outputs' for public circuits). Each Noir data type that is set to be a public input is represented by a single field element (we don't need to do this for private inputs). If the data type is >1 field element, the data is Pedersen hashed. We apply this heuristic recursively for structs and nested data. e.g. for +Circuits have custom 'args' and 'return values'. Each Noir data type that is set to be a public input is represented by a single field element (we don't need to do this for private inputs). If the data type is >1 field element, the data is Pedersen hashed. We apply this heuristic recursively for structs and nested data. e.g. for ``` struct foo { diff --git a/circuits/specs/src/architecture/contracts/deployment.md b/circuits/specs/src/architecture/contracts/deployment.md index 342112c52fb..7b3ba58ddcb 100644 --- a/circuits/specs/src/architecture/contracts/deployment.md +++ b/circuits/specs/src/architecture/contracts/deployment.md @@ -87,7 +87,7 @@ There are 3 options for linking an L2 contract with a portal contract, all with 2. Deploy the L1 portal contract first, tell the Rollup Processor the address, then deploy this L2 contract (providing the L1 address of the portal contract). 3. Deploy this L2 contract, note the deployer’s L1 user address, and allow that same person to later deploy an L1 portal contract and link it with this L2 contract. -Option 1 initially sounds nice and clean, but L1 contract deployment is _expensive_, so just a few portal contract deployments would use all the gas in an L1 block; not leaving enough room for logic to verify the L2 rollup etc. But the most difficult thing about this option would be we'd have to _await_ the success of the Portal Contract deployment attempt on L1 before allowing the L2 contract to be 'finalised', which would need callbacks and painful logic that we'd rather avoid (for contract deployment, at least) if we can. +Option 1 initially sounds nice and clean, but L1 contract deployment is _expensive_, so just a few portal contract deployments would use all the gas in an L1 block; not leaving enough room for logic to verify the L2 rollup etc. But the most difficult thing about this option would be we'd have to _await_ the success of the Portal Contract deployment attempt on L1 before allowing the L2 contract to be 'finalised'. Option 2 is a nice option, although it doesn't allow for deployment of the Portal Contract to be paid-for from the privacy of aztec's L2 - a user would need public Eth to deploy it. diff --git a/circuits/specs/src/architecture/contracts/transactions.md b/circuits/specs/src/architecture/contracts/transactions.md index 90c01b72c3f..0cd7ab1dc40 100644 --- a/circuits/specs/src/architecture/contracts/transactions.md +++ b/circuits/specs/src/architecture/contracts/transactions.md @@ -1,29 +1,88 @@ -# Transactions (Calls) +# Transactions -A transaction begins as a call to a single function[^1]. A function can be uniquely identified (across all contracts) by its [`functionSignature`](#function-signature). A 'call' to a function is expressed through a [`callStackItem`](#call-stacks). During the execution of a transaction, the initial function might make calls to other functions, so callstacks are required. Call stack items are verified recursively. The final kernel snark that is produced by the recursion represents the entire transaction. +A transaction always comes from a user account, and must be signed by that user's aztec private key. A transaction represents a call to some function of some contract, passing some parameters, and specifying some fee. + + + Contracts can be deployed with a special type of call (a contractDeploymentCall). [^1]: Most transactions will likely begin with _two_ callstack items: one for the actual call, and one to pay the rollup provider a fee (by invoking some payment circuit). [Fee payments](../fees/fees.md) still need to be spec'd out. -## Function signature -A private function call is uniquely defined by a 64-bit integer, which we'll call a `functionSignature`: +## `TxObject` + +| Value | Description | +| --- | --- | +| `from`: `aztecAddress` | The aztec address of the user signing the tx. | +| `to`: [`contractAddress`](#contractaddress) | The contract address of the contract being called.
For calls which deploy a contract, this is `0` (context will be understood from the fact this will be popped of a contractDeploymentCallStack).
For calls to private constructors, this is not known when generating the private kernel proof which verifies the private constructor (as the contract won't yet have been assigned an address), so is `0` (in combination with `functionSignature.isConstructor == true`). | +| `functionSignature`: [`FunctionSignature`](#functionsignature) | An identifier for the function being called. | +| `args`: `Array[Field]` | Arguments being passed into the function by this tx. | +| `nonce`: `Field` | Useful for overriding a tx which has already been sent to the pool. Note: for private function calls, this _must not_ be incremented sequentially, but should be random-looking.
`0` if this is a fee-paying tx to accompany a 'proper' tx. | +| `txContext`: [`TxContext`](#txcontext) | Miscellaneous data relating to this tx, which might be useful for all subsequent nested function calls, and kernel circuits of this tx. | +| `chainId`: `Field` | Needed to prevent replay attacks on other rollups (e.g. testnet / devnet).
`0` if this is a fee-paying tx to accompany a 'proper' tx. | -| Num Bits | Description | +## `ContractAddress` + +| Value | Description | | --- | --- | -| 0-31 (32-bits) | `contractAddress` | The contract address being called.
For calls which deploy a contract, this is `0` (context will be understood from the fact this will be popped of a contractDeploymentCallStack).
For calls to private constructors, this is not known when generating the private kernel proof which verifies the private constructor, so is `0` (in combination with `isConstructor`). | -| 32-60 (29-bits) | `vkIndex` - the position of the vk (i.e. its leaf index) in this contract's `vkTree` (this defines the function being called) | -| 61 (1-bit) | `isPrivate` - A bit describing if this function is public or private.

:question: Is this needed? Perhaps the differences in private/public ABIs is sufficient to cause a circuit to fail if passed the wrong proof type? Or, maybe the vk tree could be arranged in a way which clearly separates public/private vks. | -| 62 (1-bit) | `isConstructor` - If a function is a constructor, it's going to be called by the Contract Deployment Kernel circuit. This flag notifies the kernel circuit that this private circuit is being executed as a constructor for the deployment of a new contract, and so the following public inputs of this private circuit MUST be revealed to the public kernel circuit (so that the Contract Deployment kernel circuit may validate them):
  • `callStackItemHash` - so that the Contract Deployment kernel circuit (and interested parties) can be convinced that the constructor was run with the correct set of inputs (this might need to exposed all the way to L1)
  • `vkHash` - so that the Contract Deplyment constructor can validate that the correct function was executed. (Notice, we don't use a conventional `functionSignature` because we won't be adding constructor vkHashes to the vkTree). Notice, by design, this doesn't reveal any details to observers about the nature of the executed function. We might want to optionally allow the underlying vk to be broadcast (and hence we might need to expose this vkHash all the way to L1).
  • `emittedPublicInputs` - to pass particular inputs to L1.

Special note: this `isConstructor` flag is not part of the private circuit's ABI (as it potentially could have been), because the checks in the contract deployment kernel circuit are much cheaper if it's accessible here. | -| 63 (1-bit) | `isCallback` - Tells the kernel circuit that this function is being executed as a callback from an earlier L2 --> L1 call. | +| `contractAddress`: `Field` | See [here](deployment.md#l2-contract-address) for contract address derivation. | + +## `FunctionSignature` +| Value | Description | +| --- | --- | +| `vkIndex`: `Field` | The position of the vk (i.e. its leaf index) in this contract's `vkTree`. This is used to identify the function being called. It is derived as the first 4 bytes of the hash of the abi encoding of the function, similar to Solidity. The reason we do this, is so that a vkIndex can be derived from a contract interface, regardless of the ordering of that interface's functions. | +| `isPrivate`: `Bool` | A bit describing if this function is public or private. | +| `isConstructor`: `Bool` | If a function is a constructor, it's going to be called by the Contract Deployment Kernel circuit. This flag notifies the kernel circuit that this private circuit is being executed as a constructor for the deployment of a new contract, and so the following public inputs of this private circuit MUST be revealed to the public kernel circuit (so that the Contract Deployment kernel circuit may validate them):
  • `callStackItemHash` - so that the Contract Deployment kernel circuit (and interested parties) can be convinced that the constructor was run with the correct set of inputs (this might need to exposed all the way to L1)
  • `vkHash` - so that the Contract Deplyment constructor can validate that the correct function was executed. (Notice, we don't use a conventional `functionSignature` because we won't be adding constructor vkHashes to the vkTree). Notice, by design, this doesn't reveal any details to observers about the nature of the executed function. We might want to optionally allow the underlying vk to be broadcast (and hence we might need to expose this vkHash all the way to L1).
  • `emittedPublicInputs` - to pass particular inputs to L1.
| -_Note_: the `contractTree` is append-only, so individual verification keys can't be 'replaced' for bug-fixes etc.; the entire contract (a `vkTree`) would need to be re-deployed to the next available slot in the `contractTree`. Such re-deployments, of course, would change the contract address. + +_Note_: the `contractTree` is append-only, so individual verification keys can't be 'replaced' for bug-fixes etc.; the entire contract (a `vkTree`) would need to be re-deployed to the next available slot in the `contractTree`. Such re-deployments, of course, would change the contract address, unless using a proxy pattern. + + +## `FeeData` + +Currently, the fee model is inspired by EIP-1559. + +| Value | Description | +| --- | --- | +| `maxPriorityFeePerAztecGas`: `Field` | | +| `maxFeePerAztecGas`: `Field` | | +| `aztecGasLimit`: `Field` | | +| `maxPriorityFeePerEthGas`: `Field` | | +| `maxFeePerEthGas`: `Field` | | +| `ethGasLimit`: `Field` | | +| `payFeePrivately`: `Bool` | | +| `payFeeFromL1`: `Bool` | Provides a way of paying for private L2 function execution from L1 (the RollupProcessor.sol could provide the interface for ETH or ERC20... but we could generalise this by somehow pointing to a particular 'other' payment L1 contract state?). "Submit on-chain the callHash and state a fee (in L1 currency) for the L2 tx, and then when the L2 tx is executed, the rollup provider may redeem the previously-published fee".

Notifies the kernel circuit that the following public inputs of this private circuit MUST be revealed to the public kernel circuit:
  • `callHash` - no other data is needed (in order to allow the user to keep the function they've actually executed private).
| +| `payFeeFromPublicL2`: `Bool` | Provides a way of paying for private L2 function execution from a public L2 circuit. This input being `true` will cause the rollup provider to look for an `isFeePayment` tx in the _public_ callStack. | +| `feeAmount`: `Field` | | +| `feeStandardId`: `Field` | | +| `signedFeePaymentTxHash`: `Field` | Hash of a [SignedTxObject](#signedtxobject) | + + +## `TxContext` + +| Value | Description | +| --- | --- | +| `calledFromL1`: `Bool` | Is this tx being sent as a continuation of some L1 tx which made a call to L2? If the L1 contract wants to call a specific L2 circuit, then the function signature needs to be revealed on-chain so that it can be checked that the correct, intended function was executed.

Notifies the private kernel circuit that an L1 contract wants to call this specific private L2 circuit, and so the following MUST be revealed to the public kernel circuit:
  • `functionSignature` - needed so the L1 contract can confirm the intended function was executed on L2. Although a callHash contains the functionSignature, the L1 contract wouldn't (cheaply) be able to unpack the callHash. So we expose the function signature as well to keep costs down. Although this leaks the function which was called, there's no way around that; this is an L1 -> L2 call after all.
  • `callHash` - used as a 'lookup' key. The RollupProcessor will store this `callHash`, and await an L2 tx with this `callHash` before triggering a callback to the L1 contract which made this L1 -> L2 call in the first place.
  • `emittedPublicInputs` - needed so that a set of values can be emitted by an L2 function and exposed to L1. It would be too expensive to unpack the callHash and extract all of the custom public inputs of a circuit. This is much cheaper, and is very similar to how the EVM exposes only a few values (via event emissions) to JavaScript (for example).


We need this convoluted process, because the RollupProcessor has to be _sure_ an L1 fee has been set-aside for them, before they add any corresponding L2 states. | +| `calledFromPublicL2`: `Bool` | Is this tx being sent as a continuation of some public L2 tx which made a call to Private L2? | +| `isCallback`: `Bool` | Is this tx being sent as a continuation of some L2 --> L1 call, which now needs to continue L2 execution? | +| `resultsTreeLeafIndex`: `Field` | Not sure if we want this or some kind of tx hash. If executing a callback, the user/dapp needs to feed-in info about the original call they made, so that the Private Client can find the right results tree leaf to use. | +| `isFeePaymentTx`: `Bool` | Is this tx the 'fee payment' component of some other tx? Notifies the kernel circuit that the following public inputs of this private circuit MUST be revealed to the public kernel circuit:
  • `functionSignature` - so that the rollup provider can see how they're to be paid
  • `emittedPublicInputs` - so that the rollup provider can validate the amount they'll be paid (they'll need to be provided with the underlying public inputs separately, to validate the hash).
| +| `feeData`: [`FeeData`](#feedata) | Empty if `isFeePaymentTx == false`. Conveys information about the fee being paid for this tx. | +| `referenceRollupNum`: `Field` | The rollup number which should be used if referring to any historic tree values. Useful if the proof needs to use a particular tree state snapshot of a particular historic rollup. | + + +## `SignedTxObject` + +| Value | Description | +| --- | --- | +| `txObject`: [`TxObject`](#txobject) | The TxObject being signed over. | +| r, s, v | The usual ecdsa signature values. | --- -## Call Stacks +# Call Stacks To fully define how Aztec 3 implements call semantics, we start by defining 4 call stack data structures. @@ -32,20 +91,28 @@ A call stack is a vector where each entry describes a transaction that is yet to There are 4 call stack types in the Aztec 3 architecture: public calls, private calls, L1 calls (see [earlier](./function-types.md) for details of those 3), and [contract deployment](./deployment.md) calls. -### Structure of a call stack item +## Structure of a call stack item + +A call stack item represents a call which has been made by a function during execution of a tx. It is formatted this way so as to be read by a kernel circuit. + +The format varies, depending on the type of call being made. + + +### `PrivateCallStackItem` + +| Data | Description | +| -------- | -------- | +| `contractAddress`: [`ContractAddress`](#contractaddress) | The address of the contract being called. | +| `functionSignature`: [`FunctionSignature`](#functionsignature) | The 'function signature' of the circuit being called. | +| `publicInputs`: [`PrivateCircuitPublicInputs`](../app-circuits/public-input-abis.md#privatecircuitpublicinputs) | The public inputs of the call, which can be calculated in advanced through simulation. | -A call stack item contains the following witnesses: +### `PublicCallStackItem` | Data | Description | | -------- | -------- | -| `functionSignature` | The 'function signature' of the circuit being called. I.e. `concat(contractAddress, vkIndex, isPrivate)` (see earlier) | -| `publicInputsHash` | The public inputs of the call (represented as a pedersen hash. Preimage provided as auxiliary data. When a call stack item is processed, the preimage is unpacked).

Note: for the public circuit ABI, _not all_ public inputs are hashed to form this `publicInputsHash`, since variables read/written from/to the publicDataTree are not known at the time the call is made by the user (or by another circuit). See the Public Circuit ABI section. | -| `callContext: {` | 'Object' for distinguishing between `call` and `delegateCall` | -| ` - msgSender,` | - If doing a `call` or `staticCall`: Either the user address or the address of the contract that created the call. (Can be set to `0` for private -> public calls)
- If doing a `delegateCall`: the address of the calling contract's own `callContext.msgSender` (since delegate calls can be chained). | -| ` - storageContractAddress,` | - If doing a `call` or `staticCall`: the address of the contract being called.
- If doing a `delegateCall`: the address of the calling contract's own `callContext.storageContractAddress` (since delegate calls can be chained). | -| `}` | | -| `bool isDelegateCall` | Used by the kernel snark to validate that the `callContext` of newly-pushed `callStackItems` is consistent with the contract making the call. | -| `bool isStaticCall` | Informs the kernel snark that it MUST fail if the function being called modifies state.

A state modification includes: creating a new contract; emitting events; writing to trees; making a 'call' to another contract. :question: Not sure why 'delegatecall' is not included as a potentially state-modifying tx in ethereum specs?

Note: static calls to private circuits might not make sense. 'Reads' from the privateDataTree require a write of equal value, but the kernel snark cannot 'see' what has been written (it's a private tx), and so cannot validate that a state change didn't take place. So there would be no output commitments or nullifiers for a private static call. But a private call's only use is (I think :question:) to read/modify private state. So I'm thinking a staticCall to a private circuit doesn't make sense. | +| `contractAddress`: [`ContractAddress`](#contractaddress) | The address of the contract being called. | +| `functionSignature`: [`FunctionSignature`](#functionsignature) | The 'function signature' of the circuit being called. | +| `publicInputs`: [`PublicCircuitPublicInputs`](../app-circuits/public-input-abis.md#publiccircuitpublicinputs) | The public inputs of the call, which can be calculated in advanced through simulation.
**Note:** for the public circuit ABI, _not all_ public inputs can be included in `publicInputs`, since variables read/written from/to the publicDataTree are not known at the time the call is made by the user (or by another circuit). See the Public Circuit ABI section. | > Note: A `proof` is not included in the call stack item. For public calls, the proof is not known at the time the call is made, because public proofs are generated by the rollup provider. For private calls, the proof isn't needed for a call stack item to be unique; the input nullifiers and output commitments ensure uniqueness of calls. :question: Q: is a private call which doesn't read/modify state nonsensical (if so, that's good - we can reject such calls (they won't have any nullifiers or commitments), thereby ensuring uniqueness of private callStack items)? @@ -55,30 +122,16 @@ A call stack item contains the following witnesses: > Note: The `contractAddress` is sometimes set to `0` in the `functionSignature` if a function is calling another function of the same contract. (Functions cannot know their own contract address, since it is set after the function's circuit has been compiled). The kernel circuits are capable of interpreting this. Examples of a function calling another function of the same contract are: a private-to-public call; and a call to a callback function. - -#### `callStackItemHash` -`callStackItemHash := hash(functionSignature, publicInputsHash, callContext, etc.)` -a.k.a. `callHash` - similar to Ethereum's notion of a txHash. - -We also use the term `callbackCallHash` to refer to the `callHash` of a callback function (which has certain public inputs omitted when calculating the call stack item). - -Having a single value for each item on the stack (a hash) makes thinking about the callstack easier. - -#### Contract Deployment call stack item +### `ContractDeploymentCallStackItem` An instruction to deploy a contract is also expressed through a call, but the call stack item's data is slightly abbreviated (no function signature): | Data | Description | | -------- | -------- | -| `publicInputsHash` | The public inputs of the call (represented as a pedersen hash. Preimage provided as auxiliary data. When a call stack item is processed, the preimage is unpacked). | -| `callContext: {` | 'Object' for distinguishing between `call` and `delegateCall`. :question: Not sure if we need this for a contract deployment? | -| ` - msgSender,` | | -| ` - storageContractAddress,` | | -| `}` | | -| `bool isDelegateCall` | | -| `bool isStaticCall` | | +| `publicInputs`: [`ContractDeploymentPublicInputs`](../app-circuits/public-input-abis.md#contractdeploymentpublicinputs) | The public inputs of this call. | -### L1 callstack items + +### `L1CallstackItem` An L1 callstack item is a call to L1. So it's the Ethereum-defined tuple (functionSelector, argument encoding). See [here](https://docs.soliditylang.org/en/v0.8.11/abi-spec.html#function-selector-and-argument-encoding). @@ -96,6 +149,26 @@ So: - We don't do this within the app-specific circuit to save on expensive keccak hashing (since the kernel has to do a portal contract address check, so needs to do this hashing already). +### `CallbackStackItem` + +When a function makes a call to another 'layer', it can specify a success or failure callback. By the end of recursing through many calls, a kernel circuit might need to keep track of multiple callbacks that have been requested by many circuits. See [more here](./l1-calls.md), for info on the contents of this table. + +| Data | Description | +| -------- | -------- | +| `callbackPublicKey`: `Point` | The public inputs of this call. | +| `successCallbackCallHash`: `Field` | | +| `failureCallbackCallHash`: `Field` | | +| `successResultArgMapAcc`: `Field` | | + + +#### `callStackItemHash` +`callStackItemHash := hash(functionSignature, publicInputsHash, callContext, etc.)` +a.k.a. `callHash` - similar to Ethereum's notion of a txHash. + +We also use the term `callbackCallHash` to refer to the `callHash` of a callback function (which has certain public inputs omitted when calculating the call stack item). + +Having a single value for each item on the stack (a hash) makes thinking about the callstack easier. + ### Passing inputs between functions Brief explanation of passing inputs between functions: diff --git a/circuits/specs/src/architecture/kernel-circuits/contract-deployment-kernel.md b/circuits/specs/src/architecture/kernel-circuits/contract-deployment-kernel.md index ff06e59ab0d..5fbe14b3435 100644 --- a/circuits/specs/src/architecture/kernel-circuits/contract-deployment-kernel.md +++ b/circuits/specs/src/architecture/kernel-circuits/contract-deployment-kernel.md @@ -1,5 +1,9 @@ # Contract Deployment Kernel Circuit + +**NOTE: this section is out of date (naming and architecture), given recent conversations.** + + Notice, that this is a _kernel_ circuit. That's because this circuit will itself verify a private &or public kernel snark representing the new contract's 'constructors'. Unlike the other two (private & public) kernel snarks though, Contract Deployment Kernel Circuits can be called by users and/or functions, meaning they have a callStack of their own which can be pushed-to. The Contract Deployment call stack will be processed at the very end of the kernel chain; after the private and public kernels have been executed. You'll notice that the private/public inputs for this kernel circuit are a superset of the inputs of both the private & public kernel circuits. That's because contract deployments are processed at the very end of a tx, so all other data needs to 'pass through' this circuit. diff --git a/circuits/specs/src/architecture/kernel-circuits/kernel-circuits.md b/circuits/specs/src/architecture/kernel-circuits/kernel-circuits.md index 124ef179cdb..2944e9f2021 100644 --- a/circuits/specs/src/architecture/kernel-circuits/kernel-circuits.md +++ b/circuits/specs/src/architecture/kernel-circuits/kernel-circuits.md @@ -4,7 +4,7 @@ Kernel circuits are used to validate the correctness of a private or public tran There are 3 Kernel circuits: - private kernel circuit -- public kernel circuit +- public kernel circuit (Note: this is outdated and will need to become a VM). - contract deployment kernel circuit Private kernel circuit proofs are generated by the client (transaction sender). Public & Contract Deployment kernel circuit proofs are generated by the rollup provider. diff --git a/circuits/specs/src/architecture/kernel-circuits/private-kernel.md b/circuits/specs/src/architecture/kernel-circuits/private-kernel.md index c9a29302a21..51a140000b8 100644 --- a/circuits/specs/src/architecture/kernel-circuits/private-kernel.md +++ b/circuits/specs/src/architecture/kernel-circuits/private-kernel.md @@ -1,203 +1,172 @@ # Private Kernel Circuit -## Private inputs ABI +# Private inputs ABI -| Data Type | Description | +## `PreviousKernelData` + +| Value | Description | +| -------- | -------- | +| `publicInputs`: [`PrivateKernelPublicInputs`](#privatekernelpublicinputs) | The public inputs from the previous iteration of the kernel snark, to be verified within this iteration. | +| `proof`: `Proof` | The previous kernel snark's proof. | +| `vk`: `VerificationKey` | The vk that should be used when verifying the previous kernel snark. | +| `privateKernelVKTreeRoot`: `Field` | To allow multiple sizes and permutations of kernel circuits, we can put their vks as leaves in a big tree. We can then perform a membership check to ensure the vk is from an approved kernel circuit. | +| `vkIndex`: `Field` | The index of the kernel circuit's vk within the private kernel vk tree. | +| `vkPath`: `Array[Field]` | Part of the membership proof of the kernel circuit's vk within the private kernel vk tree. | + +## `PrivateCallData` + +| Value | Description | +| -------- | -------- | +| `callStackItem`: [`PrivateCallStackItem`](../contracts/transactions.md#privatecallstackitem) | Unpacked data relating to the next private callstack item that we're going to pop off the callstack and verify within this snark. | +| `proof`: `Proof` | The proof for this item of the callstack. We'll be verifying this within this kernel circuit. | +| `vk`: `VerificationKey` | The full verification key of the private call proof that will be verified within this circuit. | +| `vkPath`: `Array[Field]` | The sibling path of the `vk`'s `vkHash` within the aztec contract's 'mini merkle tree'. Note, the `vkIndex` to use when proving membership can be grabbed from the `callStackItem`. | +| `oldContractTreeRoot`: `Field` | The root of the contract tree which the kernel circuit may use to validate the existence of this contract. | +| `contractLeafIndex`: `Field` | The leaf index of the contracts tree where this contract's vkTree is stored | +| `contractPath` | The sibling path from this contract's root (a leaf of the contract tree) to the `oldContractTreeRoot` | +| `portalContractAddress` | The portal contract address that corresponds to the contract of the function being called. | + +## `PrivateKernelPrivateInputs` + +| Value | Description | +| -------- | -------- | +| `signedTxObject`: [`SignedTxObject`](../contracts/transactions.md#signedtxobject) | Only required to validate permissions for the first call in the callstack. TODO: generalise for account abstraction. | +| `previousKernel`: [`PreviousKernelData`](#previouskerneldata) | Previous kernel data (empty if this is the first iteration). | +| `privateCall`: [`PrivateCallData`](#privatecalldata) | Details about the next call which will be popped of the callstack during this kernel recursion. | + + +# Public inputs ABI + +## `AggregationObject` + +A barrretenberg object. Might change in future. Don't worry about this too much. + +| Value | Description | +| -------- | -------- | +| `P0`: `Point` | | +| `P1`: `Point` | | +| `publicInputs` | | +| `proofWitnessIndices` | | + +## `OptionallyRevealedData` + +Some values from a private call can be optionally revealed to the 'public world', depending on the function and its [`TxContext`](../contracts/transactions.md#txcontext). For some/every private call we have the following fields (some of which might be 0). (Note: there might be more efficient ways to encode this data - this is just for illustration): + +| Value | Description | | -------- | -------- | -| `signature` | ECDSA signature (where `message = publicInputsHash`) signed by the user (if `start.privateCallCount == 0`, otherwise empty) | -| `start: {` | | -| `- aggregatedProof` | The current aggregated proof state (if any) | -| `- privateCallCount` | How many calls have been recursively executed so far? | -| `- privateCallStack` | Starting state of private call stack (max depth 64) | -| `- publicCallStack` | Starting state of public call stack (max depth 64) | -| `- contractDeploymentCallStack` | Output state of contract deployment call stack (max depth 4?) | -| `- l1CallStack` | Starting state of L1 call stack (max depth 64?) | -| `- callbackStack` | See breakdown in the public inputs ABI in the next table | -| `- optionallyRevealedData` | See breakdown in the public inputs ABI in the next table | -| `- outputCommitments` | Starting state of commitments to be added to `privateDataTree` | -| `- inputNullifiers` | Starting state of nullifiers to be added to `nullifierTree` (up to 64) | -| `},` | | -| `previousKernel: {` | | -| `- proof` | Previous Kernel snark proof (if any). | -|
- publicInputs = {
  end: start, // copy within circuit.
  constants: {
    oldTreeRoots: {
      privateDataTree,
      contractTree,
    },
    privateKernelVKTreeRoot,
    isConstructorRecursion,
    isCallbackRecursion,
    executedCallback: {
      l1ResultHash,
      l1ResultsTreeLeafIndex,
    },
    globals: {
      minTimestamp,
    },
  }
  isPrivate,
  isPublic,
  isContractDeployment,
}
| The first Kernel Circuit execution can have `previousKernel.proof = 0` (or equivalent). | -| `- vk` | The VK that should be used to verify the `previousKernel.proof`. | -| `- vkIndex` | The leaf index to accompany the `previousKernel.vkPath`. | -| `- vkPath` | We can support multiple 'sizes' of kernel circuit (i.e. kernel circuits with varying numbers of public inputs) if we store all of the VKs of such circuits as vkHashes in a little Merkle tree. This path is the sibling path from the `previousKernel.vk`'s leaf to the root of such a tree. | -| `}` | | -| `privateCall: {` | Data relating to the next private callstack item that we're going to pop off the callstack and verify within this snark. Recall we're representing items in the callstack as a `callStackItemHash`. We'll pass the unpacked data here, for validation within this kernel circuit. | -| `- functionSignature,` | 64-bits (see earlier section) | -| `- publicInputs: {...},` | Rather than pass in the `publicInputsHash`, we pass in its preimage here (we'll hash it within this kernel circuit). This is _all_ of the data listed in the Private Circuit ABI's table of public inputs (see earlier section). | -| `- callContext: {...},` | | -| `- isDelegateCall` | | -| `- isStaticCall` | | -| `- proof` | The proof for this item of the callstack. We'll be verifying this within this kernel circuit. | -| `- vk` | The full verification key of the private call proof that will be verified within this circuit. (I.e. the proof `start.privateCallStack.pop().proof`) | -| `- vkPath` | The sibling path of the `vk`'s `vkHash` within the aztec contract's 'mini merkle tree'. Note, the `vkIndex` to use when proving membership can be grabbed from the `privateCall` being executed (which itself is popped off the callstack). | -| `- portalContractAddress` | The portal contract address that corresponds to the contract of the function being called (`privateCall`). | -| `- contractLeafIndex` | The leaf index of the contracts tree where this contract's vkTree is stored | -| `- contractPath` | The sibling path from this contract's root (a leaf of the contract tree) to the `oldContractTreeRoot` | -| `- privatelyExecutedCallback: {` | Only populated (if at all) by the first call in a tx, if that call is a callback. This gives details of the callback that's been executed, so the callback and result can be cross-checked against the l1ResultsTree within this private kernel circuit. It's checked within the private kernel circuit so that the fact that this callback has even been executed can be hidden. | -| `- - l1SuccessResultValues`, | The results of an L1 interaction. These underlying result values will be reconciled against this `privateCall.publicInputs.executedCallback.l1ResultHash` | -| `- - l1SuccessResultArgPositions`, | An array which details how the L1 Results array gets mapped to the argument positions of the callback function. This will be checked within this circuit whether these values 'accumulate' to give the `successResultArgMapAcc`. The format can be cumbersome, if it saves on constraints, since this is a private input. | -| `- - l1ResultsTreeSiblingPath`, | The leafIndex is a public input of the privateCall itself. | -|
-  - callbackStackItem: {
callbackPublicKey,
successCallbackHash,
failureCallbackHash,
successResultArgMapAcc
- - } | | -| `- - callbackPrivateKey`, | | -| `- },` | | -| `}` | | - -## Public inputs ABI - -| Data type | Description | +| `callStackItemHash`: `Field` | Serves as a 'lookup key' of sorts, for when an L1 function has made a call to a L2 function, and will need to validate that the correct call was made. | +| `functionSignature`: [`FunctionSignature`](../contracts/transactions.md#functionsignature) | | +| `emittedEvents` | Emitting data to another layer. | +| `vkHash` | | +| `portalContractAddress` | Needed when making a call from L2 to L1. | + +## `AccumulatedData` + +The end state of a kernel recursion. It can be used as the 'start' state of the next kernel recursion. + +| Value | Description | +| -------- | -------- | +| `aggregationObject`: [`AggregationObject`](#aggregationobject) | A representation of the aggregation of all proofs so far in the recursion. | +| `privateCallCount`: `Field` | How many calls have been recursively executedso far? | +| `newCommitments`: `Array[Field]` | A list of all commitments created by all circuits recursed-through so far. | +| `newNullifiers`: `Array[Field]` | A list of all nullifiers created by all circuits recursed-through so far. | +| `privateCallStack`: `Array[Field]` | A call stack containing any calls made by all of the circuits previously recursed-through, which haven't-yet been popped off this stack. | +| `publicCallStack`: `Array[Field]` | " | +| `contractDeploymentCallStack`: `Array[Field]` | " | +| `l1CallStack`: [`Array[L1CallstackItem]`](../contracts/transactions.md#l1callstackitem) | " | +| `optionallyRevealedData`: [`Array[OptionallyRevealedData]`](#optionallyrevealeddata) | | + + +## `OldTreeRoots` + +| Value | Description | +| -------- | -------- | +| `privateDataTreeRoot`: `Field` | | +| `constPublicDataTreeRoot`: `Field` | (maybe) | +| `nullifierTreeRoot`: `Field` | | +| `contractTreeRoot`: `Field` | | +| `resultsTreeRoot`: `Field` | | +| `privateKernelVKTreeRoot`: `Field` | | + +## `RecursionContext` + +Contains many of the same values as [`TxContext`](../contracts/transactions.md#txcontext), but with some extra info thrown in. TODO: some of this data might need to be 'swallowed' by the last kernel recursion, and only some of the data optionally revealed, via [`OptionallyRevealedData`](#optionallyrevealeddata). + +| Value | Description | +| -------- | -------- | +| `calledFromL1`: `Field` | | +| `calledFromPublicL2`: `Field` | | +| `isConstructor`: `Bool` | | +| `isFeePaymentTx`: `Bool` | | +| `feeData`: [`FeeData`](../contracts/transactions.md#feedata) | | +| `referenceBlockNum`: `Field` | | +| `referenceTimestamp`: `Field` | | + +## `ConstantData` + +| Value | Description | +| -------- | -------- | +| `oldTreeeRoots`: [`OldTreeRoots`](#oldtreeroots) | | +| `recursionContext`: [`RecursionContext`](#recursioncontext) | | + +## `PrivateKernelPublicInputs` + +| Value | Description | | --- | --- | -| `end: {` | | -| `- aggregatedProof,` | Output aggregated proof | -| `- privateCallCount,` | How many calls have been recursively executed at end of circuit execution? (either `start.privateCallCount + 1` or `0` iff `endPrivateCallStack` is empty | -| `- privateCallStack,` | Output state of private call stack (max depth 64) | -| `- publicCallStack,` | Output state of public call stack (max depth 64) | -| `- contractDeploymentCallStack` | Output state of contract deployment call stack (max depth 4?) | -| `- l1CallStack,` | Output state of l1 call stack (max depth 64?) | -| `- callbackStack: [{` | Data to add to the `l1ResultsTree`. See [here](../contracts/l1-calls.md) | -| `- - callbackPublicKey` | | -| `- - successCallbackCallHash,` | of the callback function to execute upon success of the L1 call. | -| `- - failureCallbackCallHash` | of the callback function to execute upon failure of the L1 call. | -| `- - successResultArgMapAcc` | See [here](../contracts/l1-calls.md#successresultargmapacc). | -| `}],` | | -| `- optionallyRevealedData: [{` | Some values from a private call can be optionally revealed to the 'public world', depending on bools of the private circuit ABI. For some/every private call each 'object' in this 'array' contains the following fields (some of which might be 0, depending on the bools) (note: there might be more efficient ways to encode this data - this is just for illustration): | -| `- - callStackItemHash,` | Serves as a 'lookup key' of sorts. | -| `- - functionSignature,` | | -| `- - emittedPublicInputs: [_, _, _, _],` | | -| `- - vkHash,` | | -| `- - portalContractAddress,` | | -| `- - ` | :question: Discussion needed. We might also need to reveal all the bools to the public kernel snark, so that it may filter out data that doesn't need to be revealed to L1. | -| `- }, ...]` | | -| `- outputCommitments,` | Output state of commitments to be added to `privateDataTree` (up to 64) | -| `- inputNullifiers,` | Output state of nullifiers to be added to `nullifierTree` (up to 64) | -| `},` | | -| `constants: {` | | -| `- oldTreeRoots: {` | | -| `- - privateDataTree,` | must equal value used in private call proof | -| `- - contractTree,` | A recent root of the contract tree (for vk membership checks) | -| `- - l1ResultsTree,` | A recent root of the L1 results tree. This MUST always be populated (even though it's only used when `privatelyExecutedCallback` is nonempty) to hide whether or not this is a callback. To enforce this, the correctness of this value (even if it's unused within thie circui) will be checked by the base rollup circuit. | -| `- },` | | -| `- privateKernelVKTreeRoot` | The root of a little Merkle tree whose leaves are hashes of the private kernel circuit VKs, allowing support for multuple 'sizes' of kernel circuit (i.e. with varying numbers of public inputs) | -| `- isConstructorRecursion`, | Flags whether this entire recursion began with a constructor function. | -| `- isCallbackRecursion`, | Flags whether this entire recursion began with a callback function. | -| `- executedCallback: {` | Only populated (if at all) by the first call in a tx, if that call is a callback AND if the callback's execution doesn't want to be 'hidden' :question: WHY WOULD WE EVER WANT THIS CASE?. This gives details of the callback that's been executed, so the callback and result can be cross-checked against the l1ResultsTree eventually in the Base Rollup Circuit.
We assume the rollup provider will have a record of the contents of each leaf of the l1ResultsTree, so we don't need to provide the data here; the rollup provider can pass it as a private input to the Base Rollup snark. | -| `- - l1ResultHash`, | This will eventually be compared against a leaf of the L1 Callback Tree in the Base Rollup Circuit. | -| `- - l1ResultsTreeLeafIndex`, | Communicates to the rollup provider the correct leaf to prove membership against in the l1ResultsTree. This will eventually be used to lookup a leaf of the L1 Callback Tree in the Base Rollup Circuit. | -| `- },` | | -| `- globals: {` | | -| `- - minTimestamp` | must equal value used in private call proof | -| `- }` | | -| `}` | | -| `isPrivate = true` | Bool. Tells the next kernel circuit that this is a private kernel snark. | -| `isPublic = false` | Bool. Tells the next kernel circuit that this is not a public kernel snark. | -| `isContractDeployment = false` | Bool. Tells the next kernel circuit that this is not a contract deployment kernel snark. | +| `end`: `AccumulatedData` | | +| `constants`: [`ConstantData`](#constantdata) | Data which will not change between kernel recursions. | +| `kernelType`: `Enum[private, public, contract_deployment]` | | ## Execution Logic - `require(previousKernel.publicInputs.isPublic == false && previousKernel.publicInputs.isContractDeployment == false)` -TODO: less nesting! (Or, in practice, we'll modularise this all into neat functions). +In practice, we'll modularise this all into neat functions when we actually write the code. Base case: +* Let `start := previousKernelData.publicInputs.end` * if `start.privateCallCount == 0`: - * Require previous kernel data to be empty. Can't do this - the `verify_proof()` function needs a valid dummy proof and vk to verify. + * Require previous kernel data to be empty. (Note: bear in mind - the `verify_proof()` function needs a valid dummy proof and vk to complete execution). * Validate that `start.privateCallStack.length == 1 && start.publicCallStack.length == 0 && start.contractDeploymentCallStack.length == 0 && start.l1CallStack.length == 0` - - TBD: to allow the option of a fee payment, we might require `start.privateCallStack.length` to be "1" or "2, where one tx has an `isFeePayment` indicator". We could even allow any number of initial private calls on the stack, but that's a pretty big deviation from the ethereum tx model. + - TBD: to allow the option of a fee payment, we might require `start.privateCallStack.length` to be "1" or "2, where one tx has an `isFeePayment` indicator". * Pop the only (TBD) `privateCallHash` off the `start.privateCallStack`. - - If `privateCall.functionSignature.isConstructor == true`: + - Validate that `hash(privateCall.callStackItem) == privateCallHash` + - If `privateCall.callStackItem.functionSignature.isConstructor == true`: - then we don't need a signature from the user, since this entire 'callstack' has been instantiated by a Contract Deployment kernel snark (which itself will have been signed by the user). - - Set `constants.isConstructorRecursion := true` - This public input will percolate to, and be checked by. the Contract Deployment Kernel Circuit which calls this constructor. This check is required to prevent a person from circumventing the ECDSA signature check by simply setting `isConstructor = true` when making a private call. If this aggregated kernel snark reaches the rollup circuit without this flag being reset to `false` by the Contract Deployment Kernel Circuit (to say "yes, this kernel was indeed a constructor for a Contract Deployment Kernel Circuit"), then the entire tx will be rejected by the rollup circuit. + - Set `constants.recursionContext.isConstructor := true` - This public input will percolate to -- and be checked by -- the Contract Deployment Kernel Circuit which calls this constructor. This check is required to prevent a person from circumventing the ECDSA signature check by simply setting `isConstructor = true` when making a private call. If this aggregated kernel snark reaches the rollup circuit without this flag being reset to `false` by the Contract Deployment Kernel Circuit (to say "yes, this kernel was indeed a constructor for a Contract Deployment Kernel Circuit"), then the entire tx will be rejected by the rollup circuit. - Else: - - Set `constants.isConstructorRecursion := false` - - Verify the ECDSA `signature`, with `message := privateCallHash` and `signer := privateCall.callContext.msgSender`. + - Set `constants.recursionContext.isConstructor := false` + - Verify the ECDSA signature contained in `signedTxObject`. - Validate the `callContext`. Usually the correctness of a callContext is checked between the `privateCall` and all the new calls it makes (see later in this logic). That means for this 'Base case', those checks haven't been done for this `privateCall` (since there was no prior iteration of this kernel circuit to make those checks). - If `privateCall.isDelegateCall == true || privateCall.isStaticCall == true`: - Revert - a user cannot make a delegateCall or staticCall. - Else: - - Assert `privateCall.callContext.storageContractAddress == privateCall.functionSignature.contractAddress` - - If `privateCall.functionSignature.isCallback == true`: - - Set `constants.isCallbackRecursion = true;` - this can only be set in the _first_ call of a recursion. - - We can infer whether the user wants to keep this callback's execution private, or if they want to expose it, from the `privatelyExecutedCallback` private inputs: - - If `privatelyExecutedCallback` is zeroes, then the user doesn't want to execute this callback privately (maybe it interacts with some public state tree data). - - Let `exposeCallback := true;` - - Copy over the `privateCall.publicInputs.executedCallback` data to this snark's output: `constants.executedCallback`. - - Else: - - Let `exposeCallback := false;` - - In which case we'll check the validity of this callback here: - - Extract `{ l1ResultsTreeSiblingPath, callbackStackItem: { callbackPublicKey, successCallback, failureCallback }, callbackPrivateKey } = privateCall.privatelyExecutedCallback;` - - Extract `{ l1ResultHash, l1ResultsTreeLeafIndex } = privateCall.publicInputs.executedCallback;` - - If `l1ResultHash != 0` (success): - - Check the successCallback's `functionSignature` matches the `privateCall`'s: - - `require(successCallback.functionSignature == privateCall.functionSignature)` - - In fact, check the entire callbackCallHash reconciles. - - Also check the `successResultArgMapAcc` reconciles. - - Extract array `positionData = privateCall.privatelyExecutedCallback.l1SuccessResultArgPositions;` - - Extract the underlying results `l1SuccessResultValues = privateCall.privatelyExecutedCallback.l1SuccessResultValues;` - - Reconcile the `privateCall.privatelyExecutedCallback.callbackStackItem.successResultArgMapAcc` against `positionData` (messy computation if using turboplonk). - - `positionData` is probably binary decompositions, so range checks aren't needed. Multiply all the stuff together with the primes (details omitted, since this solution is a stop-gap). No need to prevent duplicate positions here: the app circuit must do that when it makes the initial call. - - Compare the resulting value against `successResultArgMapAcc`. - - Then, for turbo: sum each of the `positionData` 'columns' to get the `position` as a value. For each `position` loop through the `privateCall.publicInputs.customPublicInputs` until reaching the index `i` of the `position`, and then `require(customPublicInputs[i] == l1SuccessResultValue[i]`. What a pain - Bring on ultraplonk! - - Else: - - Check the failureCallback's `functionSignature` matches the `privateCall`'s: - - `require(failureCallback.functionSignature == privateCall.functionSignature)` - - In fact, check the entire callbackCallHash reconciles. - - Let `callbackStackItemHash = hash(callbackStackItem)` - - Let `leafValue = hash(l1ResultHash, callbackStackItemHash)` - - Check membership of the `leafValue` in the `l1ResultsTree` using: - - `l1ResultsTreeLeafIndex` - - `l1ResultsTreeSiblingPath` - - `constants.oldTreeRoots.l1ResultsTree` - - Validate the `callbackPrivateKey`: - - `require(callbackPrivateKey * G = callbackPublicKey)` (for some fixed point `G`). - - Set `callbackNullifier := hash(callbackDatumHash, callbackPrivateKey)` to prevent this callback from being executed again. - - Set `isCallbackRecursion = false;` to hide that this is a callback, and to prevent callback logic being triggered later in the Base Rollup circuit. - - Ensure `constants.executedCallback` is zeroes. - - We don't include the whole `leafValue` in the preimage of the nullifier, to prevent a user maliciously calling the callback twice: once for 'success' and once for 'fail' (although that shouldn't be possible if the 'L1 results copier' circuit works correctly). - - Else: - - Set `isCallbackRecursion = false;` - - Assert `l1ResultHash == 0` + - Assert `privateCall.callStackItem.publicInputs.callContext.storageContractAddress == privateCall.callStackItem.contractAddress` Recursion: * If `previousKernel.publicInputs.isPrivate && start.privateCallCount > 0`: - - If `privateCall.functionSignature.isConstructor == true || privateCall.functionSignature.isCallback == true`: - - Revert - only the first call in the kernel recursion can be a constructor or a callback. - * Verify the `previousKernelProof` using the `previousKernelVK` - * Validate that the `previousKernelVK` is a valid private kernel VK with a membership check: - * Calculate `previousKernelVKHash := hash(previousKernelVK);` - * Compute `root` using the `previousKernelVKHash`, `previousKernelVKPath` and `previousKernelVKIndex`. + - If `privateCall.callStackItem.functionSignature.isConstructor == true`: + - Revert - only the first call in the kernel recursion can be a constructor. + * Verify the `previousKernel.proof` using the `previousKernel.vk` + * Validate that the `previousKernel.vk` is a valid private kernel VK with a membership check: + * Calculate `previousKernelVKHash := hash(previousKernel.vk);` + * Compute `root` using the `previousKernelVKHash`, `previousKernel.vkPath` and `previousKernel.vkIndex`. * Validate that `root == privateKernelVKTreeRoot`. * Validate consistency of 'starting' and 'previous end' values: - - verify that the `start...` values match the `previousKernelProofPublicInputs.end...` equivalents. (As mentioned in the table above, we might be able to just pass one set of inputs to avoid this cross-checking) + - verify that the `start...` values match the `previousKernel.publicInputs.end...` equivalents. * Validate consistency of values which must remain the same throughout the recursion (when passed from kernel circuit to kernel circuit): - * ensure this kernel circuit's 'constant' public inputs match the `previousKernelProof`'s public inputs. + * ensure this kernel circuit's 'constant' public inputs match the `previousKernel.publicInputs.constants`. * E.g. old tree roots. - Also ensure that any 'append-only' stacks or arrays have the same entries as the previous kernel proof, before pushing more data onto them! Verify the next call on the callstack: -* Verify `start.privateCallStack.length > 0` and (if not already done during the 'Base Case' logic above), pop 1 item off of `start.privateCallStack`. -* Validate that `privateCall.functionSignature.isPrivate == true` (otherwise this is the wrong type of kernel circuit to be using). +* Verify `start.privateCallStack.length > 0` and (if not already done during the 'Base Case' logic above, depending on how we do the implementation), pop 1 item off of `start.privateCallStack` (a `privateCallStackItemHash`) +* Validate that `privateCall.callStackItem.functionSignature.isPrivate == true` (otherwise this is the wrong type of kernel circuit to be using). * Validate that this newly-popped `privateCallStackItemHash` corresponds to the `privateCall` data passed into this circuit: - * Calculate `privateCallPublicInputsHash := hash(privateCall.publicInputs);` - * Verify that `privateCallStackItemHash == hash(privateCall.functionSignature, privateCallPublicInputsHash, privateCall.callContext, etc...)` - * Recall, the structure of a callstack item: - * ```js - privateCall = { - functionSignature: { - contractAddress, - vkIndex, - isPrivate, - isConstructor, - isCallback, - }, - publicInputsHash, - callContext, - isDelegateCall, - isStaticCall, - } - ``` + * Calculate `privateCallPublicInputsHash := hash(privateCall.callStackItem.publicInputs);` + * Verify that `privateCallStackItemHash == hash(privateCall.callStackItem)` + * Recall, the structure of a [callstack item](../contracts/transactions.md#privatecallstackitem). * Verify the correctness of `(proof, privateCallPublicInputsHash)` using the `vk`. * Validate the `vk` actually represents the function that is purportedly being executed: * Extract the `contractAddress` and `vkIndex` from `privateCall.functionSignature`. @@ -222,7 +191,6 @@ Update the `end` values: - For each `inputNullifier` in `inputNullifiers`: - `siloedInputNullifier := hash(storageContractAddress, inputNullifier);` - Push those values (`siloedOutputCommitments` and `siloedInputNullifiers`) onto `end.outputCommitments`, `end.inputNullifiers` - - Also push `callbackNullifier` onto `end.inputNullifiers`, if it exists. * It would be great if these new commitments & nullifiers could be pushed onto the first nonzero element of the `end` lists, so that these `end` lists remain tightly-packed, allowing many more rounds of recursion. Within a circuit, searching for this first nonzero element's index and then pushing to that position will use approx `(3 * 16 + 1) * 256 = 12544` constraints - so `2 * 12544 = 25088` constraints to push both the nullifier and commitment lists. * n = 256 * m = 16 @@ -241,23 +209,10 @@ Update the `end` values: - Else: - Assert `newCallStackItem.callContext.msgSender == publicCall.functionSignature.contractAddress` - Assert `newCallStackItem.callContext.storageContractAddress == newCallStackItem.functionSignature.contractAddress` - - Validate `partialL1CallStack` and `callbackStack` lengths: - - `require(partialL1CallStack.length == callbackStack.length)` - every L1 call must have a callback entry (even if the callbacks are zeroes). - For each `partialL1CallStackItem` in the `partialL1CallStack` (index `i`): - Ensure that the call is being sent to the associated portal contract address, by adding the `portalContractAddress` here: - Let `l1CallStackItem := keccak(portalContractAddress, partialL1CallStackItem)` - - Validate `publicCall.callbackStack[i]`: - - Let `successCallback = publicCall.callbackStack[i].successCallback` - - Let `failureCallback = publicCall.callbackStack[i].failureCallback` - - Ensure the contract address of each of the two callbacks matches that of the public call: - - TODO: we might actually want to _mutate_ the contractAddress from `0` to the correct address here. `0` initially, because a contract doesn't know its own address, so `0` can mean an instruction to this kernel snark to insert `address(this)` - - `require(successCallback.functionSignature.contractAddress == publicCall.functionSignature.contractAddress)`; - - `require(failureCallback.functionSignature.contractAddress == publicCall.functionSignature.contractAddress)`; - - Calculate the callbackHashes: - - Let `successCallbackHash = hash(successCallback.functionSignature, etc...)` - - Let `failureCallbackHash = hash(failureCallback.functionSignature, etc...)` - Push the contents of these call stacks onto the kernel circuit's `end.privateCallStack`, `end.publicCallStack`, `end.contractDeploymentCallStack` and `end.l1CallStack`. - - Also push the each `{callbackPublicKey, successCallbackHash, failureCallbackHash}` onto `end.callbackStack`. - As per the commitments/nullifiers bullet immediately above, it would be nice if these 'pushes' could result in tightly-packed stacks. - Determine whether any values need to be optionally revealed to the 'public world', by referring to the `publicCall`'s booleans: - Let `optionallyRevealedData = {};` @@ -265,10 +220,6 @@ Update the `end` values: - `optionallyRevealedData.callStackItemHash = privateCallStackItemHash;` - `optionallyRevealedData.vkHash = vkHash;` - `optionallyRevealedData.emittedPublicInputs = privateCall.publicInputs.emittedPublicInputs;` - - If `privateCall.functionSignature.isCallback && exposeCallback`, set: - - `optionallyRevealedData.functionSignature = privateCall.functionSignature;` - - `optionallyRevealedData.emittedPublicInputs = privateCall.publicInputs.emittedPublicInputs;` - - TODO: consider whether we can get rid of the emittedPublicInputs being emitted by a callback. More [here](../contracts/l1-calls.md#more-details). - If `isFeePayment`, set: - `optionallyRevealedData.callStackItemHash = privateCallStackItemHash;` - `optionallyRevealedData.functionSignature = privateCall.functionSignature;` diff --git a/circuits/specs/src/architecture/kernel-circuits/public-kernel.md b/circuits/specs/src/architecture/kernel-circuits/public-kernel.md index 71b040bc25f..4ab3cc709b0 100644 --- a/circuits/specs/src/architecture/kernel-circuits/public-kernel.md +++ b/circuits/specs/src/architecture/kernel-circuits/public-kernel.md @@ -1,5 +1,7 @@ # Public Kernel Circuit +**IGNORE this page. We now think we'll need a VM for public functions, so this is massively out of date. (Even without the need for a VM, the content of this page has fallen significantly behind the naming and architecture of other pages).** + The public kernel circuit has a very similar structure to that of the private kernel circuit. The public circuit tracks its own call depth. If `start.publicCallCount == 0` , one of two conditions must be met: diff --git a/circuits/specs/src/noir-stuff/extremes/call-l1.md b/circuits/specs/src/noir-stuff/extremes/call-l1.md index d91f4940e24..6c3a3c1522d 100644 --- a/circuits/specs/src/noir-stuff/extremes/call-l1.md +++ b/circuits/specs/src/noir-stuff/extremes/call-l1.md @@ -107,7 +107,7 @@ fn swap_a_for_b( custom_inputs: [ amount_a, ], - emitted_public_inputs: {}, + emitted_events: {}, executed_callback: {}, output_commitments: { @@ -188,7 +188,7 @@ fn swap_a_for_b( custom_inputs: [ 0, // Inputs which will be 'result' values are set as 0. ], - emitted_public_inputs: {}, + emitted_events: {}, // executed_callback: {...}, // Object is omitted, // since it's not known yet. // TODO: maybe we ONLY need the custom_inputs??? @@ -243,7 +243,7 @@ fn swap_a_for_b( amount_a, // All args are known for a failure callback. (There's // no result being fed in). ], - emitted_public_inputs: {}, + emitted_events: {}, // executed_callback: {...}, // Object is omitted, // since it's not known yet. output_commitments: { @@ -383,7 +383,7 @@ fn hide_amount_b( custom_inputs: { amount_b, }, - emitted_public_inputs: {}, // lots of unused stuff denoted by {} or []. + emitted_events: {}, // lots of unused stuff denoted by {} or []. executed_callback: { // Nonzero values only if it's actually being executed as a callback. // These values will be passed straight through this circuit; no checks diff --git a/circuits/specs/src/noir-stuff/extremes/call-private.md b/circuits/specs/src/noir-stuff/extremes/call-private.md index 3f5801be68d..72a5360bae1 100644 --- a/circuits/specs/src/noir-stuff/extremes/call-private.md +++ b/circuits/specs/src/noir-stuff/extremes/call-private.md @@ -52,7 +52,7 @@ fn my_private_function( b, c, ], - emitted_public_inputs: {}, + emitted_events: {}, executed_callback: {}, output_commitments: { @@ -89,7 +89,7 @@ fn my_private_function( a, b, ], - emitted_public_inputs: {}, + emitted_events: {}, executed_callback: {}, output_commitments: { diff --git a/circuits/specs/src/noir-stuff/extremes/decr-private-owned.md b/circuits/specs/src/noir-stuff/extremes/decr-private-owned.md index e6aba85e6af..9c34a834601 100644 --- a/circuits/specs/src/noir-stuff/extremes/decr-private-owned.md +++ b/circuits/specs/src/noir-stuff/extremes/decr-private-owned.md @@ -64,7 +64,7 @@ fn decrement_my_own_private_state( }, PUBLIC_INPUTS: { custom_inputs: {}, // lots of unused stuff denoted by {} or []. - emitted_public_inputs: {}, + emitted_events: {}, executed_callback: {}, output_commitments: { @@ -170,7 +170,7 @@ fn decrement_my_own_private_state( }, PUBLIC_INPUTS: { custom_inputs: {}, // lots of unused stuff denoted by {} or []. - emitted_public_inputs: {}, + emitted_events: {}, executed_callback: {}, output_commitments: { diff --git a/circuits/specs/src/noir-stuff/extremes/deploy-contract.md b/circuits/specs/src/noir-stuff/extremes/deploy-contract.md index b4b28a1809a..92d6592aad4 100644 --- a/circuits/specs/src/noir-stuff/extremes/deploy-contract.md +++ b/circuits/specs/src/noir-stuff/extremes/deploy-contract.md @@ -94,7 +94,7 @@ fn deploy( }, PUBLIC_INPUTS: { custom_inputs: [], - emitted_public_inputs: {}, + emitted_events: {}, executed_callback: {}, output_commitments: {}, @@ -195,7 +195,7 @@ fn private_constructor( // the `emittedPublicInputs` or call stacks, so that the kernel circuit // does indeed swallow the secret param with no leaks. ], - emitted_public_inputs: {}, + emitted_events: {}, executed_callback: {}, output_commitments: { diff --git a/circuits/specs/src/noir-stuff/extremes/emit-event.md b/circuits/specs/src/noir-stuff/extremes/emit-event.md index d9021a90749..1d24bcb2d2a 100644 --- a/circuits/specs/src/noir-stuff/extremes/emit-event.md +++ b/circuits/specs/src/noir-stuff/extremes/emit-event.md @@ -72,7 +72,7 @@ fn called_by_l1( a, b, ], - emitted_public_inputs: [ + emitted_events: [ 123, 456, ], @@ -102,8 +102,8 @@ fn called_by_l1( } ) { // Noddy example: - let { emitted_public_inputs } = PUBLIC_INPUTS; - assert(emitted_public_inputs[0] == 123); + let { emitted_events } = PUBLIC_INPUTS; + assert(emitted_events[0] == 123); assert(emitted_publit_inputs[1] == 456); } ``` \ No newline at end of file diff --git a/circuits/specs/src/noir-stuff/extremes/incr-private-not-owned.md b/circuits/specs/src/noir-stuff/extremes/incr-private-not-owned.md index c6383ecf7cd..19171d6cc08 100644 --- a/circuits/specs/src/noir-stuff/extremes/incr-private-not-owned.md +++ b/circuits/specs/src/noir-stuff/extremes/incr-private-not-owned.md @@ -37,7 +37,7 @@ fn increment_someone_elses_private_state( }, PUBLIC_INPUTS: { custom_inputs: {}, // lots of unused stuff denoted by {} or []. - emitted_public_inputs: {}, + emitted_events: {}, executed_callback: {}, output_commitments: { diff --git a/circuits/specs/src/noir-stuff/extremes/incr-private-owned.md b/circuits/specs/src/noir-stuff/extremes/incr-private-owned.md index bc4150c99a0..2005adabe0b 100644 --- a/circuits/specs/src/noir-stuff/extremes/incr-private-owned.md +++ b/circuits/specs/src/noir-stuff/extremes/incr-private-owned.md @@ -82,7 +82,7 @@ fn increment_my_own_private_state( }, PUBLIC_INPUTS: { custom_inputs: {}, // lots of unused stuff denoted by {} or []. - emitted_public_inputs: {}, + emitted_events: {}, executed_callback: {}, output_commitments: { @@ -240,7 +240,7 @@ fn increment_someone_elses_private_state( }, PUBLIC_INPUTS: { custom_inputs: {}, // lots of unused stuff denoted by {} or []. - emitted_public_inputs: {}, + emitted_events: {}, executed_callback: {}, output_commitments: { From 3f55e73c4df8b90f0d82ab01056401273e597cd2 Mon Sep 17 00:00:00 2001 From: iAmMichaelConnor Date: Wed, 14 Dec 2022 09:53:38 +0000 Subject: [PATCH 016/166] label files as outdated, relative to latest spec --- circuits/specs/src/architecture/contracts/deployment.md | 2 ++ circuits/specs/src/architecture/contracts/l1-calls.md | 2 ++ .../kernel-circuits/contract-deployment-kernel.md | 2 ++ .../specs/src/architecture/kernel-circuits/public-kernel.md | 2 ++ .../specs/src/architecture/rollup-circuits/base-rollup.md | 4 +--- .../src/architecture/rollup-circuits/l1-results-copier.md | 2 ++ .../specs/src/architecture/rollup-circuits/merge-rollup.md | 2 ++ circuits/specs/src/examples/erc20/appendix/appendix.md | 2 ++ circuits/specs/src/examples/erc20/deployment.md | 2 ++ circuits/specs/src/examples/erc20/deposit.md | 2 ++ circuits/specs/src/examples/erc20/erc20-shielding.md | 2 ++ circuits/specs/src/examples/erc20/transfer.md | 2 ++ circuits/specs/src/examples/erc20/withdraw.md | 2 ++ 13 files changed, 25 insertions(+), 3 deletions(-) diff --git a/circuits/specs/src/architecture/contracts/deployment.md b/circuits/specs/src/architecture/contracts/deployment.md index 7b3ba58ddcb..9d6af5219c5 100644 --- a/circuits/specs/src/architecture/contracts/deployment.md +++ b/circuits/specs/src/architecture/contracts/deployment.md @@ -1,3 +1,5 @@ +# THIS PAGE IS OUT OF DATE + # Contract Deployment A contract is a collection of functions and state variables. Each 'function' is expressed as a circuit, and each circuit can be represented by its verification key. I.e. each verification key represents a callable function in the smart contract. diff --git a/circuits/specs/src/architecture/contracts/l1-calls.md b/circuits/specs/src/architecture/contracts/l1-calls.md index 2f4ef93e164..9b1b1b75c1e 100644 --- a/circuits/specs/src/architecture/contracts/l1-calls.md +++ b/circuits/specs/src/architecture/contracts/l1-calls.md @@ -1,3 +1,5 @@ +# THIS PAGE IS OUT OF DATE + # L1 --> L2 / L2 --> L1 calls diff --git a/circuits/specs/src/architecture/kernel-circuits/contract-deployment-kernel.md b/circuits/specs/src/architecture/kernel-circuits/contract-deployment-kernel.md index 5fbe14b3435..fe1e43d3f38 100644 --- a/circuits/specs/src/architecture/kernel-circuits/contract-deployment-kernel.md +++ b/circuits/specs/src/architecture/kernel-circuits/contract-deployment-kernel.md @@ -1,3 +1,5 @@ +# THIS PAGE IS OUT OF DATE + # Contract Deployment Kernel Circuit diff --git a/circuits/specs/src/architecture/kernel-circuits/public-kernel.md b/circuits/specs/src/architecture/kernel-circuits/public-kernel.md index 4ab3cc709b0..f96fb878fe8 100644 --- a/circuits/specs/src/architecture/kernel-circuits/public-kernel.md +++ b/circuits/specs/src/architecture/kernel-circuits/public-kernel.md @@ -1,3 +1,5 @@ +# THIS PAGE IS OUT OF DATE + # Public Kernel Circuit **IGNORE this page. We now think we'll need a VM for public functions, so this is massively out of date. (Even without the need for a VM, the content of this page has fallen significantly behind the naming and architecture of other pages).** diff --git a/circuits/specs/src/architecture/rollup-circuits/base-rollup.md b/circuits/specs/src/architecture/rollup-circuits/base-rollup.md index 246067c1e46..bc60fb9137d 100644 --- a/circuits/specs/src/architecture/rollup-circuits/base-rollup.md +++ b/circuits/specs/src/architecture/rollup-circuits/base-rollup.md @@ -1,6 +1,4 @@ - +# THIS PAGE NEEDS SOME UPDATES # Base rollup circuit diff --git a/circuits/specs/src/architecture/rollup-circuits/l1-results-copier.md b/circuits/specs/src/architecture/rollup-circuits/l1-results-copier.md index 69223c168be..340cfb0505f 100644 --- a/circuits/specs/src/architecture/rollup-circuits/l1-results-copier.md +++ b/circuits/specs/src/architecture/rollup-circuits/l1-results-copier.md @@ -1,3 +1,5 @@ +# THIS PAGE IS OUT OF DATE + # L1 Results Copier Circuit See the [L2 --> L1 calls](../contracts/l1-calls.md#l2----l1-calls) section for motivation. diff --git a/circuits/specs/src/architecture/rollup-circuits/merge-rollup.md b/circuits/specs/src/architecture/rollup-circuits/merge-rollup.md index b70b5b3a44a..71d7f8429e4 100644 --- a/circuits/specs/src/architecture/rollup-circuits/merge-rollup.md +++ b/circuits/specs/src/architecture/rollup-circuits/merge-rollup.md @@ -1,3 +1,5 @@ +# THIS PAGE NEEDS SOME UPDATES + # Merge rollup circuit ## Private inputs ABI diff --git a/circuits/specs/src/examples/erc20/appendix/appendix.md b/circuits/specs/src/examples/erc20/appendix/appendix.md index bf16fad24a2..3d998ab0aa3 100644 --- a/circuits/specs/src/examples/erc20/appendix/appendix.md +++ b/circuits/specs/src/examples/erc20/appendix/appendix.md @@ -1,3 +1,5 @@ +# THIS SECTION IS OUT OF DATE + # Appendix Extra reference materials to support the explanations in this section. diff --git a/circuits/specs/src/examples/erc20/deployment.md b/circuits/specs/src/examples/erc20/deployment.md index 2e1a54dcb23..f700ac780ed 100644 --- a/circuits/specs/src/examples/erc20/deployment.md +++ b/circuits/specs/src/examples/erc20/deployment.md @@ -1,3 +1,5 @@ +# OUT OF DATE + # Deployment Let's suppose our aztec contract will have 3 circuits (plus constructor circuits): deposit, transfer, withdraw. diff --git a/circuits/specs/src/examples/erc20/deposit.md b/circuits/specs/src/examples/erc20/deposit.md index 208c0572eee..5a10358f039 100644 --- a/circuits/specs/src/examples/erc20/deposit.md +++ b/circuits/specs/src/examples/erc20/deposit.md @@ -1,3 +1,5 @@ +# OUT OF DATE + # Deposit diff --git a/circuits/specs/src/examples/erc20/erc20-shielding.md b/circuits/specs/src/examples/erc20/erc20-shielding.md index 6f91259211c..83f42944b94 100644 --- a/circuits/specs/src/examples/erc20/erc20-shielding.md +++ b/circuits/specs/src/examples/erc20/erc20-shielding.md @@ -1,3 +1,5 @@ +# OUT OF DATE + # Example - ERC20 shield Let's walk through the steps of deploying a contract to Aztec's L2, which shields ERC20-tokens from L1. diff --git a/circuits/specs/src/examples/erc20/transfer.md b/circuits/specs/src/examples/erc20/transfer.md index 8dfcc0bf6ca..b5c3b61d526 100644 --- a/circuits/specs/src/examples/erc20/transfer.md +++ b/circuits/specs/src/examples/erc20/transfer.md @@ -1,3 +1,5 @@ +# OUT OF DATE + # Transfer A transfer is an entirely private function. diff --git a/circuits/specs/src/examples/erc20/withdraw.md b/circuits/specs/src/examples/erc20/withdraw.md index 8eeedf01365..3d967ff70de 100644 --- a/circuits/specs/src/examples/erc20/withdraw.md +++ b/circuits/specs/src/examples/erc20/withdraw.md @@ -1,3 +1,5 @@ +# OUT OF DATE + # Withdraw Withdrawal is an example of a [L2 --> L1 call](../../architecture/contracts/l1-calls.md#l2----l1-calls). A user wants to nullify a private note on L2, and then be transferred ERC20 tokens on L1. From 125da0ce5d222f89b51ddffe3bc7e451268125ff Mon Sep 17 00:00:00 2001 From: iAmMichaelConnor Date: Sun, 1 Jan 2023 15:13:10 +0000 Subject: [PATCH 017/166] wip: significant state var updates --- .../specs/src/noir-stuff/extremes/call-l1.md | 12 +- .../src/noir-stuff/extremes/call-private.md | 14 +- .../noir-stuff/extremes/call-public-same.md | 10 +- .../src/noir-stuff/extremes/call-public.md | 10 +- .../noir-stuff/extremes/decr-private-owned.md | 4 +- .../noir-stuff/extremes/deploy-contract.md | 12 +- .../src/noir-stuff/extremes/edit-public.md | 2 +- .../src/noir-stuff/extremes/emit-event.md | 2 +- .../extremes/incr-private-not-owned.md | 2 +- .../noir-stuff/extremes/incr-private-owned.md | 4 +- .../src/noir-stuff/extremes/read-public.md | 2 +- circuits/src/aztec3/circuits/abis/.test.cpp | 16 +- .../abis/private_circuit_public_inputs.hpp | 64 ++--- .../abis/public_circuit_public_inputs.hpp | 28 +- .../src/aztec3/circuits/abis/tx_object.hpp | 12 +- circuits/src/aztec3/circuits/apps/README.md | 2 +- .../src/aztec3/circuits/apps/contract.hpp | 24 +- .../src/aztec3/circuits/apps/contract.tpp | 20 +- .../apps/function_execution_context.hpp | 2 +- .../apps/notes/default_private_note/note.hpp | 126 +++++++++ .../apps/notes/default_private_note/note.tpp | 254 ++++++++++++++++++ .../default_private_note/note_preimage.hpp | 144 ++++++++++ .../nullifier_preimage.hpp | 69 +++++ .../circuits/apps/notes/note_interface.hpp | 71 +++++ .../aztec3/circuits/apps/opcodes/opcodes.hpp | 33 +++ .../aztec3/circuits/apps/opcodes/opcodes.tpp | 44 +++ .../aztec3/circuits/apps/oracle_wrapper.hpp | 24 +- .../circuits/apps/private_state.test.cpp | 26 +- .../circuits/apps/private_state_note.tpp | 46 ++-- .../apps/private_state_note_preimage.hpp | 58 ++-- .../circuits/apps/private_state_operand.hpp | 4 +- .../circuits/apps/private_state_var.hpp | 22 +- .../circuits/apps/private_state_var.tpp | 51 ++-- .../aztec3/circuits/apps/state_vars/.test.cpp | 166 ++++++++++++ .../apps/state_vars/field_state_var.hpp | 52 ++++ .../aztec3/circuits/apps/state_vars/index.hpp | 3 + .../apps/state_vars/mapping_state_var.hpp | 72 +++++ .../apps/state_vars/mapping_state_var.tpp | 142 ++++++++++ .../apps/state_vars/state_var_base.hpp | 95 +++++++ .../apps/state_vars/state_var_base.tpp | 43 +++ .../apps/state_vars/utxo_state_var.hpp | 52 ++++ .../apps/state_vars/utxo_state_var.tpp | 25 ++ .../apps/test_apps/escrow/contract.hpp | 8 +- .../apps/test_apps/escrow/deposit.cpp | 97 ++++++- .../circuits/apps/test_apps/escrow/init.hpp | 2 +- .../apps/test_apps/escrow/transfer.cpp | 20 +- .../apps/test_apps/escrow/withdraw.cpp | 14 +- .../apps/test_apps/escrow/withdraw.hpp | 4 +- .../contract.hpp | 4 +- .../function1.cpp | 10 +- .../function2.cpp | 12 +- .../src/aztec3/circuits/apps/utxo_datum.hpp | 78 ++++++ .../aztec3/circuits/kernel/private/.test.cpp | 2 +- circuits/src/aztec3/constants.hpp | 18 +- circuits/src/aztec3/oracle/README.md | 2 +- circuits/src/aztec3/oracle/oracle.hpp | 92 +++++-- 56 files changed, 1943 insertions(+), 284 deletions(-) create mode 100644 circuits/src/aztec3/circuits/apps/notes/default_private_note/note.hpp create mode 100644 circuits/src/aztec3/circuits/apps/notes/default_private_note/note.tpp create mode 100644 circuits/src/aztec3/circuits/apps/notes/default_private_note/note_preimage.hpp create mode 100644 circuits/src/aztec3/circuits/apps/notes/default_private_note/nullifier_preimage.hpp create mode 100644 circuits/src/aztec3/circuits/apps/notes/note_interface.hpp create mode 100644 circuits/src/aztec3/circuits/apps/opcodes/opcodes.hpp create mode 100644 circuits/src/aztec3/circuits/apps/opcodes/opcodes.tpp create mode 100644 circuits/src/aztec3/circuits/apps/state_vars/.test.cpp create mode 100644 circuits/src/aztec3/circuits/apps/state_vars/field_state_var.hpp create mode 100644 circuits/src/aztec3/circuits/apps/state_vars/index.hpp create mode 100644 circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.hpp create mode 100644 circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.tpp create mode 100644 circuits/src/aztec3/circuits/apps/state_vars/state_var_base.hpp create mode 100644 circuits/src/aztec3/circuits/apps/state_vars/state_var_base.tpp create mode 100644 circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp create mode 100644 circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.tpp create mode 100644 circuits/src/aztec3/circuits/apps/utxo_datum.hpp diff --git a/circuits/specs/src/noir-stuff/extremes/call-l1.md b/circuits/specs/src/noir-stuff/extremes/call-l1.md index 6c3a3c1522d..da50796e2e3 100644 --- a/circuits/specs/src/noir-stuff/extremes/call-l1.md +++ b/circuits/specs/src/noir-stuff/extremes/call-l1.md @@ -104,7 +104,7 @@ fn swap_a_for_b( token_balance_a_new_salt, }, PUBLIC_INPUTS: { - custom_inputs: [ + args: [ amount_a, ], emitted_events: {}, @@ -142,7 +142,7 @@ fn swap_a_for_b( ) { // Params: - let amount_a = PUBLIC_INPUTS.custom_inputs.amount_a + let amount_a = PUBLIC_INPUTS.args.amount_a /******************************************************************************** * MAKE THE L1 CALL @@ -185,13 +185,13 @@ fn swap_a_for_b( // Some public inputs are omitted from this object when calculating a // _callback's_ call hash, because they depend on the (as of yet) // unknown L1 result. - custom_inputs: [ + args: [ 0, // Inputs which will be 'result' values are set as 0. ], emitted_events: {}, // executed_callback: {...}, // Object is omitted, // since it's not known yet. - // TODO: maybe we ONLY need the custom_inputs??? + // TODO: maybe we ONLY need the args??? // TODO: model the claim circuit, so I understand what's needed for // that context. output_commitments: { @@ -239,7 +239,7 @@ fn swap_a_for_b( is_callback: true, // <-- callback! }, public_inputs: { - custom_inputs: [ + args: [ amount_a, // All args are known for a failure callback. (There's // no result being fed in). ], @@ -380,7 +380,7 @@ fn hide_amount_b( token_balance_b_new_salt, }, PUBLIC_INPUTS: { - custom_inputs: { + args: { amount_b, }, emitted_events: {}, // lots of unused stuff denoted by {} or []. diff --git a/circuits/specs/src/noir-stuff/extremes/call-private.md b/circuits/specs/src/noir-stuff/extremes/call-private.md index 72a5360bae1..20af37dad18 100644 --- a/circuits/specs/src/noir-stuff/extremes/call-private.md +++ b/circuits/specs/src/noir-stuff/extremes/call-private.md @@ -47,7 +47,7 @@ fn my_private_function( }, public_inputs: { // All of the public inputs of a private function call - custom_inputs: [ + args: [ a, b, c, @@ -85,7 +85,7 @@ fn my_private_function( ] }, PUBLIC_INPUTS: { - custom_inputs: [ + args: [ a, b, ], @@ -115,8 +115,8 @@ fn my_private_function( called_from_l1: false, } ) { - let a = PUBLIC_INPUTS.custom_inputs.a; - let b = PUBLIC_INPUTS.custom_inputs.b; + let a = PUBLIC_INPUTS.args.a; + let b = PUBLIC_INPUTS.args.b; let c = a + b; @@ -131,9 +131,9 @@ fn my_private_function( assert(call_stack_item.function_signature.vk_index == 0); // Check the correct parameters are being passed to the function: - assert(call_stack_item.public_inputs.custom_inputs[0] == a); - assert(call_stack_item.public_inputs.custom_inputs[1] == b); - assert(call_stack_item.public_inputs.custom_inputs[2] == c); + assert(call_stack_item.public_inputs.args[0] == a); + assert(call_stack_item.public_inputs.args[1] == b); + assert(call_stack_item.public_inputs.args[2] == c); // The call context will be checked in the kernel snark, so we don't need // to check it here. diff --git a/circuits/specs/src/noir-stuff/extremes/call-public-same.md b/circuits/specs/src/noir-stuff/extremes/call-public-same.md index 1a33cc0e6b8..c3476274d63 100644 --- a/circuits/specs/src/noir-stuff/extremes/call-public-same.md +++ b/circuits/specs/src/noir-stuff/extremes/call-public-same.md @@ -110,8 +110,8 @@ fn my_private_function( called_from_l1: false, } ) { - let a = PUBLIC_INPUTS.custom_inputs.a; - let b = PUBLIC_INPUTS.custom_inputs.b; + let a = PUBLIC_INPUTS.args.a; + let b = PUBLIC_INPUTS.args.b; let c = a + b; @@ -128,9 +128,9 @@ fn my_private_function( assert(call_stack_item.function_signature.vkIndex == 0); // Check the correct parameters are being passed to the function: - assert(call_stack_item.public_inputs.custom_inputs[0] == a); - assert(call_stack_item.public_inputs.custom_inputs[1] == b); - assert(call_stack_item.public_inputs.custom_inputs[2] == c); + assert(call_stack_item.public_inputs.args[0] == a); + assert(call_stack_item.public_inputs.args[1] == b); + assert(call_stack_item.public_inputs.args[2] == c); // The call context will be checked in the kernel snark, so we don't need // to check it here. diff --git a/circuits/specs/src/noir-stuff/extremes/call-public.md b/circuits/specs/src/noir-stuff/extremes/call-public.md index af0408c3bf8..daec436d398 100644 --- a/circuits/specs/src/noir-stuff/extremes/call-public.md +++ b/circuits/specs/src/noir-stuff/extremes/call-public.md @@ -112,8 +112,8 @@ fn my_private_function( called_from_l1: false, } ) { - let a = PUBLIC_INPUTS.custom_inputs.a; - let b = PUBLIC_INPUTS.custom_inputs.b; + let a = PUBLIC_INPUTS.args.a; + let b = PUBLIC_INPUTS.args.b; let c = a + b; @@ -128,9 +128,9 @@ fn my_private_function( assert(call_stack_item.function_signature.vkIndex == 0); // Check the correct parameters are being passed to the function: - assert(call_stack_item.public_inputs.custom_inputs[0] == a); - assert(call_stack_item.public_inputs.custom_inputs[1] == b); - assert(call_stack_item.public_inputs.custom_inputs[2] == c); + assert(call_stack_item.public_inputs.args[0] == a); + assert(call_stack_item.public_inputs.args[1] == b); + assert(call_stack_item.public_inputs.args[2] == c); // The call context will be checked in the kernel snark, so we don't need // to check it here. diff --git a/circuits/specs/src/noir-stuff/extremes/decr-private-owned.md b/circuits/specs/src/noir-stuff/extremes/decr-private-owned.md index 9c34a834601..276f9bf9503 100644 --- a/circuits/specs/src/noir-stuff/extremes/decr-private-owned.md +++ b/circuits/specs/src/noir-stuff/extremes/decr-private-owned.md @@ -63,7 +63,7 @@ fn decrement_my_own_private_state( x_new_salt, }, PUBLIC_INPUTS: { - custom_inputs: {}, // lots of unused stuff denoted by {} or []. + args: {}, // lots of unused stuff denoted by {} or []. emitted_events: {}, executed_callback: {}, @@ -169,7 +169,7 @@ fn decrement_my_own_private_state( x_new_salt, }, PUBLIC_INPUTS: { - custom_inputs: {}, // lots of unused stuff denoted by {} or []. + args: {}, // lots of unused stuff denoted by {} or []. emitted_events: {}, executed_callback: {}, diff --git a/circuits/specs/src/noir-stuff/extremes/deploy-contract.md b/circuits/specs/src/noir-stuff/extremes/deploy-contract.md index 92d6592aad4..b5f26beb8b1 100644 --- a/circuits/specs/src/noir-stuff/extremes/deploy-contract.md +++ b/circuits/specs/src/noir-stuff/extremes/deploy-contract.md @@ -93,7 +93,7 @@ fn deploy( ], }, PUBLIC_INPUTS: { - custom_inputs: [], + args: [], emitted_events: {}, executed_callback: {}, @@ -137,8 +137,8 @@ fn deploy( // Check the correct parameters are being passed to the constructors: - assert(private_constructor_public_inputs.custom_inputs[0] == 123); - assert(public_constructor_public_inputs.custom_inputs[0] == 456); + assert(private_constructor_public_inputs.args[0] == 123); + assert(public_constructor_public_inputs.args[0] == 456); // The call contexts will be checked in the kernel snark, so we don't need // to check it here. @@ -183,13 +183,13 @@ fn private_constructor( b_new_salt, }, PUBLIC_INPUTS: { - custom_inputs: [ + args: [ _b, // Although this param was decorated as `secret`, it cannot be a // private input to the circuit, because it's passed into the circuit // by another circuit (which must validate the correctness of the // value being passed in). // It will still be hidden from the world, since the private kernel - // circuit will swallow all custom_inputs, unless they're also + // circuit will swallow all args, unless they're also // emitted as events. // TODO: prevent `secret` params from being exposed by an app via // the `emittedPublicInputs` or call stacks, so that the kernel circuit @@ -280,7 +280,7 @@ fn public_constructor( called_from_l1: false, } ) { - let amount = PUBLIC_INPUTS.custom_inputs.amount; + let amount = PUBLIC_INPUTS.args.amount; // Perform the calculation (for example): require(a_storage_slot == 1); diff --git a/circuits/specs/src/noir-stuff/extremes/edit-public.md b/circuits/specs/src/noir-stuff/extremes/edit-public.md index 4f94a129392..e0d51013a74 100644 --- a/circuits/specs/src/noir-stuff/extremes/edit-public.md +++ b/circuits/specs/src/noir-stuff/extremes/edit-public.md @@ -53,7 +53,7 @@ fn my_public_function( called_from_l1: false, } ) { - let amount = PUBLIC_INPUTS.custom_inputs.amount; + let amount = PUBLIC_INPUTS.args.amount; // Perform the calculation: require(x_storage_slot == 1); diff --git a/circuits/specs/src/noir-stuff/extremes/emit-event.md b/circuits/specs/src/noir-stuff/extremes/emit-event.md index 1d24bcb2d2a..419e367c8f3 100644 --- a/circuits/specs/src/noir-stuff/extremes/emit-event.md +++ b/circuits/specs/src/noir-stuff/extremes/emit-event.md @@ -68,7 +68,7 @@ fn called_by_l1( // none shown }, PUBLIC_INPUTS: { - custom_inputs: [ + args: [ a, b, ], diff --git a/circuits/specs/src/noir-stuff/extremes/incr-private-not-owned.md b/circuits/specs/src/noir-stuff/extremes/incr-private-not-owned.md index 19171d6cc08..b97b16f2903 100644 --- a/circuits/specs/src/noir-stuff/extremes/incr-private-not-owned.md +++ b/circuits/specs/src/noir-stuff/extremes/incr-private-not-owned.md @@ -36,7 +36,7 @@ fn increment_someone_elses_private_state( x_new_salt, }, PUBLIC_INPUTS: { - custom_inputs: {}, // lots of unused stuff denoted by {} or []. + args: {}, // lots of unused stuff denoted by {} or []. emitted_events: {}, executed_callback: {}, diff --git a/circuits/specs/src/noir-stuff/extremes/incr-private-owned.md b/circuits/specs/src/noir-stuff/extremes/incr-private-owned.md index 2005adabe0b..1a0e5d768ab 100644 --- a/circuits/specs/src/noir-stuff/extremes/incr-private-owned.md +++ b/circuits/specs/src/noir-stuff/extremes/incr-private-owned.md @@ -81,7 +81,7 @@ fn increment_my_own_private_state( x_new_salt, }, PUBLIC_INPUTS: { - custom_inputs: {}, // lots of unused stuff denoted by {} or []. + args: {}, // lots of unused stuff denoted by {} or []. emitted_events: {}, executed_callback: {}, @@ -239,7 +239,7 @@ fn increment_someone_elses_private_state( x_new_salt, }, PUBLIC_INPUTS: { - custom_inputs: {}, // lots of unused stuff denoted by {} or []. + args: {}, // lots of unused stuff denoted by {} or []. emitted_events: {}, executed_callback: {}, diff --git a/circuits/specs/src/noir-stuff/extremes/read-public.md b/circuits/specs/src/noir-stuff/extremes/read-public.md index 7b5c30d8931..18cb71754a9 100644 --- a/circuits/specs/src/noir-stuff/extremes/read-public.md +++ b/circuits/specs/src/noir-stuff/extremes/read-public.md @@ -53,7 +53,7 @@ fn my_private_function( called_from_l1: false, } ) { - let amount = PUBLIC_INPUTS.custom_inputs.amount; + let amount = PUBLIC_INPUTS.args.amount; // Perform the calculation: require(x_storage_slot == 1); diff --git a/circuits/src/aztec3/circuits/abis/.test.cpp b/circuits/src/aztec3/circuits/abis/.test.cpp index dda79da9a88..6d4c0e60e3c 100644 --- a/circuits/src/aztec3/circuits/abis/.test.cpp +++ b/circuits/src/aztec3/circuits/abis/.test.cpp @@ -79,8 +79,8 @@ TEST(abi_tests, test_native_to_circuit_call_context) // TEST(abi_tests, test_native_public_inputs) // { // PublicCircuitPublicInputs public_inputs = { -// .custom_inputs = { 1, 2, 3, 4, 5, 6, 7, 8 }, -// .custom_outputs = { 9, 10, 11, 12 }, +// .args = { 1, 2, 3, 4, 5, 6, 7, 8 }, +// .return_values = { 9, 10, 11, 12 }, // .emitted_events = { 13, 14, 15, 16 }, // .state_transitions = { { { 21, 22, 23 }, { 21, 22, 23 }, { 21, 22, 23 }, { 21, 22, 23 } } }, // .state_reads = { { { 24, 25 }, { 24, 25 }, { 24, 25 }, { 24, 25 } } }, @@ -96,8 +96,8 @@ TEST(abi_tests, test_native_to_circuit_call_context) // TEST(abi_tests, test_native_to_circuit_public_circuit_public_inputs) // { // PublicCircuitPublicInputs native_public_inputs = { -// .custom_inputs = { 1, 2, 3, 4, 5, 6, 7, 8 }, -// .custom_outputs = { 9, 10, 11, 12 }, +// .args = { 1, 2, 3, 4, 5, 6, 7, 8 }, +// .return_values = { 9, 10, 11, 12 }, // .emitted_events = { 13, 14, 15, 16 }, // .state_transitions = { { { 21, 22, 23 }, { 21, 22, 23 }, { 21, 22, 23 }, { 21, 22, 23 } } }, // .state_reads = { { { 24, 25 }, { 24, 25 }, { 24, 25 }, { 24, 25 } } }, @@ -118,8 +118,8 @@ TEST(abi_tests, test_native_to_circuit_call_context) // TEST(abi_tests, test_native_call_stack_item) // { // PublicCircuitPublicInputs public_inputs = { -// .custom_inputs = { 1, 2, 3, 4, 5, 6, 7, 8 }, -// .custom_outputs = { 9, 10, 11, 12 }, +// .args = { 1, 2, 3, 4, 5, 6, 7, 8 }, +// .return_values = { 9, 10, 11, 12 }, // .emitted_events = { 13, 14, 15, 16 }, // .state_transitions = { { { 21, 22, 23 }, { 21, 22, 23 }, { 21, 22, 23 }, { 21, 22, 23 } } }, // .state_reads = { { { 24, 25 }, { 24, 25 }, { 24, 25 }, { 24, 25 } } }, @@ -151,8 +151,8 @@ TEST(abi_tests, test_native_to_circuit_call_context) // TEST(abi_tests, test_native_to_circuit_call_stack_item) // { // PublicCircuitPublicInputs public_inputs = { -// .custom_inputs = { 1, 2, 3, 4, 5, 6, 7, 8 }, -// .custom_outputs = { 9, 10, 11, 12 }, +// .args = { 1, 2, 3, 4, 5, 6, 7, 8 }, +// .return_values = { 9, 10, 11, 12 }, // .emitted_events = { 13, 14, 15, 16 }, // .state_transitions = { { { 21, 22, 23 }, { 21, 22, 23 }, { 21, 22, 23 }, { 21, 22, 23 } } }, // .state_reads = { { { 24, 25 }, { 24, 25 }, { 24, 25 }, { 24, 25 } } }, diff --git a/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp b/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp index 4680a09e58f..611ea2640b2 100644 --- a/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp +++ b/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp @@ -24,8 +24,8 @@ template class PrivateCircuitPublicInputs { public: CallContext call_context; - std::array custom_inputs; - std::array custom_outputs; + std::array args; + std::array return_values; std::array emitted_events; @@ -53,8 +53,8 @@ template class PrivateCircuitPublicInputs { PrivateCircuitPublicInputs> pis = { to_circuit_type(call_context), - to_ct(custom_inputs), - to_ct(custom_outputs), + to_ct(args), + to_ct(return_values), to_ct(emitted_events), @@ -82,8 +82,8 @@ template class PrivateCircuitPublicInputs { inputs.push_back(call_context.hash()); - spread_arr_into_vec(custom_inputs, inputs); - spread_arr_into_vec(custom_outputs, inputs); + spread_arr_into_vec(args, inputs); + spread_arr_into_vec(return_values, inputs); spread_arr_into_vec(emitted_events, inputs); @@ -122,8 +122,8 @@ template class OptionalPrivateCircuitPublicInputs { public: std::optional> call_context; - std::array custom_inputs; - std::array custom_outputs; + std::array args; + std::array return_values; std::array emitted_events; @@ -144,8 +144,8 @@ template class OptionalPrivateCircuitPublicInputs { OptionalPrivateCircuitPublicInputs( std::optional> const& call_context, - std::array const& custom_inputs, - std::array const& custom_outputs, + std::array const& args, + std::array const& return_values, std::array const& emitted_events, @@ -161,8 +161,8 @@ template class OptionalPrivateCircuitPublicInputs { opt_fr const& old_nullifier_tree_root, opt_fr const& old_contract_tree_root) : call_context(call_context) - , custom_inputs(custom_inputs) - , custom_outputs(custom_outputs) + , args(args) + , return_values(return_values) , emitted_events(emitted_events) , output_commitments(output_commitments) , input_nullifiers(input_nullifiers) @@ -183,8 +183,8 @@ template class OptionalPrivateCircuitPublicInputs { new_inputs.call_context = std::nullopt; - new_inputs.custom_inputs.fill(std::nullopt); - new_inputs.custom_outputs.fill(std::nullopt); + new_inputs.args.fill(std::nullopt); + new_inputs.return_values.fill(std::nullopt); new_inputs.emitted_events.fill(std::nullopt); @@ -229,8 +229,8 @@ template class OptionalPrivateCircuitPublicInputs { make_unused_element_zero(composer, call_context); - make_unused_array_elements_zero(composer, custom_inputs); - make_unused_array_elements_zero(composer, custom_outputs); + make_unused_array_elements_zero(composer, args); + make_unused_array_elements_zero(composer, return_values); make_unused_array_elements_zero(composer, emitted_events); @@ -259,8 +259,8 @@ template class OptionalPrivateCircuitPublicInputs { (*call_context).set_public(); - set_array_public(custom_inputs); - set_array_public(custom_outputs); + set_array_public(args); + set_array_public(return_values); set_array_public(emitted_events); @@ -291,8 +291,8 @@ template class OptionalPrivateCircuitPublicInputs { OptionalPrivateCircuitPublicInputs> pis = { to_circuit_type(call_context), - to_ct(custom_inputs), - to_ct(custom_outputs), + to_ct(args), + to_ct(return_values), to_ct(emitted_events), @@ -324,8 +324,8 @@ template class OptionalPrivateCircuitPublicInputs { OptionalPrivateCircuitPublicInputs pis = { to_native_type(call_context), - to_nt(custom_inputs), - to_nt(custom_outputs), + to_nt(args), + to_nt(return_values), to_nt(emitted_events), @@ -358,8 +358,8 @@ template class OptionalPrivateCircuitPublicInputs { inputs.push_back((*call_context).hash()); - spread_arr_opt_into_vec(custom_inputs, inputs); - spread_arr_opt_into_vec(custom_outputs, inputs); + spread_arr_opt_into_vec(args, inputs); + spread_arr_opt_into_vec(return_values, inputs); spread_arr_opt_into_vec(emitted_events, inputs); @@ -386,8 +386,8 @@ template class OptionalPrivateCircuitPublicInputs { return PrivateCircuitPublicInputs{ .call_context = call_context.value(), - .custom_inputs = map(custom_inputs, get_value), - .custom_outputs = map(custom_outputs, get_value), + .args = map(args, get_value), + .return_values = map(return_values, get_value), .emitted_events = map(emitted_events, get_value), @@ -480,8 +480,8 @@ void read(uint8_t const*& it, OptionalPrivateCircuitPublicInputs& private_c OptionalPrivateCircuitPublicInputs& pis = private_circuit_public_inputs; read(it, pis.call_context); - read(it, pis.custom_inputs); - read(it, pis.custom_outputs); + read(it, pis.args); + read(it, pis.return_values); read(it, pis.emitted_events); read(it, pis.output_commitments); read(it, pis.input_nullifiers); @@ -502,8 +502,8 @@ void write(std::vector& buf, OptionalPrivateCircuitPublicInputs co OptionalPrivateCircuitPublicInputs const& pis = private_circuit_public_inputs; write(buf, pis.call_context); - write(buf, pis.custom_inputs); - write(buf, pis.custom_outputs); + write(buf, pis.args); + write(buf, pis.return_values); write(buf, pis.emitted_events); write(buf, pis.output_commitments); write(buf, pis.input_nullifiers); @@ -522,8 +522,8 @@ std::ostream& operator<<(std::ostream& os, OptionalPrivateCircuitPublicInputs const& pis = private_circuit_public_inputs; return os << "call_context: " << pis.call_context << "\n" - << "custom_inputs: " << pis.custom_inputs << "\n" - << "custom_outputs: " << pis.custom_outputs << "\n" + << "args: " << pis.args << "\n" + << "return_values: " << pis.return_values << "\n" << "emitted_events: " << pis.emitted_events << "\n" << "output_commitments: " << pis.output_commitments << "\n" << "input_nullifiers: " << pis.input_nullifiers << "\n" diff --git a/circuits/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp b/circuits/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp index 590b6dc1db9..3ca59f2a181 100644 --- a/circuits/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp +++ b/circuits/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp @@ -23,8 +23,8 @@ template struct PublicCircuitPublicInputs { CallContext call_context; - std::array custom_inputs; - std::array custom_outputs; + std::array args; + std::array return_values; std::array emitted_events; @@ -44,8 +44,8 @@ template struct PublicCircuitPublicInputs { // static PublicCircuitPublicInputs empty() // { // PublicCircuitPublicInputs pis = { - // std::array::fill(0), - // std::array::fill(0), + // std::array::fill(0), + // std::array::fill(0), // std::array::fill(0), @@ -77,8 +77,8 @@ template struct PublicCircuitPublicInputs { PublicCircuitPublicInputs> pis = { to_circuit_type(call_context), - .custom_inputs = to_ct(custom_inputs), - .custom_outputs = to_ct(custom_outputs), + .args = to_ct(args), + .return_values = to_ct(return_values), .emitted_events = to_ct(emitted_events), @@ -107,8 +107,8 @@ template struct PublicCircuitPublicInputs { // efficiency, so that fewer hashes are needed to 'unwrap' the call_context in the kernel circuit. // inputs.push_back(call_context.hash()); - spread_arr_into_vec(custom_inputs, inputs); - spread_arr_into_vec(custom_outputs, inputs); + spread_arr_into_vec(args, inputs); + spread_arr_into_vec(return_values, inputs); spread_arr_into_vec(emitted_events, inputs); @@ -136,8 +136,8 @@ template void read(uint8_t const*& it, PublicCircuitPublicInputs< using serialize::read; PublicCircuitPublicInputs& pis = private_circuit_public_inputs; - read(it, pis.custom_inputs); - read(it, pis.custom_outputs); + read(it, pis.args); + read(it, pis.return_values); read(it, pis.emitted_events); read(it, pis.emitted_ouputs); @@ -160,8 +160,8 @@ void write(std::vector& buf, PublicCircuitPublicInputs const& priv PublicCircuitPublicInputs const& pis = private_circuit_public_inputs; - write(buf, pis.custom_inputs); - write(buf, pis.custom_outputs); + write(buf, pis.args); + write(buf, pis.return_values); write(buf, pis.emitted_events); write(buf, pis.emitted_ouputs); @@ -182,8 +182,8 @@ std::ostream& operator<<(std::ostream& os, PublicCircuitPublicInputs const& { PublicCircuitPublicInputs const& pis = private_circuit_public_inputs; - return os << "custom_inputs: " << pis.custom_inputs << "\n" - << "custom_outputs: " << pis.custom_outputs << "\n" + return os << "args: " << pis.args << "\n" + << "return_values: " << pis.return_values << "\n" << "emitted_events: " << pis.emitted_events << "\n" << "state_transitions: " << pis.state_transitions << "\n" diff --git a/circuits/src/aztec3/circuits/abis/tx_object.hpp b/circuits/src/aztec3/circuits/abis/tx_object.hpp index 51987aeb12d..4ecc886d4fb 100644 --- a/circuits/src/aztec3/circuits/abis/tx_object.hpp +++ b/circuits/src/aztec3/circuits/abis/tx_object.hpp @@ -21,7 +21,7 @@ template struct TxObject { address from; address to; FunctionSignature function_signature; - std::array custom_inputs; + std::array args; fr nonce; TxContext tx_context; fr chain_id; @@ -35,8 +35,8 @@ template struct TxObject { auto to_circuit_type = [&](auto& e) { return e.to_circuit_type(composer); }; TxObject> tx_object = { - to_ct(from), to_ct(to), to_circuit_type(function_signature), - to_ct(custom_inputs), to_ct(nonce), to_circuit_type(tx_context), + to_ct(from), to_ct(to), to_circuit_type(function_signature), + to_ct(args), to_ct(nonce), to_circuit_type(tx_context), to_ct(chain_id), }; @@ -51,7 +51,7 @@ template void read(uint8_t const*& it, TxObject& tx_object) read(it, tx_object.from); read(it, tx_object.to); read(it, tx_object.function_signature); - read(it, tx_object.custom_inputs); + read(it, tx_object.args); read(it, tx_object.nonce); read(it, tx_object.tx_context); read(it, tx_object.chain_id); @@ -64,7 +64,7 @@ template void write(std::vector& buf, TxObject cons write(buf, tx_object.from); write(buf, tx_object.to); write(buf, tx_object.function_signature); - write(buf, tx_object.custom_inputs); + write(buf, tx_object.args); write(buf, tx_object.nonce); write(buf, tx_object.tx_context); write(buf, tx_object.chain_id); @@ -75,7 +75,7 @@ template std::ostream& operator<<(std::ostream& os, TxObject return os << "from: " << tx_object.from << "\n" << "to: " << tx_object.to << "\n" << "function_signature: " << tx_object.function_signature << "\n" - << "custom_inputs: " << tx_object.custom_inputs << "\n" + << "args: " << tx_object.args << "\n" << "nonce: " << tx_object.nonce << "\n" << "tx_context: " << tx_object.tx_context << "\n" << "chain_id: " << tx_object.chain_id << "\n"; diff --git a/circuits/src/aztec3/circuits/apps/README.md b/circuits/src/aztec3/circuits/apps/README.md index 9d966334fa8..6688506f6ff 100644 --- a/circuits/src/aztec3/circuits/apps/README.md +++ b/circuits/src/aztec3/circuits/apps/README.md @@ -67,7 +67,7 @@ PrivateStateVar - PrivateStateType private_state_type; - std::string name; - fr start_slot; -- grumpkin_point slot_point; +- grumpkin_point storage_slot_point; - std::map> private_states; - bool is_mapping = false; - std::optional> mapping_key_names = std::nullopt; diff --git a/circuits/src/aztec3/circuits/apps/contract.hpp b/circuits/src/aztec3/circuits/apps/contract.hpp index 8acd32c39ff..9d4235f4f5c 100644 --- a/circuits/src/aztec3/circuits/apps/contract.hpp +++ b/circuits/src/aztec3/circuits/apps/contract.hpp @@ -1,6 +1,5 @@ #pragma once -// #include -// #include + #include "function_declaration.hpp" #include "private_state_var.hpp" #include "l1_function_interface.hpp" @@ -13,7 +12,6 @@ using plonk::stdlib::witness_t; using plonk::stdlib::types::CircuitTypes; using NT = plonk::stdlib::types::NativeTypes; using aztec3::circuits::abis::FunctionSignature; -// using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; template class FunctionExecutionContext; @@ -26,12 +24,15 @@ template class Contract { FunctionExecutionContext& exec_ctx; const std::string contract_name; + fr state_counter = 0; std::vector state_names; + std::map> private_state_vars; std::map> function_signatures; + std::map> l1_functions; Contract(FunctionExecutionContext& exec_ctx, std::string const& contract_name) @@ -52,17 +53,17 @@ template class Contract { L1FunctionInterface& get_l1_function(std::string const& name); - void push_new_state_name(std::string const& name); + void push_new_state_var_name(std::string const& name); - PrivateStateVar& new_private_state(std::string const& name, - PrivateStateType const& private_state_type = PARTITIONED); + PrivateStateVar& declare_private_state_var(std::string const& name, + PrivateStateType const& private_state_type = PARTITIONED); // For initialising a private state which is a mapping. - PrivateStateVar& new_private_state(std::string const& name, - std::vector const& mapping_key_names, - PrivateStateType const& private_state_type = PARTITIONED); + PrivateStateVar& declare_private_state_var(std::string const& name, + std::vector const& mapping_key_names, + PrivateStateType const& private_state_type = PARTITIONED); - PrivateStateVar& get_private_state(std::string const& name); + PrivateStateVar& get_private_state_var(std::string const& name); }; } // namespace aztec3::circuits::apps @@ -72,5 +73,6 @@ template class Contract { // - We retain implicit instantiation of templates, meaning we can pick and choose (with static_assert) which class // methods support native, // circuit or both types. -// - We don't implement method definitions in this file, to avoid a circular dependency with exec_ctx.hpp. +// - We don't implement method definitions in this file, to avoid a circular dependency with +// function_execution_context.hpp. #include "contract.tpp" \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/contract.tpp b/circuits/src/aztec3/circuits/apps/contract.tpp index 9438c3757aa..7217c91abca 100644 --- a/circuits/src/aztec3/circuits/apps/contract.tpp +++ b/circuits/src/aztec3/circuits/apps/contract.tpp @@ -60,7 +60,7 @@ template L1FunctionInterface& Contract:: return l1_functions[name]; } -template void Contract::push_new_state_name(std::string const& name) +template void Contract::push_new_state_var_name(std::string const& name) { if (index_of(state_names, name) == -1) { state_names.push_back(name); @@ -70,10 +70,10 @@ template void Contract::push_new_state_name(std::s } template -PrivateStateVar& Contract::new_private_state(std::string const& name, - PrivateStateType const& private_state_type) +PrivateStateVar& Contract::declare_private_state_var(std::string const& name, + PrivateStateType const& private_state_type) { - push_new_state_name(name); + push_new_state_var_name(name); PrivateStateVar private_state_var = PrivateStateVar(&exec_ctx, private_state_type, name, state_counter++); private_state_vars.insert(std::make_pair(name, private_state_var)); @@ -82,18 +82,20 @@ PrivateStateVar& Contract::new_private_state(std::string con // For initialising a private state which is a mapping. template -PrivateStateVar& Contract::new_private_state(std::string const& name, - std::vector const& mapping_key_names, - PrivateStateType const& private_state_type) +PrivateStateVar& Contract::declare_private_state_var( + std::string const& name, + std::vector const& mapping_key_names, + PrivateStateType const& private_state_type) { - push_new_state_name(name); + push_new_state_var_name(name); PrivateStateVar private_state_var = PrivateStateVar(&exec_ctx, private_state_type, name, state_counter++, mapping_key_names); private_state_vars.insert(std::make_pair(name, private_state_var)); return private_state_vars[name]; }; -template PrivateStateVar& Contract::get_private_state(std::string const& name) +template +PrivateStateVar& Contract::get_private_state_var(std::string const& name) { if (!private_state_vars.contains(name)) { throw_or_abort("name not found"); diff --git a/circuits/src/aztec3/circuits/apps/function_execution_context.hpp b/circuits/src/aztec3/circuits/apps/function_execution_context.hpp index 39956be6bcd..f707348606e 100644 --- a/circuits/src/aztec3/circuits/apps/function_execution_context.hpp +++ b/circuits/src/aztec3/circuits/apps/function_execution_context.hpp @@ -87,7 +87,7 @@ template class FunctionExecutionContext { } } for (size_t i = 0; i < new_private_state_notes.size(); ++i) { - new_private_state_notes[i].preimage.input_nullifier = new_nullifiers[i]; + new_private_state_notes[i].preimage.nonce = new_nullifiers[i]; new_commitments.push_back(new_private_state_notes[i].compute_commitment()); } } diff --git a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.hpp b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.hpp new file mode 100644 index 00000000000..f07d9219df5 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.hpp @@ -0,0 +1,126 @@ +#pragma once + +#include "../note_interface.hpp" + +#include "note_preimage.hpp" +#include "nullifier_preimage.hpp" + +#include "../../state_vars/utxo_state_var.hpp" + +#include +#include + +namespace aztec3::circuits::apps::notes { + +using aztec3::circuits::apps::state_vars::UTXOStateVar; + +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; + +// template class UTXOStateVar; +// template struct DefaultPrivateNotePreimage; +// template struct DefaultPrivateNoteNullifierPreimage; + +template +class DefaultPrivateNote : public NoteInterface, ValueType>, + DefaultPrivateNoteNullifierPreimage>> { + public: + typedef CircuitTypes CT; + typedef typename CT::fr fr; + typedef typename CT::grumpkin_point grumpkin_point; + typedef typename CT::address address; + typedef typename CT::boolean boolean; + + // no known conversion + // from 'UTXOStateVar > > *' to 'UTXOStateVar >::Note> *'( + // aka 'UTXOStateVar > > *') + + // using Note = aztec3::circuits::apps::notes::DefaultPrivateNote; + + using NotePreimage = DefaultPrivateNotePreimage, ValueType>; + using NullifierPreimage = DefaultPrivateNoteNullifierPreimage>; + + UTXOStateVar* utxo_state_var; + + DefaultPrivateNote(UTXOStateVar* utxo_state_var, NotePreimage note_preimage) + : utxo_state_var(utxo_state_var) + , note_preimage(note_preimage){}; + + // bool operator==(PrivateStateNote const&) const = default; + + // METHODS + + void remove() override; + + // HOOKS + + fr get_commitment() override + { + if (commitment) { + return *commitment; + } + return compute_commitment().first; + }; + + fr get_nullifier() override + { + if (!nullifier) { + throw_or_abort("No nullifier exists for this note yet. Call compute_nullifier() first."); + } + return *nullifier; + }; + + // grumpkin_point get_partial_commitment() override const + // { + // if (!partial_commitment) { + // throw_or_abort( + // "No partial_commitment exists for this note. Are you sure you haven't accidentally created a " + // "complete commitment?"); + // } + // return *partial_commitment; + // }; + + std::pair compute_commitment() override; + + std::pair compute_nullifier() override; + + // std::pair> compute_partial_commitment() override; + + static fr compute_nullifier(fr const& commitment, + fr const& owner_private_key, + boolean const& is_real_commitment = true); + + // static fr compute_dummy_nullifier(fr const& dummy_commitment, fr const& owner_private_key); + + NotePreimage& get_preimage() { return note_preimage; }; + + private: + bool check_if_partial() const; + + // bool check_if_partial() const = 0; + + std::optional commitment; + std::optional nullifier; + std::optional partial_commitment; + + bool is_partial = false; + + NotePreimage note_preimage; + std::optional nullifier_preimage; +}; + +} // namespace aztec3::circuits::apps::notes + +// Importing in this way (rather than explicit instantiation of a template class at the bottom of a .cpp file) preserves +// the following: +// - We retain implicit instantiation of templates, meaning we can pick and choose (with static_assert) which class +// methods support native, +// circuit or both types. +// - We don't implement method definitions in this file, to avoid a circular dependency with state_factory.hpp. +#include "note.tpp" \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.tpp b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.tpp new file mode 100644 index 00000000000..e9ba26c6f12 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.tpp @@ -0,0 +1,254 @@ +#include "note_preimage.hpp" +#include "nullifier_preimage.hpp" + +#include "../../oracle_wrapper.hpp" + +#include + +#include + +#include +#include +#include +#include +#include +#include + +namespace aztec3::circuits::apps::notes { + +namespace { +using aztec3::GeneratorIndex; +using crypto::pedersen::generator_index_t; +using plonk::stdlib::witness_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; +} // namespace + +// template +// DefaultPrivateNote::DefaultPrivateNote(PrivateStateVar& private_state_var, +// DefaultPrivateNotePreimage preimage, +// bool commit_on_init) +// : private_state_var(private_state_var) +// , preimage(preimage) +// , is_partial(check_if_partial()) +// { +// if (commit_on_init) { +// if (is_partial) { +// partial_commitment = compute_partial_commitment(); +// } else { +// commitment = compute_commitment(); +// } +// } +// } + +template void DefaultPrivateNote::remove() +{ + auto [nullifier, nullifier_preimage] = compute_nullifier(); + + // TODO: implement this function! + (void)nullifier; + (void)nullifier_preimage; +} + +template bool DefaultPrivateNote::check_if_partial() const +{ + const auto& [value, owner, creator_address, memo, salt, nonce, _] = this->note_preimage; + + if (!value || !owner || !creator_address || !memo || !salt || !nonce) { + return true; + } + if (utxo_state_var->is_partial_slot) { + return true; + } + return false; +} + +// eclaration is incompatible with "std::pair< +// aztec3::circuits::apps::notes::DefaultPrivateNote::fr, +// aztec3::circuits::apps::notes::DefaultPrivateNote::NotePreimage > +// aztec3::circuits::apps::notes::DefaultPrivateNote::compute_commitment() " + +// template +// std::pair::fr, +// typename DefaultPrivateNote::NotePreimage> +template +std::pair::fr, DefaultPrivateNotePreimage, V>> +DefaultPrivateNote::compute_commitment() +{ + if (commitment.has_value()) { + return std::make_pair(*commitment, this->note_preimage); + } + + grumpkin_point storage_slot_point = utxo_state_var->storage_slot_point; + + std::vector inputs; + std::vector generators; + + auto gen_pair_address = [&](std::optional
const& input, size_t const hash_sub_index) { + if (!input) { + throw_or_abort("Cannot commit to a partial preimage. Call compute_partial_commitment instead, or complete " + "the preimage."); + } + return std::make_pair((*input).to_field(), generator_index_t({ GeneratorIndex::COMMITMENT, hash_sub_index })); + }; + + auto gen_pair_fr = [&](std::optional const& input, size_t const hash_sub_index) { + if (!input) { + throw_or_abort("Cannot commit to a partial preimage. Call compute_partial_commitment instead, or complete " + "the preimage."); + } + return std::make_pair(*input, generator_index_t({ GeneratorIndex::COMMITMENT, hash_sub_index })); + }; + + const auto& [value, owner, creator_address, memo, salt, nonce, is_real] = this->note_preimage; + + const auto commitment_point = + storage_slot_point + + CT::commit( + { gen_pair_fr(value, PrivateStateNoteGeneratorIndex::VALUE), + gen_pair_address(owner, PrivateStateNoteGeneratorIndex::OWNER), + gen_pair_address(creator_address, PrivateStateNoteGeneratorIndex::CREATOR), + gen_pair_fr(memo, PrivateStateNoteGeneratorIndex::MEMO), + gen_pair_fr(salt, PrivateStateNoteGeneratorIndex::SALT), + gen_pair_fr(nonce, PrivateStateNoteGeneratorIndex::NONCE), + std::make_pair(is_real, + generator_index_t({ GeneratorIndex::COMMITMENT, PrivateStateNoteGeneratorIndex::IS_REAL })) + + }); + + commitment = commitment_point.x; + + return std::make_pair(*commitment, note_preimage); +} + +// template +// typename CircuitTypes::grumpkin_point DefaultPrivateNote::compute_partial_commitment() const +// { +// if (partial_commitment.has_value()) { +// info( +// "WARNING: you've already computed a partial commitment for this note. Now, you might have since changed " +// "the preimage and you want to update the partial commitment, and that's ok, so we won't throw an error " +// "here. But if that's not the case, you should call get_partial_commitment() instead, to save +// constraints."); +// } + +// grumpkin_point storage_slot_point = private_state_var.storage_slot_point; + +// std::vector inputs; +// std::vector generators; + +// auto gen_pair_address = [&](std::optional
const& input, size_t const hash_sub_index) { +// return input ? std::make_pair((*input).to_field(), +// generator_index_t({ GeneratorIndex::COMMITMENT, hash_sub_index })) +// : std::make_pair(fr(1), +// generator_index_t({ GeneratorIndex::COMMITMENT_PLACEHOLDER, hash_sub_index })); +// }; + +// auto gen_pair_fr = [&](std::optional const& input, size_t const hash_sub_index) { +// return input ? std::make_pair(*input, generator_index_t({ GeneratorIndex::COMMITMENT, hash_sub_index })) +// : std::make_pair(fr(1), +// generator_index_t({ GeneratorIndex::COMMITMENT_PLACEHOLDER, hash_sub_index })); +// }; + +// const auto& [start_slot, +// mapping_key_values_by_key_name, +// value, +// owner, +// creator_address, +// salt, +// nonce, +// memo, +// is_real] = preimage; + +// return storage_slot_point + +// CT::commit({ gen_pair_fr(value, PrivateStateNoteGeneratorIndex::VALUE), +// gen_pair_address(owner, PrivateStateNoteGeneratorIndex::OWNER), +// gen_pair_address(creator_address, PrivateStateNoteGeneratorIndex::CREATOR), +// gen_pair_fr(salt, PrivateStateNoteGeneratorIndex::SALT), +// gen_pair_fr(nonce, PrivateStateNoteGeneratorIndex::NONCE), +// gen_pair_fr(memo, PrivateStateNoteGeneratorIndex::MEMO), +// std::make_pair( +// is_real, +// generator_index_t({ GeneratorIndex::COMMITMENT, PrivateStateNoteGeneratorIndex::IS_REAL +// })) + +// }); +// } + +template +std::pair::fr, DefaultPrivateNoteNullifierPreimage>> +DefaultPrivateNote::compute_nullifier() +{ + if (is_partial) { + throw_or_abort("Can't nullify a partial note."); + } + if (!commitment) { + throw_or_abort("Commitment not yet calculated. Call compute_commitment() or change how you initialise this " + "note to include the `commit_on_init` bool."); + } + if (nullifier && nullifier_preimage) { + return std::make_pair(*nullifier, *nullifier_preimage); + } + + fr& owner_private_key = this->utxo_state_var->exec_ctx->oracle.get_msg_sender_private_key(); + + nullifier = + DefaultPrivateNote::compute_nullifier(*commitment, owner_private_key, note_preimage.is_real); + nullifier_preimage = { + *commitment, + owner_private_key, + note_preimage.is_real, + }; + return std::make_pair(*nullifier, *nullifier_preimage); +}; + +template +typename CircuitTypes::fr DefaultPrivateNote::compute_nullifier( + fr const& commitment, fr const& owner_private_key, boolean const& is_real_commitment) +{ + /** + * Hashing the private key in this way enables the following use case: + * - A user can demonstrate to a 3rd party that they have spent a note, by providing the + hashed_private_key + * and the note_commitment. The 3rd party can then recalculate the nullifier. This does not reveal the + * underlying private_key to the 3rd party. */ + const grumpkin_point hashed_private_key = CT::grumpkin_group::template fixed_base_scalar_mul<254>( + owner_private_key, GeneratorIndex::NULLIFIER_HASHED_PRIVATE_KEY); + + const std::vector hash_inputs{ + commitment, + hashed_private_key.x, + hashed_private_key.y, + is_real_commitment, + }; + + // We compress the hash_inputs with Pedersen, because that's cheaper (constraint-wise) than compressing + // the data directly with Blake2s in the next step. + const fr compressed_inputs = CT::compress(hash_inputs, GeneratorIndex::NULLIFIER); + + // Blake2s hash the compressed result. Without this it's possible to leak info from the pedersen + // compression. + /** E.g. we can extract a representation of the hashed_pk: + * Paraphrasing, if: + * nullifier = note_comm * G1 + hashed_pk * G2 + is_real_note * G3 + * Then an observer can derive hashed_pk * G2 = nullifier - note_comm * G1 - is_real_note * G3 + * They can derive this for every tx, to link which txs are being sent by the same user. + * Notably, at the point someone withdraws, the observer would be able to connect `hashed_pk * G2` with a + * specific eth address. + */ + auto blake_input = typename CT::byte_array(compressed_inputs); + auto blake_result = CT::blake2s(blake_input); + return fr(blake_result); +}; + +// template +// typename CircuitTypes::fr DefaultPrivateNote::compute_dummy_nullifier(fr const& dummy_commitment, +// fr const& +// owner_private_key) +// { +// return DefaultPrivateNote::compute_nullifier(dummy_commitment, owner_private_key, false); +// } + +// template class DefaultPrivateNote; + +} // namespace aztec3::circuits::apps::notes \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note_preimage.hpp b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note_preimage.hpp new file mode 100644 index 00000000000..122ea448840 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note_preimage.hpp @@ -0,0 +1,144 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace aztec3::circuits::apps::notes { + +using crypto::pedersen::generator_index_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; + +template struct DefaultPrivateNotePreimage { + typedef typename NCT::fr fr; + typedef typename NCT::grumpkin_point grumpkin_point; + typedef typename NCT::address address; + typedef typename NCT::boolean boolean; + + // No custom constructors so that designated initializers can be used (for readability of test circuits). + + std::optional value; + std::optional
owner; + std::optional
creator_address; + std::optional memo; // numerical representation of a string + + std::optional salt; + std::optional nonce; + + boolean is_real; + + bool operator==(DefaultPrivateNotePreimage const&) const = default; + + template auto to_circuit_type(Composer& composer) const + { + static_assert((std::is_same::value)); + + // Capture the composer: + auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + + // Depending on whether the _circuit_ type version of `V` is from the stdlib, or some custom type, the + // conversion method will be different. + const bool has_to_circuit_type = requires(V v) { v.to_circuit_type(); }; + const bool has_to_ct = requires(V v) { to_ct(v); }; + + // To avoid messy template arguments in the calling code, we use a lambda functino with `auto` return type to + // avoid explicitly having to state the circuit type for `V`. + auto circuit_value = [&]() -> auto + { + if constexpr (has_to_circuit_type) { + return value.to_circuit_type(); + } else if (has_to_ct) { + return to_ct(value); + } else { + throw_or_abort("Can't convert Value to circuit type"); + } + } + (); + + // When this method is called, this class must be templated over native types. We can avoid templating over the + // circuit types (for the return values) (in order to make the calling syntax cleaner) with the below `decltype` + // deduction of the _circuit_ version of template type `V`. + DefaultPrivateNotePreimage, typename decltype(circuit_value)::value_type> preimage = { + circuit_value, to_ct(owner), to_ct(creator_address), to_ct(memo), to_ct(salt), to_ct(nonce), to_ct(is_real), + }; + + return preimage; + }; + + template auto to_native_type() const + { + + static_assert(!std::is_same::value); + + auto to_nt = [&](auto& e) { return plonk::stdlib::types::to_nt(e); }; + + // See `to_circuit_type()` for explanation of this code. + const bool has_to_native_type = requires(V v) { v.to_native_type(); }; + const bool has_to_nt = requires(V v) { to_nt(v); }; + + auto native_value = [&]() -> auto + { + if constexpr (has_to_native_type) { + return value.to_native_type(); + } else if (has_to_nt) { + return to_nt(value); + } else { + throw_or_abort("Can't convert Value to native type"); + } + } + (); + + DefaultPrivateNotePreimage preimage = { + native_value, to_nt(owner), to_nt(creator_address), to_nt(memo), to_nt(salt), to_nt(nonce), to_nt(is_real), + }; + + return preimage; + }; +}; + +template void read(uint8_t const*& it, DefaultPrivateNotePreimage& preimage) +{ + using serialize::read; + + read(it, preimage.value); + read(it, preimage.owner); + read(it, preimage.creator_address); + read(it, preimage.memo); + read(it, preimage.salt); + read(it, preimage.nonce); + read(it, preimage.is_real); +}; + +template +void write(std::vector& buf, DefaultPrivateNotePreimage const& preimage) +{ + using serialize::write; + + write(buf, preimage.value); + write(buf, preimage.owner); + write(buf, preimage.creator_address); + write(buf, preimage.memo); + write(buf, preimage.salt); + write(buf, preimage.nonce); + write(buf, preimage.is_real); +}; + +template +std::ostream& operator<<(std::ostream& os, DefaultPrivateNotePreimage const& preimage) +{ + return os << "value: " << preimage.value << "\n" + << "owner: " << preimage.owner << "\n" + << "creator_address: " << preimage.creator_address << "\n" + << "memo: " << preimage.memo << "\n" + << "salt: " << preimage.salt << "\n" + << "nonce: " << preimage.nonce << "\n" + << "is_real: " << preimage.is_real << "\n"; +} + +// template using MappingKeyValues = std::map>; + +} // namespace aztec3::circuits::apps::notes \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/notes/default_private_note/nullifier_preimage.hpp b/circuits/src/aztec3/circuits/apps/notes/default_private_note/nullifier_preimage.hpp new file mode 100644 index 00000000000..eee508234cb --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/notes/default_private_note/nullifier_preimage.hpp @@ -0,0 +1,69 @@ +#pragma once +#include +#include +#include +#include +#include +#include + +namespace aztec3::circuits::apps::notes { + +using crypto::pedersen::generator_index_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; + +template struct DefaultPrivateNoteNullifierPreimage { + typedef typename NCT::fr fr; + typedef typename NCT::boolean boolean; + + fr commitment; + fr owner_private_key; + boolean is_real; + + bool operator==(DefaultPrivateNoteNullifierPreimage const&) const = default; + + template + DefaultPrivateNoteNullifierPreimage> to_circuit_type(Composer& composer) const + { + static_assert((std::is_same::value)); + + // Capture the composer: + auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + + DefaultPrivateNoteNullifierPreimage> preimage = { + to_ct(commitment), + to_ct(owner_private_key), + to_ct(is_real), + }; + + return preimage; + }; +}; + +template void read(uint8_t const*& it, DefaultPrivateNoteNullifierPreimage& preimage) +{ + using serialize::read; + + read(it, preimage.commitment); + read(it, preimage.owner_private_key); + read(it, preimage.is_real); +}; + +template void write(std::vector& buf, DefaultPrivateNoteNullifierPreimage const& preimage) +{ + using serialize::write; + + write(buf, preimage.commitment); + write(buf, preimage.owner_private_key); + write(buf, preimage.is_real); +}; + +template +std::ostream& operator<<(std::ostream& os, DefaultPrivateNoteNullifierPreimage const& preimage) +{ + return os << "commitment: " << preimage.commitment << "\n" + << "owner_private_key: " << preimage.owner_private_key << "\n" + << "is_real: " << preimage.is_real << "\n"; +} + +} // namespace aztec3::circuits::apps::notes \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/notes/note_interface.hpp b/circuits/src/aztec3/circuits/apps/notes/note_interface.hpp new file mode 100644 index 00000000000..c48c7042e84 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/notes/note_interface.hpp @@ -0,0 +1,71 @@ +#pragma once + +// #include "../state_vars/utxo_state_var.hpp" + +#include +#include + +namespace aztec3::circuits::apps::notes { + +using aztec3::circuits::apps::state_vars::UTXOStateVar; + +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; + +// template class UTXOStateVar; +// template class FunctionExecutionContext; + +// template struct PrivateStateNotePreimage; + +template class NoteInterface { + public: + typedef CircuitTypes CT; + typedef typename CT::fr fr; + typedef typename CT::grumpkin_point grumpkin_point; + typedef typename CT::address address; + typedef typename CT::boolean boolean; + + // bool operator==(PrivateStateNote const&) const = default; + + // UTXOStateVar* utxo_state_var; + + // NoteInterface(UTXOStateVar* utxo_state_var, NotePreimage note_preimage) + // : utxo_state_var(utxo_state_var) + // , note_preimage(note_preimage){}; + + // METHODS + + virtual void remove() = 0; + + // HOOKS + + virtual fr get_commitment() = 0; + + virtual fr get_nullifier() = 0; + + // virtual grumpkin_point get_partial_commitment() const = 0; + + // virtual NotePreimage get_note_preimage() const = 0; + + // virtual NullifierPreimageTmp get_nullifier_preimage() const = 0; + + virtual std::pair compute_commitment() = 0; + + virtual std::pair compute_nullifier() = 0; + + // virtual std::pair compute_partial_commitment() = 0; + + // STATIC HOOKS: + + // static fr compute_dummy_commitment() = 0; + + // static fr compute_nullifier(fr const& commitment, + // fr const& owner_private_key, + // boolean const& is_real_commitment = true) = 0; + + // static fr compute_dummy_nullifier(fr const& dummy_commitment, fr const& owner_private_key) = 0; + // private: + // std::optional note_preimage; +}; + +} // namespace aztec3::circuits::apps::notes \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/opcodes/opcodes.hpp b/circuits/src/aztec3/circuits/apps/opcodes/opcodes.hpp new file mode 100644 index 00000000000..b41b54624a6 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/opcodes/opcodes.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include "../state_vars/utxo_state_var.hpp" + +#include +#include +#include + +namespace aztec3::circuits::apps::opcodes { + +using aztec3::circuits::apps::state_vars::UTXOStateVar; + +using plonk::stdlib::witness_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; + +template class Opcodes { + public: + typedef CircuitTypes CT; + typedef NativeTypes NT; + + /** + * @brief Load a singleton UTXOSLoadDatum from the Private Client's DB. + */ + template + static Note UTXO_SLOAD(UTXOStateVar* utxo_state_var, typename Note::NotePreimage const& advice); +}; + +} // namespace aztec3::circuits::apps::opcodes + +// - We don't implement method definitions in this file, to avoid a circular dependency with +// utxo_state_var.hpp. +#include "opcodes.tpp" diff --git a/circuits/src/aztec3/circuits/apps/opcodes/opcodes.tpp b/circuits/src/aztec3/circuits/apps/opcodes/opcodes.tpp new file mode 100644 index 00000000000..582d67a1544 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/opcodes/opcodes.tpp @@ -0,0 +1,44 @@ +#pragma once + +#include "../utxo_datum.hpp" + +#include "../state_vars/state_var_base.hpp" +#include "../state_vars/utxo_state_var.hpp" + +#include +#include +#include + +namespace aztec3::circuits::apps::opcodes { + +using aztec3::circuits::apps::state_vars::UTXOStateVar; + +using plonk::stdlib::witness_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; + +template +template +Note Opcodes::UTXO_SLOAD(UTXOStateVar* utxo_state_var, + typename Note::NotePreimage const& advice) +{ + auto& oracle = utxo_state_var->exec_ctx->oracle; + + typename CT::grumpkin_point& storage_slot_point = utxo_state_var->storage_slot_point; + + UTXOSLoadDatum utxo_datum = + oracle.template get_utxo_sload_datum(storage_slot_point, advice); + + Note new_note{ utxo_state_var, utxo_datum.preimage }; + + oracle.get_contract_address().assert_equal(utxo_datum.contract_address, "UTXO_SLOAD: bad contract address"); + + new_note.get_commitment().assert_equal(utxo_datum.commitment, "UTXO_SLOAD: bad commitment"); + + // TODO within this function: + // - Merkle Membership Check using utxo_datum.{sibling_path, leaf_index, old_private_data_tree_root} + + return new_note; +}; + +} // namespace aztec3::circuits::apps::opcodes diff --git a/circuits/src/aztec3/circuits/apps/oracle_wrapper.hpp b/circuits/src/aztec3/circuits/apps/oracle_wrapper.hpp index 3132f5fba6d..d00c0d1941e 100644 --- a/circuits/src/aztec3/circuits/apps/oracle_wrapper.hpp +++ b/circuits/src/aztec3/circuits/apps/oracle_wrapper.hpp @@ -15,13 +15,17 @@ using aztec3::oracle::NativeOracle; using plonk::stdlib::types::CircuitTypes; /** - * The main purpose of this wrapper is to cache values which have been already given by the oracle. Insecure circuits - * could be built if the same value is queried twice from the oracle (since a malicious prover could provide two - * different witnesses for a single thing). + * The main purpose of this wrapper is to: + * - cache values which have been already given by the oracle previously during this execution; + * - convert Native types (returned by the oracle) into circuit types, using the composer instance. + * Note: Insecure circuits could be built if the same value is queried twice from the oracle (since a malicious prover + * could provide two different witnesses for a single thing). The Native oracle will throw if you try a double-query of + * certain information. */ template class OracleWrapperInterface { typedef CircuitTypes CT; typedef typename CT::fr fr; + typedef typename CT::grumpkin_point grumpkin_point; typedef typename CT::address address; public: @@ -44,6 +48,8 @@ template class OracleWrapperInterface { return *msg_sender_private_key; }; + address get_contract_address() { return get_call_context().storage_contract_address; }; + CallContext& get_call_context() { if (call_context) { @@ -76,6 +82,18 @@ template class OracleWrapperInterface { native_preimages.second.to_circuit_type(composer)); } + template + auto get_utxo_sload_datum(grumpkin_point const& storage_slot_point, NotePreimage const& advice) + { + auto native_storage_slot_point = plonk::stdlib::types::to_nt(storage_slot_point); + + auto native_advice = advice.template to_native_type(); + + auto native_utxo_sload_datum = oracle.get_utxo_sload_datum(native_storage_slot_point, native_advice); + + return native_utxo_sload_datum.to_circuit_type(composer); + } + private: std::optional> call_context; std::optional msg_sender_private_key; diff --git a/circuits/src/aztec3/circuits/apps/private_state.test.cpp b/circuits/src/aztec3/circuits/apps/private_state.test.cpp index 0fcde74de33..e9304ccc511 100644 --- a/circuits/src/aztec3/circuits/apps/private_state.test.cpp +++ b/circuits/src/aztec3/circuits/apps/private_state.test.cpp @@ -23,7 +23,7 @@ class private_state_tests : public ::testing::Test {}; // TEST(private_state_tests, test_native_private_state) // { // StateFactory state_factory("MyContract"); -// PrivateStateVar x = state_factory.new_private_state("x"); +// PrivateStateVar x = state_factory.declare_private_state_var("x"); // PrivateStateVar native_private_state = PrivateStateVar(x); @@ -38,9 +38,9 @@ class private_state_tests : public ::testing::Test {}; // { // StateFactory state_factory("MyContract"); -// state_factory.new_private_state("balances", { "asset_id", "owner_address" }); +// state_factory.declare_private_state_var("balances", { "asset_id", "owner" }); -// state_factory.new_private_state("x"); +// state_factory.declare_private_state_var("x"); // // info("state_factory: ", state_factory); // } @@ -48,14 +48,14 @@ class private_state_tests : public ::testing::Test {}; // TEST(private_state_tests, test_native_private_state_note_preimage) // { // StateFactory state_factory("MyContract"); -// PrivateStateVar x = state_factory.new_private_state("x"); +// PrivateStateVar x = state_factory.declare_private_state_var("x"); // PrivateStateNotePreimage native_preimage = { // .value = 2, -// .owner_address = 3, +// .owner = 3, // .creator_address = NT::address(4), // .salt = 5, -// .input_nullifier = 6, +// .nonce = 6, // .memo = 7, // }; @@ -69,15 +69,16 @@ class private_state_tests : public ::testing::Test {}; // TEST(private_state_tests, test_native_private_state_note_preimage_mapping) // { // StateFactory state_factory("MyContract"); -// PrivateStateVar x = state_factory.new_private_state("x", { "mapping_key_name_1", "mapping_key_name_2" }); +// PrivateStateVar x = state_factory.declare_private_state_var("x", { "mapping_key_name_1", "mapping_key_name_2" +// }); // PrivateStateNotePreimage native_preimage = { // .mapping_key_values_by_key_name = std::map>({ { "mapping_key_name_2", 5 } }), // .value = 2, -// .owner_address = 3, +// .owner = 3, // .creator_address = NT::address(4), // .salt = 5, -// .input_nullifier = 6, +// .nonce = 6, // .memo = 7, // }; @@ -91,15 +92,16 @@ class private_state_tests : public ::testing::Test {}; // TEST(private_state_tests, test_native_private_state_note_mapping) // { // StateFactory state_factory("MyContract"); -// PrivateStateVar x = state_factory.new_private_state("x", { "mapping_key_name_1", "mapping_key_name_2" }); +// PrivateStateVar x = state_factory.declare_private_state_var("x", { "mapping_key_name_1", "mapping_key_name_2" +// }); // PrivateStateNotePreimage private_state_preimage = { // .mapping_key_values_by_key_name = std::map>({ { "mapping_key_name_2", 5 } }), // .value = 2, -// .owner_address = 3, +// .owner = 3, // .creator_address = NT::address(4), // .salt = 5, -// .input_nullifier = 6, +// .nonce = 6, // .memo = 7, // }; diff --git a/circuits/src/aztec3/circuits/apps/private_state_note.tpp b/circuits/src/aztec3/circuits/apps/private_state_note.tpp index b8e297b0589..abf9f3d658e 100644 --- a/circuits/src/aztec3/circuits/apps/private_state_note.tpp +++ b/circuits/src/aztec3/circuits/apps/private_state_note.tpp @@ -42,10 +42,9 @@ PrivateStateNote::PrivateStateNote(PrivateStateVar& private_ template bool PrivateStateNote::check_if_partial() const { - const auto& [start_slot, slot_point, value, owner_address, creator_address, salt, input_nullifier, memo, _] = - preimage; + const auto& [start_slot, storage_slot_point, value, owner, creator_address, salt, nonce, memo, _] = preimage; - if (!value || !owner_address || !creator_address || !salt || !input_nullifier || !memo) { + if (!value || !owner || !creator_address || !salt || !nonce || !memo) { return true; } if (private_state_var.is_partial_slot) { @@ -60,7 +59,7 @@ template typename CircuitTypes::fr PrivateStateNot return *commitment; } - grumpkin_point slot_point = private_state_var.slot_point; + grumpkin_point storage_slot_point = private_state_var.storage_slot_point; std::vector inputs; std::vector generators; @@ -84,21 +83,21 @@ template typename CircuitTypes::fr PrivateStateNot const auto& [start_slot, mapping_key_values_by_key_name, value, - owner_address, + owner, creator_address, salt, - input_nullifier, + nonce, memo, is_real] = preimage; const auto commitment_point = - slot_point + + storage_slot_point + CT::commit( { gen_pair_fr(value, PrivateStateNoteGeneratorIndex::VALUE), - gen_pair_address(owner_address, PrivateStateNoteGeneratorIndex::OWNER), + gen_pair_address(owner, PrivateStateNoteGeneratorIndex::OWNER), gen_pair_address(creator_address, PrivateStateNoteGeneratorIndex::CREATOR), gen_pair_fr(salt, PrivateStateNoteGeneratorIndex::SALT), - gen_pair_fr(input_nullifier, PrivateStateNoteGeneratorIndex::INPUT_NULLIFIER), + gen_pair_fr(nonce, PrivateStateNoteGeneratorIndex::NONCE), gen_pair_fr(memo, PrivateStateNoteGeneratorIndex::MEMO), std::make_pair(is_real, generator_index_t({ GeneratorIndex::COMMITMENT, PrivateStateNoteGeneratorIndex::IS_REAL })) @@ -118,7 +117,7 @@ typename CircuitTypes::grumpkin_point PrivateStateNote::comp "here. But if that's not the case, you should call get_partial_commitment() instead, to save constraints."); } - grumpkin_point slot_point = private_state_var.slot_point; + grumpkin_point storage_slot_point = private_state_var.storage_slot_point; std::vector inputs; std::vector generators; @@ -139,24 +138,25 @@ typename CircuitTypes::grumpkin_point PrivateStateNote::comp const auto& [start_slot, mapping_key_values_by_key_name, value, - owner_address, + owner, creator_address, salt, - input_nullifier, + nonce, memo, is_real] = preimage; - return slot_point + CT::commit({ gen_pair_fr(value, PrivateStateNoteGeneratorIndex::VALUE), - gen_pair_address(owner_address, PrivateStateNoteGeneratorIndex::OWNER), - gen_pair_address(creator_address, PrivateStateNoteGeneratorIndex::CREATOR), - gen_pair_fr(salt, PrivateStateNoteGeneratorIndex::SALT), - gen_pair_fr(input_nullifier, PrivateStateNoteGeneratorIndex::INPUT_NULLIFIER), - gen_pair_fr(memo, PrivateStateNoteGeneratorIndex::MEMO), - std::make_pair(is_real, - generator_index_t({ GeneratorIndex::COMMITMENT, - PrivateStateNoteGeneratorIndex::IS_REAL })) - - }); + return storage_slot_point + + CT::commit({ gen_pair_fr(value, PrivateStateNoteGeneratorIndex::VALUE), + gen_pair_address(owner, PrivateStateNoteGeneratorIndex::OWNER), + gen_pair_address(creator_address, PrivateStateNoteGeneratorIndex::CREATOR), + gen_pair_fr(salt, PrivateStateNoteGeneratorIndex::SALT), + gen_pair_fr(nonce, PrivateStateNoteGeneratorIndex::NONCE), + gen_pair_fr(memo, PrivateStateNoteGeneratorIndex::MEMO), + std::make_pair( + is_real, + generator_index_t({ GeneratorIndex::COMMITMENT, PrivateStateNoteGeneratorIndex::IS_REAL })) + + }); } template diff --git a/circuits/src/aztec3/circuits/apps/private_state_note_preimage.hpp b/circuits/src/aztec3/circuits/apps/private_state_note_preimage.hpp index ec8209f7528..b5a247c70a6 100644 --- a/circuits/src/aztec3/circuits/apps/private_state_note_preimage.hpp +++ b/circuits/src/aztec3/circuits/apps/private_state_note_preimage.hpp @@ -20,15 +20,18 @@ template struct PrivateStateNotePreimage { // No custom constructors so that designated initializers can be used (for readability of test circuits). - std::optional start_slot; // TODO: remove optionality - std::optional slot_point; // TODO: remove optionality? + std::optional start_slot; // TODO: remove optionality + std::optional storage_slot_point; // TODO: remove optionality? + + // TODO: MAKE THIS A PAYLOAD LIKE ZEXE????? std::optional value; - std::optional
owner_address; + std::optional
owner; std::optional
creator_address; - std::optional salt; - std::optional input_nullifier; std::optional memo; // numerical representation of a string + std::optional salt; + std::optional nonce; + boolean is_real; bool operator==(PrivateStateNotePreimage const&) const = default; @@ -42,12 +45,29 @@ template struct PrivateStateNotePreimage { auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; PrivateStateNotePreimage> preimage = { - to_ct(start_slot), to_ct(slot_point), to_ct(value), to_ct(owner_address), to_ct(creator_address), - to_ct(salt), to_ct(input_nullifier), to_ct(memo), to_ct(is_real), + to_ct(start_slot), + to_ct(storage_slot_point), + to_ct(value), + to_ct(owner), + to_ct(creator_address), + to_ct(memo), + to_ct(salt), + to_ct(nonce), + to_ct(is_real), }; return preimage; }; + + fr hash() const {} + + PrivateStateNotePreimage utxo_sload_hook(){}; + + PrivateStateNotePreimage utxo_sstore_hook(){ + // maybe call the oracle to generate a salt? But that would require us to pass in the oracle, which feels messy + // / wrong... + // We'd also need to generate a nonce... + }; }; template void read(uint8_t const*& it, PrivateStateNotePreimage& preimage) @@ -55,13 +75,13 @@ template void read(uint8_t const*& it, PrivateStateNotePreimage void write(std::vector& buf, PrivateStateNotePr using serialize::write; write(buf, preimage.start_slot); - write(buf, preimage.slot_point); + write(buf, preimage.storage_slot_point); write(buf, preimage.value); - write(buf, preimage.owner_address); + write(buf, preimage.owner); write(buf, preimage.creator_address); - write(buf, preimage.salt); - write(buf, preimage.input_nullifier); write(buf, preimage.memo); + write(buf, preimage.salt); + write(buf, preimage.nonce); write(buf, preimage.is_real); }; template std::ostream& operator<<(std::ostream& os, PrivateStateNotePreimage const& preimage) { return os << "start_slot: " << preimage.start_slot << "\n" - << "slot_point: " << preimage.slot_point << "\n" + << "storage_slot_point: " << preimage.storage_slot_point << "\n" << "value: " << preimage.value << "\n" - << "owner_address: " << preimage.owner_address << "\n" + << "owner: " << preimage.owner << "\n" << "creator_address: " << preimage.creator_address << "\n" - << "salt: " << preimage.salt << "\n" - << "input_nullifier: " << preimage.input_nullifier << "\n" << "memo: " << preimage.memo << "\n" + << "salt: " << preimage.salt << "\n" + << "nonce: " << preimage.nonce << "\n" << "is_real: " << preimage.is_real << "\n"; } diff --git a/circuits/src/aztec3/circuits/apps/private_state_operand.hpp b/circuits/src/aztec3/circuits/apps/private_state_operand.hpp index 3caac8a09d7..7c171c6f914 100644 --- a/circuits/src/aztec3/circuits/apps/private_state_operand.hpp +++ b/circuits/src/aztec3/circuits/apps/private_state_operand.hpp @@ -17,7 +17,7 @@ template struct PrivateStateOperand { typedef typename NCT::address address; fr value; - address owner_address; + address owner; std::optional
creator_address; std::optional memo; // numerical representation of a string @@ -32,7 +32,7 @@ template struct PrivateStateOperand { PrivateStateOperand> preimage = { to_ct(value), - to_ct(owner_address), + to_ct(owner), to_ct(creator_address), to_ct(memo), }; diff --git a/circuits/src/aztec3/circuits/apps/private_state_var.hpp b/circuits/src/aztec3/circuits/apps/private_state_var.hpp index 8bb1aa3b10b..b23549d2066 100644 --- a/circuits/src/aztec3/circuits/apps/private_state_var.hpp +++ b/circuits/src/aztec3/circuits/apps/private_state_var.hpp @@ -13,7 +13,6 @@ namespace aztec3::circuits::apps { using plonk::stdlib::types::CircuitTypes; using plonk::stdlib::types::NativeTypes; -// template class PrivateStateFactory; template class FunctionExecutionContext; template class PrivateStateVar { @@ -25,13 +24,13 @@ template class PrivateStateVar { FunctionExecutionContext* exec_ctx; // Pointer, because PrivateStateVar can't hold a reference (because it gets initialised as a member of - // a map within PrivateStateFactory, so might not be passed data upon initialisation) + // a map within the Contract class, so might not be passed data upon initialisation) PrivateStateType private_state_type; std::string name; fr start_slot; - grumpkin_point slot_point; /// TODO: make this std::optional (since mapping vars won't have this (only specific - /// mapping values will))? + grumpkin_point storage_slot_point; /// TODO: make this std::optional (since mapping vars won't have this (only + /// specific mapping values will))? // A mapping var (in particular) can point to many private_states: std::map> private_states; @@ -48,7 +47,7 @@ template class PrivateStateVar { , private_state_type(private_state_var.private_state_type) , name(private_state_var.name) , start_slot(private_state_var.start_slot) - , slot_point(private_state_var.slot_point) + , storage_slot_point(private_state_var.storage_slot_point) , is_mapping(private_state_var.is_mapping) , mapping_key_names(private_state_var.mapping_key_names) , is_partial_slot(private_state_var.is_partial_slot){}; @@ -63,7 +62,7 @@ template class PrivateStateVar { , name(name) , start_slot(start_slot) { - slot_point = compute_start_slot_point(); + storage_slot_point = compute_start_slot_point(); }; // For initialising a mapping var: @@ -109,26 +108,25 @@ template class PrivateStateVar { std::tuple compute_slot_point_at_mapping_keys(std::vector> const& keys); private: - grumpkin_point compute_start_slot_point(); - // For initialising an fr state from within a mapping: PrivateStateVar(FunctionExecutionContext* exec_ctx, PrivateStateType const& private_state_type, std::string const& name, fr const& start_slot, - grumpkin_point const& slot_point, + grumpkin_point const& storage_slot_point, bool const& is_partial_slot) : exec_ctx(exec_ctx) , private_state_type(private_state_type) , name(name) , start_slot(start_slot) - , slot_point(slot_point) + , storage_slot_point(storage_slot_point) , is_partial_slot(is_partial_slot){}; + size_t op_count = 0; + + grumpkin_point compute_start_slot_point(); void arithmetic_checks(); void validate_operand(PrivateStateOperand const& operand) const; - - size_t op_count = 0; }; } // namespace aztec3::circuits::apps diff --git a/circuits/src/aztec3/circuits/apps/private_state_var.tpp b/circuits/src/aztec3/circuits/apps/private_state_var.tpp index 350742c6349..2f248a3495c 100644 --- a/circuits/src/aztec3/circuits/apps/private_state_var.tpp +++ b/circuits/src/aztec3/circuits/apps/private_state_var.tpp @@ -1,14 +1,17 @@ #pragma once -// #include + #include "oracle_wrapper.hpp" #include "private_state_note.hpp" #include "private_state_note_preimage.hpp" #include "private_state_operand.hpp" -#include "plonk/composer/turbo_composer.hpp" #include #include + #include + +#include + #include #include #include @@ -25,7 +28,7 @@ using plonk::stdlib::types::NativeTypes; template typename CircuitTypes::grumpkin_point PrivateStateVar::compute_start_slot_point() { - return CT::commit({ start_slot }, { PrivateStateNoteGeneratorIndex::MAPPING_SLOT }); + return CT::commit({ start_slot }, { StorageSlotGeneratorIndex::MAPPING_SLOT }); } template @@ -37,14 +40,14 @@ std::tuple PrivateStateVar::compute std::vector> input_pairs; input_pairs.push_back(std::make_pair(start_slot, - generator_index_t({ PrivateStateNoteGeneratorIndex::MAPPING_SLOT, + generator_index_t({ StorageSlotGeneratorIndex::MAPPING_SLOT, 0 }))); // hash_sub_index 0 is reserved for the start_slot. for (size_t i = 0; i < keys.size(); ++i) { if (keys[i]) { input_pairs.push_back( std::make_pair(*keys[i], - generator_index_t({ PrivateStateNoteGeneratorIndex::MAPPING_SLOT, + generator_index_t({ StorageSlotGeneratorIndex::MAPPING_SLOT, i + 1 }))); // hash_sub_index 0 is reserved for the start_slot. } else { // If this mapping key has no mapping_key_value (std::nullopt), then we must be partially committing and @@ -52,9 +55,8 @@ std::tuple PrivateStateVar::compute // So use a placeholder generator for this mapping key, to signify "this mapping key is missing". // Note: we can't just commit to a value of `0` for this mapping key, since `0` is a valid value to // commit to, and so "missing" is distinguished as follows. - input_pairs.push_back( - std::make_pair(NativeTypes::fr(1), - generator_index_t({ PrivateStateNoteGeneratorIndex::MAPPING_SLOT_PLACEHOLDER, i + 1 }))); + input_pairs.push_back(std::make_pair( + NativeTypes::fr(1), generator_index_t({ StorageSlotGeneratorIndex::MAPPING_SLOT_PLACEHOLDER, i + 1 }))); } } @@ -70,14 +72,14 @@ std::tuple::grumpkin_point, bool> PrivateStateVa std::vector> input_pairs; input_pairs.push_back(std::make_pair(start_slot, - generator_index_t({ PrivateStateNoteGeneratorIndex::MAPPING_SLOT, + generator_index_t({ StorageSlotGeneratorIndex::MAPPING_SLOT, 0 }))); // hash_sub_index 0 is reserved for the start_slot. for (size_t i = 0; i < keys.size(); ++i) { if (keys[i]) { input_pairs.push_back( std::make_pair(*keys[i], - generator_index_t({ PrivateStateNoteGeneratorIndex::MAPPING_SLOT, + generator_index_t({ StorageSlotGeneratorIndex::MAPPING_SLOT, i + 1 }))); // hash_sub_index 0 is reserved for the start_slot. } else { // If this mapping key has no mapping_key_value (std::nullopt), then we must be partially committing and @@ -86,7 +88,7 @@ std::tuple::grumpkin_point, bool> PrivateStateVa // Note: we can't just commit to a value of `0` for this mapping key, since `0` is a valid value to // commit to, and so "missing" is distinguished as follows. input_pairs.push_back(std::make_pair( - fr(1), generator_index_t({ PrivateStateNoteGeneratorIndex::MAPPING_SLOT_PLACEHOLDER, i + 1 }))); + fr(1), generator_index_t({ StorageSlotGeneratorIndex::MAPPING_SLOT_PLACEHOLDER, i + 1 }))); } } @@ -197,6 +199,7 @@ void PrivateStateVar::validate_operand(PrivateStateOperand const& } } +// TODO: move this to a new PrivateState class. template void PrivateStateVar::add(PrivateStateOperand> const& operand) { @@ -208,13 +211,13 @@ void PrivateStateVar::add(PrivateStateOperand> PrivateStateNotePreimage new_note_preimage = PrivateStateNotePreimage{ .start_slot = start_slot, - .slot_point = slot_point, + .storage_slot_point = storage_slot_point, .value = operand.value, - .owner_address = operand.owner_address, + .owner = operand.owner, .creator_address = operand.creator_address, - .salt = oracle.generate_salt(), - // .input_nullifier = // this will be injected by the exec_ctx .memo = operand.memo, + .salt = oracle.generate_salt(), + // .nonce = // this will be injected by the exec_ctx at 'finalise' .is_real = plonk::stdlib::types::to_ct(composer, true), }; @@ -237,18 +240,18 @@ void PrivateStateVar::subtract(PrivateStateOperand::subtract(PrivateStateOperand{ .start_slot = start_slot, - .slot_point = slot_point, + .storage_slot_point = storage_slot_point, .value = difference, - .owner_address = operand.owner_address, + .owner = operand.owner, .creator_address = operand.creator_address, - .salt = oracle.generate_salt(), - // .input_nullifier = // this will be injected by the exec_ctx upon `finalise()` .memo = operand.memo, + .salt = oracle.generate_salt(), + // .nonce = // this will be injected by the exec_ctx upon `finalise()` .is_real = plonk::stdlib::types::to_ct(composer, true), }; diff --git a/circuits/src/aztec3/circuits/apps/state_vars/.test.cpp b/circuits/src/aztec3/circuits/apps/state_vars/.test.cpp new file mode 100644 index 00000000000..c607061fcca --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/state_vars/.test.cpp @@ -0,0 +1,166 @@ + +// #include +// #include +// #include + +#include +#include + +#include "index.hpp" +// #include "utxo_state_var.hpp" + +#include "../notes/default_private_note/note.hpp" +#include "../notes/default_private_note/note_preimage.hpp" + +#include "../function_execution_context.hpp" +#include "../oracle_wrapper.hpp" +#include "../utxo_datum.hpp" + +#include + +#include +#include +#include +#include + +namespace { +using C = plonk::stdlib::types::turbo::Composer; +using CT = plonk::stdlib::types::CircuitTypes; +using NT = plonk::stdlib::types::NativeTypes; +using plonk::stdlib::types::to_ct; + +using DB = aztec3::oracle::FakeDB; +using aztec3::oracle::NativeOracle; +using OracleWrapper = aztec3::circuits::apps::OracleWrapperInterface; + +using aztec3::circuits::apps::state_vars::FieldStateVar; +using aztec3::circuits::apps::state_vars::MappingStateVar; +using aztec3::circuits::apps::state_vars::UTXOStateVar; + +using aztec3::circuits::apps::notes::DefaultPrivateNote; +// using aztec3::circuits::apps::notes::DefaultPrivateNotePreimage; + +//******** +// Get rid of ugle `Composer` template arg from our state var types: +template struct SpecialisedTypes { + typedef MappingStateVar mapping; + typedef UTXOStateVar utxo; +}; + +template using Mapping = typename SpecialisedTypes::mapping; + +template using UTXO = typename SpecialisedTypes::utxo; + +using Field = FieldStateVar; + +//******** + +} // namespace + +namespace aztec3::circuits::apps::state_vars { + +class state_var_tests : public ::testing::Test { + private: + DB db; + // No cheating: you have to grab this stuff from the oracle in your tests - hence the 'private' scope. + NT::fr msg_sender_private_key = 123456789; + NT::address contract_address = 12345; + NT::address msg_sender = + NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); + NT::address tx_origin = msg_sender; + + protected: + NativeOracle get_test_native_oracle() + { + return NativeOracle(db, contract_address, msg_sender, tx_origin, msg_sender_private_key); + }; +}; + +TEST_F(state_var_tests, mapping) +{ + C composer; + NativeOracle native_oracle = get_test_native_oracle(); + OracleWrapper oracle = OracleWrapper(composer, native_oracle); + FunctionExecutionContext exec_ctx(composer, oracle); + + CT::fr start_slot = 1; + + Mapping my_mapping(&exec_ctx, "balances", start_slot); + + my_mapping[5] = to_ct(composer, NT::fr(5)); + + info("my_mapping[5]: ", my_mapping[5]); + info("my_mapping[5].start_slot: ", my_mapping[5].start_slot); + info("my_mapping[5].storage_slot_point: ", my_mapping[5].storage_slot_point); +} + +TEST_F(state_var_tests, mapping_within_mapping) +{ + C composer; + NativeOracle native_oracle = get_test_native_oracle(); + OracleWrapper oracle = OracleWrapper(composer, native_oracle); + FunctionExecutionContext exec_ctx(composer, oracle); + + CT::fr start_slot = 1; + + Mapping> my_mapping(&exec_ctx, "balances", start_slot); + + my_mapping[5][6] = 7; + + info(my_mapping[5][6].state_var_name, ": ", my_mapping[5][6]); +} + +TEST_F(state_var_tests, partial_mapping) +{ + C composer; + NativeOracle native_oracle = get_test_native_oracle(); + OracleWrapper oracle = OracleWrapper(composer, native_oracle); + FunctionExecutionContext exec_ctx(composer, oracle); + + CT::fr start_slot = 1; + + Mapping> my_mapping(&exec_ctx, "balances", start_slot); + + my_mapping["?"][6] = 7; + + info(my_mapping["?"][6].state_var_name, ": ", my_mapping["?"][6]); +} + +TEST_F(state_var_tests, utxo_of_default_private_note_fr) +{ + C composer; + NativeOracle native_oracle = get_test_native_oracle(); + OracleWrapper oracle = OracleWrapper(composer, native_oracle); + FunctionExecutionContext exec_ctx(composer, oracle); + + using Note = DefaultPrivateNote; + + // bool sort(NT::uint256 i, NT::uint256 j) + // { + // return (i < j); + // }; + + CT::fr start_slot = 1; + + UTXO my_utxo(&exec_ctx, + "balance", + start_slot); // TODO: handshake with exec_ctx to get the start slot, rather than passing one in. + + const auto& msg_sender = oracle.get_msg_sender(); + + Note old_note = my_utxo.get({ .owner = msg_sender }); + + info("old_note.get_preimage(): ", old_note.get_preimage()); + + old_note.remove(); + + CT::fr new_value = *(old_note.get_preimage().value) + 5; + + info("new_value: ", new_value); + + // my_utxo.insert({ .value = new_value }); + + // storage_slot, { value, owner }, salt, nonce +} + +} // namespace aztec3::circuits::apps::state_vars \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/state_vars/field_state_var.hpp b/circuits/src/aztec3/circuits/apps/state_vars/field_state_var.hpp new file mode 100644 index 00000000000..cbb59881c53 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/state_vars/field_state_var.hpp @@ -0,0 +1,52 @@ +#pragma once + +#include "state_var_base.hpp" +#include "../function_execution_context.hpp" + +#include +#include + +namespace aztec3::circuits::apps::state_vars { + +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; + +template class FieldStateVar : public StateVar { + public: + typedef CircuitTypes CT; + typedef NativeTypes NT; + typedef typename CT::fr fr; + typedef typename CT::grumpkin_point grumpkin_point; + + fr value; + + FieldStateVar& operator=(fr&& other) + { + value = other; + return *this; + } + + FieldStateVar(){}; + + // Instantiate a top-level mapping: + FieldStateVar(FunctionExecutionContext* exec_ctx, std::string const& state_var_name, fr const& start_slot) + : StateVar(exec_ctx, state_var_name, start_slot){}; + + // Instantiate a nested mapping: + FieldStateVar(FunctionExecutionContext* exec_ctx, + std::string const& state_var_name, + grumpkin_point const& storage_slot_point, + size_t level_of_container_nesting, + bool is_partial_slot) + : StateVar( + exec_ctx, state_var_name, storage_slot_point, level_of_container_nesting, is_partial_slot){}; + + bool operator==(FieldStateVar const&) const = default; +}; + +template inline std::ostream& operator<<(std::ostream& os, FieldStateVar const& v) +{ + return os << v.value; +} + +} // namespace aztec3::circuits::apps::state_vars diff --git a/circuits/src/aztec3/circuits/apps/state_vars/index.hpp b/circuits/src/aztec3/circuits/apps/state_vars/index.hpp new file mode 100644 index 00000000000..d0c69b2c882 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/state_vars/index.hpp @@ -0,0 +1,3 @@ +#include "field_state_var.hpp" +#include "mapping_state_var.hpp" +#include "utxo_state_var.hpp" \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.hpp b/circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.hpp new file mode 100644 index 00000000000..31c356e5cf3 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.hpp @@ -0,0 +1,72 @@ +#pragma once + +#include "state_var_base.hpp" +#include "../function_execution_context.hpp" + +#include +#include + +namespace aztec3::circuits::apps::state_vars { + +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; + +/** + * Note: we restrict mapping keys to always be something which is convertible into a `field` type. This is to allow + * storage_slot_points to be computed more easily. You'll notice, therefore, that there's no Key template type. + */ +template class MappingStateVar : public StateVar { + public: + typedef CircuitTypes CT; + typedef NativeTypes NT; + typedef typename CT::fr fr; + typedef typename CT::grumpkin_point grumpkin_point; + + // native_storage_slot.x => value cache, to prevent creating constraints with each `at()` call. + std::map value_cache; + + MappingStateVar(){}; + + // Instantiate a top-level mapping: + MappingStateVar(FunctionExecutionContext* exec_ctx, + std::string const& state_var_name, + fr const& start_slot) + : StateVar(exec_ctx, state_var_name, start_slot){}; + + // Instantiate a nested mapping: + MappingStateVar(FunctionExecutionContext* exec_ctx, + std::string const& state_var_name, + grumpkin_point const& storage_slot_point, + size_t level_of_container_nesting, + bool is_partial_slot) + : StateVar( + exec_ctx, state_var_name, storage_slot_point, level_of_container_nesting, is_partial_slot){}; + + bool operator==(MappingStateVar const&) const = default; + + V& operator[](std::optional const& key) { return this->at(key); }; + V& operator[](std::string const& question_mark) + { + ASSERT(question_mark != "?"); + return this->at(std::nullopt); + }; + + V& at(std::optional const& key); + + static std::tuple compute_slot_point_at_mapping_key(NT::fr const& start_slot, + size_t level_of_container_nesting, + std::optional const& key); + + std::tuple compute_slot_point_at_mapping_key(std::optional const& key); +}; + +} // namespace aztec3::circuits::apps::state_vars + +// Importing in this way (rather than explicit instantiation of a template class at the bottom of a .cpp file) preserves +// the following: +// - We retain implicit instantiation of templates, meaning we can pick and choose (with static_assert) which class +// methods support native, +// circuit or both types. +// - We don't implement method definitions in this file, to avoid a circular dependency with +// function_execution_context.hpp. +#include "mapping_state_var.tpp" diff --git a/circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.tpp b/circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.tpp new file mode 100644 index 00000000000..684d51a102c --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.tpp @@ -0,0 +1,142 @@ +#pragma once +// #include +// #include "oracle_wrapper.hpp" +// #include "private_state_note.hpp" +// #include "private_state_note_preimage.hpp" +// #include "private_state_operand.hpp" +#include "plonk/composer/turbo_composer.hpp" + +#include +#include +#include +#include +#include +#include +#include + +namespace aztec3::circuits::apps::state_vars { + +using crypto::pedersen::generator_index_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; + +// Fr: start_slot +// +// mapping(fr => V): +// level of nesting = 1 +// start_slot_point = start_slot * A +// at(k1).slot = start_slot_point + k1 * B +// +// mapping(fr => mapping(fr => T)): +// level_of_nesting = 2 +// start_slot_point becomes: prev_start_slot_point + k1 * B +// at(k2).slot = new_start_slot_point + k2 * C + +template +std::tuple MappingStateVar::compute_slot_point_at_mapping_key( + NT::fr const& start_slot, size_t level_of_container_nesting, std::optional const& key) +{ + bool is_partial_slot = false; // ????? + + std::vector> input_pairs; + + // TODO: compare (in a test) this little calc against calling `compute_start_slot_point`. + input_pairs.push_back(std::make_pair( + start_slot, + generator_index_t({ StorageSlotGeneratorIndex::MAPPING_SLOT, 0 }))); // hash_sub_index 0 is reserved for the + + if (key) { + input_pairs.push_back(std::make_pair( + *key, generator_index_t({ StorageSlotGeneratorIndex::MAPPING_SLOT, level_of_container_nesting }))); + } else { + // If this mapping key has no mapping_key_value (std::nullopt), then we must be partially committing and + // omitting this mapping key from that partial commitment. + // So use a placeholder generator for this mapping key, to signify "this mapping key is missing". + // Note: we can't just commit to a value of `0` for this mapping key, since `0` is a valid value to + // commit to, and so "missing" is distinguished as follows. + input_pairs.push_back(std::make_pair( + NativeTypes::fr(1), + generator_index_t({ StorageSlotGeneratorIndex::MAPPING_SLOT_PLACEHOLDER, level_of_container_nesting }))); + } + + return std::make_tuple(NativeTypes::commit(input_pairs), is_partial_slot); +} + +template +std::tuple::grumpkin_point, bool> MappingStateVar:: + compute_slot_point_at_mapping_key(std::optional const& key) +{ + bool is_partial_slot = false; // ?????? + + std::vector> input_pairs; + + input_pairs.push_back(std::make_pair(this->start_slot, + generator_index_t({ StorageSlotGeneratorIndex::MAPPING_SLOT, + 0 }))); // hash_sub_index 0 is reserved for the start_slot. + + if (key) { + input_pairs.push_back(std::make_pair( + *key, + generator_index_t( + { StorageSlotGeneratorIndex::MAPPING_SLOT, + this->level_of_container_nesting }))); // hash_sub_index 0 is reserved for the start_slot. + } else { + // If this mapping key has no mapping_key_value (std::nullopt), then we must be partially committing and + // omitting this mapping key from that partial commitment. + // So use a placeholder generator for this mapping key, to signify "this mapping key is missing". + // Note: we can't just commit to a value of `0` for this mapping key, since `0` is a valid value to + // commit to, and so "missing" is distinguished as follows. + input_pairs.push_back(std::make_pair(fr(1), + generator_index_t({ StorageSlotGeneratorIndex::MAPPING_SLOT_PLACEHOLDER, + this->level_of_container_nesting }))); + + is_partial_slot = true; + } + + return std::make_tuple(CT::commit(input_pairs), is_partial_slot); +} + +template V& MappingStateVar::at(std::optional const& key) +{ + // First calculate natively and check to see if we've already calculated this state's slot and stored it in the + // cache, so we don't create unnecessary circuit gates: + + std::optional native_key; + if (!key) { + native_key = std::nullopt; + } else { + native_key = NativeTypes::fr((*key).get_value()); + } + + bool is_partial_slot; + NativeTypes::grumpkin_point native_new_slot_point; + std::tie(native_new_slot_point, is_partial_slot) = MappingStateVar::compute_slot_point_at_mapping_key( + this->start_slot.get_value(), this->level_of_container_nesting, native_key); + NativeTypes::fr native_lookup = native_new_slot_point.x; + + // Check cache + if (this->value_cache.contains(native_lookup)) { + return this->value_cache[native_lookup]; + } + + // Create gates: + grumpkin_point new_slot_point; + std::tie(new_slot_point, is_partial_slot) = compute_slot_point_at_mapping_key(key); + NativeTypes::fr lookup = new_slot_point.x.get_value(); + + if (lookup != native_lookup) { + throw_or_abort("Expected lookup calcs to be equal!"); + } + + std::string value_name = this->state_var_name + (key ? format("[", *key, "]").c_str() : "[?]"); + + V value = V(this->exec_ctx, value_name, new_slot_point, this->level_of_container_nesting + 1, is_partial_slot); + + this->value_cache[lookup] = value; + + return this->value_cache[lookup]; +} + +// template class PrivateStateVar; + +}; // namespace aztec3::circuits::apps::state_vars diff --git a/circuits/src/aztec3/circuits/apps/state_vars/state_var_base.hpp b/circuits/src/aztec3/circuits/apps/state_vars/state_var_base.hpp new file mode 100644 index 00000000000..f92c75a405a --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/state_vars/state_var_base.hpp @@ -0,0 +1,95 @@ +#pragma once + +#include "../function_execution_context.hpp" + +#include +#include + +namespace aztec3::circuits::apps::state_vars { + +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; + +template class StateVar { + public: + typedef CircuitTypes CT; + typedef NativeTypes NT; + typedef typename CT::fr fr; + typedef typename CT::grumpkin_point grumpkin_point; + + FunctionExecutionContext* exec_ctx; + + std::string state_var_name; + + fr start_slot; + grumpkin_point storage_slot_point; + // In order to calculate the correct storage_slot_point, we need to know how many containers we're nested inside, so + // that we can find the correct Pedersen generator. + size_t level_of_container_nesting = 0; + bool is_partial_slot = false; + + // native_storage_slot.x => value cache, to prevent creating constraints with each call. + // V value; + + // StateVar(){}; + + StateVar operator=(StateVar const& other) + { + this->exec_ctx = other.exec_ctx; + this->state_var_name = other.state_var_name; + this->start_slot = other.start_slot; + this->storage_slot_point = other.storage_slot_point; + this->level_of_container_nesting = other.level_of_container_nesting; + this->is_partial_slot = other.is_partial_slot; + return *this; + } + + // StateVar(StateVar const& other) + // { + // this->exec_ctx = other.exec_ctx; + // this->state_var_name = other.state_var_name; + // this->start_slot = other.start_slot; + // this->storage_slot_point = other.storage_slot_point; + // this->level_of_container_nesting = other.level_of_container_nesting; + // this->is_partial_slot = other.is_partial_slot; + // // return *this; + // } + + StateVar(){}; + + // Instantiate a top-level state: + StateVar(FunctionExecutionContext* exec_ctx, std::string const& state_var_name, fr const& start_slot) + : exec_ctx(exec_ctx) + , state_var_name(state_var_name) + , start_slot(start_slot) + { + storage_slot_point = compute_slot_point(); + }; + + // Instantiate a nested state: + StateVar( + FunctionExecutionContext* exec_ctx, + std::string const& state_var_name, + grumpkin_point const& storage_slot_point, // the parent always calculates the storage_slot_point of its child. + size_t level_of_container_nesting, // the parent always calculates the level of nesting of its child. + bool is_partial_slot = false) + : exec_ctx(exec_ctx) + , state_var_name(state_var_name) + , storage_slot_point(storage_slot_point) + , level_of_container_nesting(level_of_container_nesting) + , is_partial_slot(is_partial_slot){}; + + bool operator==(StateVar const&) const = default; + + private: + grumpkin_point compute_slot_point(); +}; + +} // namespace aztec3::circuits::apps::state_vars + +// Importing in this way (rather than explicit instantiation of a template class at the bottom of a .cpp file) preserves +// the following: +// - We retain implicit instantiation of templates, meaning we can pick and choose (with static_assert) which class +// methods support native, +// circuit or both types. +#include "state_var_base.tpp" diff --git a/circuits/src/aztec3/circuits/apps/state_vars/state_var_base.tpp b/circuits/src/aztec3/circuits/apps/state_vars/state_var_base.tpp new file mode 100644 index 00000000000..82e66fc9e66 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/state_vars/state_var_base.tpp @@ -0,0 +1,43 @@ +#pragma once +// #include +// #include "oracle_wrapper.hpp" +// #include "private_state_note.hpp" +// #include "private_state_note_preimage.hpp" +// #include "private_state_operand.hpp" +#include "plonk/composer/turbo_composer.hpp" + +#include +#include +#include +#include +#include +#include +#include + +namespace aztec3::circuits::apps::state_vars { + +using crypto::pedersen::generator_index_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; + +// Fr: start_slot +// +// mapping(fr => V): +// level of nesting = 1 +// start_slot_point = start_slot * A +// at(k1).slot = start_slot_point + k1 * B +// +// mapping(fr => mapping(fr => T)): +// level_of_nesting = 2 +// start_slot_point becomes: prev_start_slot_point + k1 * B +// at(k2).slot = new_start_slot_point + k2 * C + +template typename CircuitTypes::grumpkin_point StateVar::compute_slot_point() +{ + ASSERT(level_of_container_nesting == 0); + return CT::commit({ start_slot }, { StorageSlotGeneratorIndex::BASE_SLOT }); +} + +// template class PrivateStateVar; + +}; // namespace aztec3::circuits::apps::state_vars diff --git a/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp b/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp new file mode 100644 index 00000000000..e0585760f49 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp @@ -0,0 +1,52 @@ +#pragma once + +#include "state_var_base.hpp" + +#include "../function_execution_context.hpp" + +#include +#include + +namespace aztec3::circuits::apps::state_vars { + +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; + +template class UTXOStateVar : public StateVar { + public: + typedef CircuitTypes CT; + typedef NativeTypes NT; + typedef typename CT::fr fr; + typedef typename CT::grumpkin_point grumpkin_point; + + typedef typename Note::NotePreimage NotePreimage; + + UTXOStateVar(){}; + + UTXOStateVar(FunctionExecutionContext* exec_ctx, std::string const& state_var_name, fr const& start_slot) + : StateVar(exec_ctx, state_var_name, start_slot){}; + + // Instantiate a nested mapping: + UTXOStateVar(FunctionExecutionContext* exec_ctx, + std::string const& state_var_name, + grumpkin_point const& storage_slot_point, + size_t level_of_container_nesting, + bool is_partial_slot) + : StateVar( + exec_ctx, state_var_name, storage_slot_point, level_of_container_nesting, is_partial_slot){}; + + // bool operator==(UTXOStateVar const&) const = default; + + /** + * @param advice - For NotePreimages, we allow 'advice' to be given, so that the correct DB entry is + * chosen. + * E.g. so that the `owner` can be specified. + */ + Note get(NotePreimage const& advice); + + // void insert(NotePreimage const& new_value); +}; + +} // namespace aztec3::circuits::apps::state_vars + +#include "utxo_state_var.tpp" \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.tpp b/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.tpp new file mode 100644 index 00000000000..19a5908bca7 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.tpp @@ -0,0 +1,25 @@ +#pragma once + +#include "../opcodes/opcodes.hpp" + +#include +#include + +namespace aztec3::circuits::apps::state_vars { + +using aztec3::circuits::apps::opcodes::Opcodes; + +template +Note UTXOStateVar::get(typename Note::NotePreimage const& advice) +{ + return Opcodes::template UTXO_SLOAD(this, advice); +}; + +// void insert(NotePreimage new_value); + +// template inline std::ostream& operator<<(std::ostream& os, UTXOStateVar const& v) +// { +// return os << v.value; +// } + +} // namespace aztec3::circuits::apps::state_vars diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp index b81684f785a..e9d76483603 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp @@ -1,9 +1,9 @@ #pragma once + #include "init.hpp" #include #include -#include namespace aztec3::circuits::apps::test_apps::escrow { @@ -11,16 +11,14 @@ inline Contract init_contract(FunctionExecutionContext& exec { Contract contract(exec_ctx, "Escrow"); - contract.new_private_state("balances", { "owner", "asset_id" }); + // mapping(owner => mapping(asset_id => balance)) balances; + contract.declare_private_state_var("balances", { "owner", "asset_id" }); // Solely used for assigning vk indices. contract.set_functions({ { .name = "deposit", .is_private = true }, { .name = "transfer", .is_private = true }, { .name = "withdraw", .is_private = true }, - // success case not needed in this app, but it's helping me figure out success cases: - { .name = "withdraw_success_callback", .is_private = true }, - { .name = "withdraw_failure_callback", .is_private = true }, }); // TODO: this L1 declaration interface is just to get something working. diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp index b0f0034532b..c76ede9d290 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp @@ -24,21 +24,21 @@ OptionalPrivateCircuitPublicInputs deposit(FunctionExecutionContext deposit(FunctionExecutionContext UTXOSet) balances; +// mapping(address = > mapping(address = > UTXO)) allowed; + +// deposit(uint amount) +// { +// balances[msg.sender].insert(amount, { owner : msg.sender }); // specify commitment owner? +// } + +// transfer(uint amount, address to) +// { +// UTXO[2] notes = balances[msg.sender].get(2, sort, filter, { owner : msg.sender }); + +// uint input_amount = notes[0].value + notes[1].value; +// require(input_amount >= amount); + +// notes[0].remove(); +// notes[1].remove(); + +// balances[msg.sender].insert(input_amount - amount, { owner : msg.sender }); + +// balances[to].insert(amount, { owner : to }); +// } + +// approve(address spender, uint amount) +// { +// UTXO note = allowed[msg.sender][spender].get(1, { owner : msg.sender }); +// allowed[msg.sender][spender].replace(increase_amount, { owner : spender }); +// } + +// function transferFrom(address sender, address recipient, uint256 amount) +// { + +// require(balances[sender] >= amount, "Insufficient balance."); +// require(allowed[sender][msg.sender] >= amount, "Insufficient allowance."); + +// balances[sender] = balances[sender].sub(amount); +// allowed[sender][msg.sender] = allowed[sender][msg.sender].sub(amount); +// balances[recipient] = balances[recipient].add(amount); +// emit Transfer(sender, recipient, amount); +// return true; +// } + +// Initialising singleton UTXOs: +// - We want to ensure we never create more than 1 UTXO in the tree for such a variable. +// - So we can't use "optional" to get a dummy UTXO (because then a user could call the functoin multiple times, eeach +// time _get_ a dummy UTXO, and then create loads of competing notes for the same variable). \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/init.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/init.hpp index 082e19395ec..4087a5782e9 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/init.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/init.hpp @@ -1,7 +1,6 @@ #pragma once #include -#include #include #include @@ -12,6 +11,7 @@ namespace aztec3::circuits::apps::test_apps::escrow { using Composer = plonk::stdlib::types::turbo::Composer; + using CT = plonk::stdlib::types::CircuitTypes; using NT = plonk::stdlib::types::NativeTypes; diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp index 0082220edb8..15f481a16f0 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp @@ -3,9 +3,7 @@ #include "contract.hpp" #include -#include #include -// #include namespace aztec3::circuits::apps::test_apps::escrow { @@ -38,7 +36,7 @@ OptionalPrivateCircuitPublicInputs transfer(FunctionExecutionContext transfer(FunctionExecutionContext transfer(FunctionExecutionContext transfer(FunctionExecutionContext withdraw(FunctionExecutionContext withdraw(FunctionExecutionContext #include -#include "init.hpp" namespace aztec3::circuits::apps::test_apps::escrow { diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/contract.hpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/contract.hpp index f99a8589dd9..df0b6ce0921 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/contract.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/contract.hpp @@ -10,8 +10,8 @@ inline Contract init_contract(FunctionExecutionContext& exec { Contract contract(exec_ctx, "priv_to_priv_function_call"); - contract.new_private_state("x"); - contract.new_private_state("y"); + contract.declare_private_state_var("x"); + contract.declare_private_state_var("y"); // Solely used for assigning vk indices. contract.set_functions({ diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.cpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.cpp index cca31a42a24..d1988b3b010 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.cpp @@ -22,11 +22,11 @@ OptionalPrivateCircuitPublicInputs function1(FunctionExecutionContext function1(FunctionExecutionContext +#include +#include + +namespace aztec3::circuits::apps { + +using plonk::stdlib::witness_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; + +/** + * @tparam NCT - NativeTypes or CircuitTypes + * @tparam NotePreimage + */ +template struct UTXOSLoadDatum { + typedef typename NCT::fr fr; + typedef typename NCT::address address; + typedef typename NCT::uint32 uint32; + + fr commitment; + address contract_address; + NotePreimage preimage; + + std::vector sibling_path; + uint32 leaf_index; + fr old_private_data_tree_root; + + template auto to_circuit_type(Composer& composer) const + { + // typedef CircuitTypes CT; + // typedef NativeTypes NT; + + static_assert(std::is_same::value); + + // Capture the composer: + auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + + auto preimage_ct = preimage.to_circuit_type(composer); + + UTXOSLoadDatum, decltype(preimage_ct)> datum = { + to_ct(commitment), to_ct(contract_address), preimage_ct, + to_ct(sibling_path), to_ct(leaf_index), to_ct(old_private_data_tree_root), + }; + + return datum; + }; + + // template using NotePreimageCT = NotePreimage>; + + // template + // UTXOSLoadDatum, NotePreimageCT> to_circuit_type(Composer& composer) const + // { + // typedef CircuitTypes CT; + // typedef NativeTypes NT; + + // static_assert((std::is_same::value)); + + // // Capture the composer: + // auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + + // NotePreimageCT preimage_ct = preimage.to_circuit_type(composer); + + // UTXOSLoadDatum, NotePreimageCT> datum = { + // preimage_ct, to_ct(commitment), to_ct(sibling_path), to_ct(leaf_index), + // to_ct(old_private_data_tree_root), + // }; + + // return datum; + // }; +}; + +} // namespace aztec3::circuits::apps diff --git a/circuits/src/aztec3/circuits/kernel/private/.test.cpp b/circuits/src/aztec3/circuits/kernel/private/.test.cpp index a2b822d8552..c4af8b8da35 100644 --- a/circuits/src/aztec3/circuits/kernel/private/.test.cpp +++ b/circuits/src/aztec3/circuits/kernel/private/.test.cpp @@ -117,7 +117,7 @@ TEST(private_kernel_tests, test_deposit) .is_private = true, .is_constructor = false, }, - .custom_inputs = deposit_public_inputs.custom_inputs, + .args = deposit_public_inputs.args, .nonce = 0, .tx_context = TxContext{ diff --git a/circuits/src/aztec3/constants.hpp b/circuits/src/aztec3/constants.hpp index 601fbb9284a..128acf1ce85 100644 --- a/circuits/src/aztec3/constants.hpp +++ b/circuits/src/aztec3/constants.hpp @@ -3,8 +3,8 @@ namespace aztec3 { -constexpr size_t CUSTOM_INPUTS_LENGTH = 8; -constexpr size_t CUSTOM_OUTPUTS_LENGTH = 4; +constexpr size_t ARGS_LENGTH = 8; +constexpr size_t RETURN_VALUES_LENGTH = 4; constexpr size_t EMITTED_EVENTS_LENGTH = 4; constexpr size_t OUTPUT_COMMITMENTS_LENGTH = 4; @@ -34,7 +34,7 @@ constexpr size_t NULLIFIER_TREE_HEIGHT = 8; // Enumerate the hash_indices which are used for pedersen hashing // Start from 1 to avoid the default generators. enum GeneratorIndex { - COMMITMENT, + COMMITMENT = 1, COMMITMENT_PLACEHOLDER, // for omitting some elements of the commitment when partially committing. OUTER_COMMITMENT, NULLIFIER_HASHED_PRIVATE_KEY, @@ -53,16 +53,20 @@ enum GeneratorIndex { PUBLIC_CIRCUIT_PUBLIC_INPUTS, }; +enum StorageSlotGeneratorIndex { + BASE_SLOT, + MAPPING_SLOT, + MAPPING_SLOT_PLACEHOLDER, +}; + // Enumerate the hash_sub_indices which are used for committing to private state note preimages. // Start from 1. enum PrivateStateNoteGeneratorIndex { - MAPPING_SLOT = 1, - MAPPING_SLOT_PLACEHOLDER, // for omitting some mapping key values when partially committing. - VALUE, + VALUE = 1, OWNER, CREATOR, SALT, - INPUT_NULLIFIER, + NONCE, MEMO, IS_REAL, }; diff --git a/circuits/src/aztec3/oracle/README.md b/circuits/src/aztec3/oracle/README.md index 39fa4e6cbf6..43cc17cfa67 100644 --- a/circuits/src/aztec3/oracle/README.md +++ b/circuits/src/aztec3/oracle/README.md @@ -1,6 +1,6 @@ # aztec3::circuits::oracle -When Aztec3 makes a call to a circuit executor (such as Noir or the test apps in aztec3/circuits/apps/test_apps), we don't pass _all_ public inputs when calling the circuit; only the `custom_inputs` inputs are sent initially. +When Aztec3 makes a call to a circuit executor (such as Noir or the test apps in aztec3/circuits/apps/test_apps), we don't pass _all_ public inputs when calling the circuit; only the `args` inputs are sent initially. Why? diff --git a/circuits/src/aztec3/oracle/oracle.hpp b/circuits/src/aztec3/oracle/oracle.hpp index 1986a402f64..28081198799 100644 --- a/circuits/src/aztec3/oracle/oracle.hpp +++ b/circuits/src/aztec3/oracle/oracle.hpp @@ -1,14 +1,25 @@ #pragma once + #include + #include +#include + +#include + #include namespace aztec3::oracle { -using NT = plonk::stdlib::types::NativeTypes; using aztec3::circuits::abis::CallContext; + using aztec3::circuits::apps::PrivateStateNotePreimage; +using aztec3::circuits::apps::UTXOSLoadDatum; + +using aztec3::circuits::apps::notes::DefaultPrivateNotePreimage; + using plonk::stdlib::types::CircuitTypes; +using NT = plonk::stdlib::types::NativeTypes; /// Note: the server will always serve NATIVE types to the circuit, since eventually we'll be passing data to Noir (so /// won't be handling circuit types at all from the Aztec3 end). @@ -71,7 +82,7 @@ template class NativeOracleInterface { throw_or_abort("no private key stored in memory"); } if (msg_sender_private_key_already_got) { - throw_or_abort(already_got_error); + throw_or_abort("msg_sender_private_key: " + already_got_error); } msg_sender_private_key_already_got = true; return *msg_sender_private_key; @@ -89,12 +100,21 @@ template class NativeOracleInterface { CallContext get_call_context() { if (call_context_already_got) { - throw_or_abort(already_got_error); + throw_or_abort("call_context: " + already_got_error); } call_context_already_got = true; return call_context; }; + template + UTXOSLoadDatum get_utxo_sload_datum(NT::grumpkin_point const storage_slot_point, + NotePreimage const advice) + { + // TODO: consider whether it's actually safe to bypass get_call_context() here... + const auto& contract_address = call_context.storage_contract_address; + return db.get_utxo_sload_datum(contract_address, storage_slot_point, advice); + } + std::pair, PrivateStateNotePreimage> get_private_state_note_preimages_for_subtraction(NT::fr const& storage_slot, NT::address const& owner, @@ -132,46 +152,84 @@ class FakeDB { public: FakeDB(){}; + /** + * For getting a singleton UTXO (not a set). + */ + UTXOSLoadDatum> get_utxo_sload_datum( + NT::address const& contract_address, + NT::grumpkin_point const& storage_slot_point, + DefaultPrivateNotePreimage const& advice) + // NT::address const& owner, + // NT::fr required_utxo_tree_root, + // size_t utxo_tree_depth) + { + (void)storage_slot_point; // Not used in this 'fake' implementation. + + DefaultPrivateNotePreimage preimage{ + .value = 100, + .owner = advice.owner, + .creator_address = 0, + .memo = 3456, + .salt = 1234, + .nonce = 2345, + .is_real = true, + }; + + const size_t utxo_tree_depth = 32; + const NT::fr required_utxo_tree_root = 2468; + + std::vector sibling_path(utxo_tree_depth); + std::fill(sibling_path.begin(), sibling_path.end(), 1); // Fill with 1's to be lazy. TODO: return a valid path. + + return { + .commitment = 1, // TODO: implement commit() method in `preimage`? + .contract_address = contract_address, + .preimage = preimage, + + .sibling_path = sibling_path, + .leaf_index = 2, + .old_private_data_tree_root = required_utxo_tree_root, + }; + }; + std::pair, PrivateStateNotePreimage> get_private_state_note_preimages_for_subtraction(NT::address const& contract_address, NT::fr const& storage_slot, NT::address const& owner, NT::fr const& subtrahend) { - if (contract_address.address_ != 0) { - // do nothing - just making these variables in-use - } + (void)contract_address; // currently unused - NT::grumpkin_point slot_point; + NT::grumpkin_point storage_slot_point; NT::fr x = storage_slot; NT::fr yy = x.sqr() * x + NT::grumpkin_group::curve_b; NT::fr y = yy.sqrt(); NT::fr neg_y = -y; y = y < neg_y ? y : neg_y; - slot_point = NT::grumpkin_group::affine_element(x, y); - info("derived slot point:", slot_point); + storage_slot_point = NT::grumpkin_group::affine_element(x, y); + info("derived slot point:", storage_slot_point); return std::make_pair( PrivateStateNotePreimage{ .start_slot = 0, - .slot_point = slot_point, + .storage_slot_point = storage_slot_point, .value = uint256_t(subtrahend) / 2 + 1, - .owner_address = owner, + .owner = owner, .creator_address = 0, - .salt = 1234, - .input_nullifier = 2345, .memo = 3456, + .salt = 1234, + .nonce = 2345, .is_real = true, }, PrivateStateNotePreimage{ .start_slot = 0, - .slot_point = slot_point, + .storage_slot_point = storage_slot_point, .value = uint256_t(subtrahend) / 2 + 3, - .owner_address = owner, + .owner = owner, .creator_address = 0, - .salt = 4567, - .input_nullifier = 5678, .memo = 6789, + .salt = 4567, + .nonce = 5678, .is_real = true, }); }; From a10214989a8d3afb681938df8b5143f9b1836d76 Mon Sep 17 00:00:00 2001 From: iAmMichaelConnor Date: Sun, 1 Jan 2023 18:48:08 +0000 Subject: [PATCH 018/166] wip: contract syntax --- .../src/aztec3/circuits/apps/contract.hpp | 55 +- .../src/aztec3/circuits/apps/contract.tpp | 43 -- .../apps/function_execution_context.hpp | 3 + .../apps/notes/default_private_note/note.hpp | 11 - .../apps/notes/default_private_note/note.tpp | 27 +- .../aztec3/circuits/apps/state_vars/.test.cpp | 70 ++- .../apps/state_vars/mapping_state_var.hpp | 6 +- .../apps/state_vars/state_var_base.hpp | 5 +- .../apps/state_vars/utxo_state_var.hpp | 4 +- .../circuits/apps/test_apps/escrow/.test.cpp | 263 ++++---- .../apps/test_apps/escrow/contract.hpp | 52 +- .../apps/test_apps/escrow/deposit.cpp | 191 +++--- .../apps/test_apps/escrow/deposit.hpp | 22 +- .../circuits/apps/test_apps/escrow/index.hpp | 10 +- .../circuits/apps/test_apps/escrow/init.hpp | 32 +- .../apps/test_apps/escrow/transfer.cpp | 126 ++-- .../apps/test_apps/escrow/transfer.hpp | 28 +- .../apps/test_apps/escrow/withdraw.cpp | 108 ++-- .../apps/test_apps/escrow/withdraw.hpp | 26 +- .../.test.cpp | 63 +- .../contract.hpp | 38 +- .../function1.cpp | 106 ++-- .../function1.hpp | 22 +- .../index.hpp | 8 +- .../private_to_private_function_call/init.hpp | 32 +- .../aztec3/circuits/kernel/private/.test.cpp | 497 +++++++-------- .../aztec3/circuits/kernel/private/index.hpp | 4 +- .../aztec3/circuits/kernel/private/init.hpp | 48 +- .../kernel/private/private_kernel_circuit.cpp | 575 +++++++++--------- .../kernel/private/private_kernel_circuit.hpp | 20 +- 30 files changed, 1242 insertions(+), 1253 deletions(-) diff --git a/circuits/src/aztec3/circuits/apps/contract.hpp b/circuits/src/aztec3/circuits/apps/contract.hpp index 9d4235f4f5c..1e52afedf79 100644 --- a/circuits/src/aztec3/circuits/apps/contract.hpp +++ b/circuits/src/aztec3/circuits/apps/contract.hpp @@ -6,12 +6,15 @@ #include +#include + namespace aztec3::circuits::apps { +using aztec3::circuits::abis::FunctionSignature; + using plonk::stdlib::witness_t; using plonk::stdlib::types::CircuitTypes; using NT = plonk::stdlib::types::NativeTypes; -using aztec3::circuits::abis::FunctionSignature; template class FunctionExecutionContext; @@ -25,11 +28,9 @@ template class Contract { const std::string contract_name; - fr state_counter = 0; - - std::vector state_names; - - std::map> private_state_vars; + fr state_var_counter = 0; + std::vector state_var_names; + std::map start_slots_by_state_var_name; std::map> function_signatures; @@ -53,17 +54,39 @@ template class Contract { L1FunctionInterface& get_l1_function(std::string const& name); - void push_new_state_var_name(std::string const& name); - - PrivateStateVar& declare_private_state_var(std::string const& name, - PrivateStateType const& private_state_type = PARTITIONED); - - // For initialising a private state which is a mapping. - PrivateStateVar& declare_private_state_var(std::string const& name, - std::vector const& mapping_key_names, - PrivateStateType const& private_state_type = PARTITIONED); + // TODO: maybe also declare a type at this stage, so the correct type can be checked-for when the StateVar type is + // created within the function. + /** + * Note: this simply tracks the 'start' storage slots of each state variable at the 'contract scope level'. + * TODO: maybe we can just keep a vector of names and query the start slot with index_of(), instead. + */ + void declare_state_var(std::string const& state_var_name) + { + push_new_state_var_name(state_var_name); + start_slots_by_state_var_name[state_var_name] = state_var_counter; + // state_var_counter++; + state_var_counter++; + ASSERT(state_var_counter.get_value() == state_var_names.size()); + }; + + fr& get_start_slot(std::string const& state_var_name) + { + if (!start_slots_by_state_var_name.contains(state_var_name)) { + throw_or_abort("Name '" + state_var_name + "' not found. Use `declare_private_state_var`."); + } + return start_slots_by_state_var_name.at(state_var_name); + }; + + private: + void push_new_state_var_name(std::string const& state_var_name) + { + if (index_of(state_var_names, state_var_name) == -1) { + state_var_names.push_back(state_var_name); - PrivateStateVar& get_private_state_var(std::string const& name); + return; + } + throw_or_abort("name already exists"); + } }; } // namespace aztec3::circuits::apps diff --git a/circuits/src/aztec3/circuits/apps/contract.tpp b/circuits/src/aztec3/circuits/apps/contract.tpp index 7217c91abca..f11e86a027b 100644 --- a/circuits/src/aztec3/circuits/apps/contract.tpp +++ b/circuits/src/aztec3/circuits/apps/contract.tpp @@ -60,47 +60,4 @@ template L1FunctionInterface& Contract:: return l1_functions[name]; } -template void Contract::push_new_state_var_name(std::string const& name) -{ - if (index_of(state_names, name) == -1) { - state_names.push_back(name); - return; - } - throw_or_abort("name already exists"); -} - -template -PrivateStateVar& Contract::declare_private_state_var(std::string const& name, - PrivateStateType const& private_state_type) -{ - push_new_state_var_name(name); - PrivateStateVar private_state_var = - PrivateStateVar(&exec_ctx, private_state_type, name, state_counter++); - private_state_vars.insert(std::make_pair(name, private_state_var)); - return private_state_vars[name]; -}; - -// For initialising a private state which is a mapping. -template -PrivateStateVar& Contract::declare_private_state_var( - std::string const& name, - std::vector const& mapping_key_names, - PrivateStateType const& private_state_type) -{ - push_new_state_var_name(name); - PrivateStateVar private_state_var = - PrivateStateVar(&exec_ctx, private_state_type, name, state_counter++, mapping_key_names); - private_state_vars.insert(std::make_pair(name, private_state_var)); - return private_state_vars[name]; -}; - -template -PrivateStateVar& Contract::get_private_state_var(std::string const& name) -{ - if (!private_state_vars.contains(name)) { - throw_or_abort("name not found"); - } - return private_state_vars[name]; -}; - } // namespace aztec3::circuits::apps \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/function_execution_context.hpp b/circuits/src/aztec3/circuits/apps/function_execution_context.hpp index f707348606e..b894b7d9211 100644 --- a/circuits/src/aztec3/circuits/apps/function_execution_context.hpp +++ b/circuits/src/aztec3/circuits/apps/function_execution_context.hpp @@ -12,6 +12,8 @@ #include +// #include + // #include "private_state_var.hpp" // #include "function_declaration.hpp" // #include "l1_function_interface.hpp" @@ -33,6 +35,7 @@ template class FunctionExecutionContext { OracleWrapperInterface& oracle; Contract* contract = nullptr; + // std::shared_ptr> contract = nullptr; OptionalPrivateCircuitPublicInputs private_circuit_public_inputs; // UnpackedData unpacked_data; diff --git a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.hpp b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.hpp index f07d9219df5..b72851b6042 100644 --- a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.hpp +++ b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.hpp @@ -32,17 +32,6 @@ class DefaultPrivateNote : public NoteInterface > > *' to 'UTXOStateVar >::Note> *'( - // aka 'UTXOStateVar > > *') - - // using Note = aztec3::circuits::apps::notes::DefaultPrivateNote; - using NotePreimage = DefaultPrivateNotePreimage, ValueType>; using NullifierPreimage = DefaultPrivateNoteNullifierPreimage>; diff --git a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.tpp b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.tpp index e9ba26c6f12..600ce22b150 100644 --- a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.tpp +++ b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.tpp @@ -24,27 +24,12 @@ using plonk::stdlib::types::CircuitTypes; using plonk::stdlib::types::NativeTypes; } // namespace -// template -// DefaultPrivateNote::DefaultPrivateNote(PrivateStateVar& private_state_var, -// DefaultPrivateNotePreimage preimage, -// bool commit_on_init) -// : private_state_var(private_state_var) -// , preimage(preimage) -// , is_partial(check_if_partial()) -// { -// if (commit_on_init) { -// if (is_partial) { -// partial_commitment = compute_partial_commitment(); -// } else { -// commitment = compute_commitment(); -// } -// } -// } - template void DefaultPrivateNote::remove() { auto [nullifier, nullifier_preimage] = compute_nullifier(); + // auto& exec_ctx = utxo_state_var->exec_ctx; + // TODO: implement this function! (void)nullifier; (void)nullifier_preimage; @@ -63,14 +48,6 @@ template bool DefaultPrivateNote::c return false; } -// eclaration is incompatible with "std::pair< -// aztec3::circuits::apps::notes::DefaultPrivateNote::fr, -// aztec3::circuits::apps::notes::DefaultPrivateNote::NotePreimage > -// aztec3::circuits::apps::notes::DefaultPrivateNote::compute_commitment() " - -// template -// std::pair::fr, -// typename DefaultPrivateNote::NotePreimage> template std::pair::fr, DefaultPrivateNotePreimage, V>> DefaultPrivateNote::compute_commitment() diff --git a/circuits/src/aztec3/circuits/apps/state_vars/.test.cpp b/circuits/src/aztec3/circuits/apps/state_vars/.test.cpp index c607061fcca..4eaa037dcc0 100644 --- a/circuits/src/aztec3/circuits/apps/state_vars/.test.cpp +++ b/circuits/src/aztec3/circuits/apps/state_vars/.test.cpp @@ -12,6 +12,7 @@ #include "../notes/default_private_note/note.hpp" #include "../notes/default_private_note/note_preimage.hpp" +#include "../contract.hpp" #include "../function_execution_context.hpp" #include "../oracle_wrapper.hpp" #include "../utxo_datum.hpp" @@ -24,15 +25,23 @@ #include namespace { +// Composer using C = plonk::stdlib::types::turbo::Composer; + +// Types using CT = plonk::stdlib::types::CircuitTypes; using NT = plonk::stdlib::types::NativeTypes; using plonk::stdlib::types::to_ct; +// Oracle using DB = aztec3::oracle::FakeDB; using aztec3::oracle::NativeOracle; using OracleWrapper = aztec3::circuits::apps::OracleWrapperInterface; +// Contract +using Contract = aztec3::circuits::apps::Contract; + +// StateVars using aztec3::circuits::apps::state_vars::FieldStateVar; using aztec3::circuits::apps::state_vars::MappingStateVar; using aztec3::circuits::apps::state_vars::UTXOStateVar; @@ -60,18 +69,17 @@ using Field = FieldStateVar; namespace aztec3::circuits::apps::state_vars { class state_var_tests : public ::testing::Test { - private: - DB db; - // No cheating: you have to grab this stuff from the oracle in your tests - hence the 'private' scope. - NT::fr msg_sender_private_key = 123456789; - NT::address contract_address = 12345; - NT::address msg_sender = - NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); - NT::address tx_origin = msg_sender; - protected: NativeOracle get_test_native_oracle() { + DB db; + // No cheating: you have to grab this stuff from the oracle in your tests - hence the 'private' scope. + NT::fr msg_sender_private_key = 123456789; + NT::address contract_address = 12345; + NT::address msg_sender = NT::fr( + uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); + NT::address tx_origin = msg_sender; + return NativeOracle(db, contract_address, msg_sender, tx_origin, msg_sender_private_key); }; }; @@ -83,9 +91,16 @@ TEST_F(state_var_tests, mapping) OracleWrapper oracle = OracleWrapper(composer, native_oracle); FunctionExecutionContext exec_ctx(composer, oracle); - CT::fr start_slot = 1; + // TODO: + // Interestingly, if I scope the below, the debugger works, but running the test via the command line fails. I + // reckon the contract (and crucially, all pointers to the contract which are stored in other classes) is being + // deleted... so the declaration of this contract and any pointers probably all need to be shared_ptr. + // { + Contract contract(exec_ctx, "TestContract"); + contract.declare_state_var("my_mapping"); + // } - Mapping my_mapping(&exec_ctx, "balances", start_slot); + Mapping my_mapping(&exec_ctx, "my_mapping"); my_mapping[5] = to_ct(composer, NT::fr(5)); @@ -101,9 +116,12 @@ TEST_F(state_var_tests, mapping_within_mapping) OracleWrapper oracle = OracleWrapper(composer, native_oracle); FunctionExecutionContext exec_ctx(composer, oracle); - CT::fr start_slot = 1; + // { + Contract contract(exec_ctx, "TestContract"); + contract.declare_state_var("my_mapping"); + // } - Mapping> my_mapping(&exec_ctx, "balances", start_slot); + Mapping> my_mapping(&exec_ctx, "my_mapping"); my_mapping[5][6] = 7; @@ -117,9 +135,12 @@ TEST_F(state_var_tests, partial_mapping) OracleWrapper oracle = OracleWrapper(composer, native_oracle); FunctionExecutionContext exec_ctx(composer, oracle); - CT::fr start_slot = 1; + // { + Contract contract(exec_ctx, "TestContract"); + contract.declare_state_var("my_mapping"); + // } - Mapping> my_mapping(&exec_ctx, "balances", start_slot); + Mapping> my_mapping(&exec_ctx, "my_mapping"); my_mapping["?"][6] = 7; @@ -140,11 +161,14 @@ TEST_F(state_var_tests, utxo_of_default_private_note_fr) // return (i < j); // }; - CT::fr start_slot = 1; + // { + Contract contract(exec_ctx, "TestContract"); + contract.declare_state_var("my_utxo"); + // } + + // FUNCTION: - UTXO my_utxo(&exec_ctx, - "balance", - start_slot); // TODO: handshake with exec_ctx to get the start slot, rather than passing one in. + UTXO my_utxo(&exec_ctx, "my_utxo"); const auto& msg_sender = oracle.get_msg_sender(); @@ -154,13 +178,13 @@ TEST_F(state_var_tests, utxo_of_default_private_note_fr) old_note.remove(); - CT::fr new_value = *(old_note.get_preimage().value) + 5; + CT::fr old_value = *(old_note.get_preimage().value); - info("new_value: ", new_value); + CT::fr new_value = old_value + 5; - // my_utxo.insert({ .value = new_value }); + info("new_value: ", new_value); - // storage_slot, { value, owner }, salt, nonce + // my_utxo.insert({ .value = new_value, .owner = msg_sender }); } } // namespace aztec3::circuits::apps::state_vars \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.hpp b/circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.hpp index 31c356e5cf3..f6b4e58742a 100644 --- a/circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.hpp +++ b/circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.hpp @@ -28,10 +28,8 @@ template class MappingStateVar : public StateVar MappingStateVar(){}; // Instantiate a top-level mapping: - MappingStateVar(FunctionExecutionContext* exec_ctx, - std::string const& state_var_name, - fr const& start_slot) - : StateVar(exec_ctx, state_var_name, start_slot){}; + MappingStateVar(FunctionExecutionContext* exec_ctx, std::string const& state_var_name) + : StateVar(exec_ctx, state_var_name){}; // Instantiate a nested mapping: MappingStateVar(FunctionExecutionContext* exec_ctx, diff --git a/circuits/src/aztec3/circuits/apps/state_vars/state_var_base.hpp b/circuits/src/aztec3/circuits/apps/state_vars/state_var_base.hpp index f92c75a405a..543a39da003 100644 --- a/circuits/src/aztec3/circuits/apps/state_vars/state_var_base.hpp +++ b/circuits/src/aztec3/circuits/apps/state_vars/state_var_base.hpp @@ -58,11 +58,12 @@ template class StateVar { StateVar(){}; // Instantiate a top-level state: - StateVar(FunctionExecutionContext* exec_ctx, std::string const& state_var_name, fr const& start_slot) + StateVar(FunctionExecutionContext* exec_ctx, std::string const& state_var_name) : exec_ctx(exec_ctx) , state_var_name(state_var_name) - , start_slot(start_slot) + { + start_slot = exec_ctx->contract->get_start_slot(state_var_name); storage_slot_point = compute_slot_point(); }; diff --git a/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp b/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp index e0585760f49..e184b189620 100644 --- a/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp +++ b/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp @@ -23,8 +23,8 @@ template class UTXOStateVar : public StateVar UTXOStateVar(){}; - UTXOStateVar(FunctionExecutionContext* exec_ctx, std::string const& state_var_name, fr const& start_slot) - : StateVar(exec_ctx, state_var_name, start_slot){}; + UTXOStateVar(FunctionExecutionContext* exec_ctx, std::string const& state_var_name) + : StateVar(exec_ctx, state_var_name){}; // Instantiate a nested mapping: UTXOStateVar(FunctionExecutionContext* exec_ctx, diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp index 1befc032c25..1da867d9257 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp @@ -1,130 +1,133 @@ -#include -#include -// #include -// #include -// #include -#include "index.hpp" -#include "contract.hpp" - -namespace aztec3::circuits::apps::test_apps::escrow { - -class escrow_tests : public ::testing::Test {}; - -TEST(escrow_tests, test_deposit) -{ - - Composer composer; - DB db; - - const NT::address contract_address = 12345; - const NT::fr msg_sender_private_key = 123456789; - const NT::address msg_sender = - NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); - const NT::address tx_origin = msg_sender; - - NativeOracle oracle = NativeOracle(db, contract_address, msg_sender, tx_origin, msg_sender_private_key); - OracleWrapper oracle_wrapper = OracleWrapper(composer, oracle); - - FunctionExecutionContext exec_ctx(composer, oracle_wrapper); - - auto amount = NT::fr(5); - auto asset_id = NT::fr(1); - auto memo = NT::fr(999); - - auto result = deposit(exec_ctx, amount, asset_id, memo); - info("result: ", result); - - info("computed witness: ", composer.computed_witness); - info("witness: ", composer.witness); - // info("constant variables: ", composer.constant_variables); - // info("variables: ", composer.variables); - info("failed?: ", composer.failed); - info("err: ", composer.err); - info("n: ", composer.n); -} - -TEST(escrow_tests, test_transfer) -{ - - Composer composer; - DB db; - - const NT::address contract_address = 12345; - const NT::fr msg_sender_private_key = 123456789; - const NT::address msg_sender = - NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); - const NT::address tx_origin = msg_sender; - - CallContext call_context = { - .msg_sender = msg_sender, - .storage_contract_address = contract_address, - .tx_origin = msg_sender, - .is_delegate_call = false, - .is_static_call = false, - }; - - NativeOracle oracle = NativeOracle(db, call_context, msg_sender_private_key); - OracleWrapper oracle_wrapper = OracleWrapper(composer, oracle); - - FunctionExecutionContext exec_ctx(composer, oracle_wrapper); - - auto amount = NT::fr(5); - auto to = NT::address(657756); - auto asset_id = NT::fr(1); - auto memo = NT::fr(999); - auto reveal_msg_sender_to_recipient = true; - auto fee = NT::fr(2); - - transfer(exec_ctx, amount, to, asset_id, memo, reveal_msg_sender_to_recipient, fee); - - info("computed witness: ", composer.computed_witness); - info("witness: ", composer.witness); - // info("constant variables: ", composer.constant_variables); - // info("variables: ", composer.variables); - info("failed?: ", composer.failed); - info("err: ", composer.err); - info("n: ", composer.n); -} - -TEST(escrow_tests, test_withdraw) -{ - - Composer composer; - DB db; - - const NT::address contract_address = 12345; - const NT::fr msg_sender_private_key = 123456789; - const NT::address msg_sender = - NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); - - CallContext call_context = { - .msg_sender = msg_sender, - .storage_contract_address = contract_address, - .tx_origin = msg_sender, - .is_delegate_call = false, - .is_static_call = false, - }; - - NativeOracle oracle = NativeOracle(db, call_context, msg_sender_private_key); - OracleWrapper oracle_wrapper = OracleWrapper(composer, oracle); - - FunctionExecutionContext exec_ctx(composer, oracle_wrapper); - - auto amount = NT::fr(5); - auto asset_id = NT::fr(1); - auto memo = NT::fr(999); - auto l1_withdrawal_address = NT::fr(657756); - auto fee = NT::fr(2); - - withdraw(exec_ctx, amount, asset_id, memo, l1_withdrawal_address, fee); - - info("computed witness: ", composer.computed_witness); - info("witness: ", composer.witness); - // info("constant variables: ", composer.constant_variables); - // info("variables: ", composer.variables); - info("failed?: ", composer.failed); - info("err: ", composer.err); - info("n: ", composer.n); -} - -} // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file +// #include +// #include +// // #include +// // #include +// // #include +// #include "index.hpp" +// #include "contract.hpp" + +// namespace aztec3::circuits::apps::test_apps::escrow { + +// class escrow_tests : public ::testing::Test {}; + +// TEST(escrow_tests, test_deposit) +// { + +// Composer composer; +// DB db; + +// const NT::address contract_address = 12345; +// const NT::fr msg_sender_private_key = 123456789; +// const NT::address msg_sender = +// NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, +// 0x2ef9f7f09867fd6eULL)); +// const NT::address tx_origin = msg_sender; + +// NativeOracle oracle = NativeOracle(db, contract_address, msg_sender, tx_origin, msg_sender_private_key); +// OracleWrapper oracle_wrapper = OracleWrapper(composer, oracle); + +// FunctionExecutionContext exec_ctx(composer, oracle_wrapper); + +// auto amount = NT::fr(5); +// auto asset_id = NT::fr(1); +// auto memo = NT::fr(999); + +// auto result = deposit(exec_ctx, amount, asset_id, memo); +// info("result: ", result); + +// info("computed witness: ", composer.computed_witness); +// info("witness: ", composer.witness); +// // info("constant variables: ", composer.constant_variables); +// // info("variables: ", composer.variables); +// info("failed?: ", composer.failed); +// info("err: ", composer.err); +// info("n: ", composer.n); +// } + +// TEST(escrow_tests, test_transfer) +// { + +// Composer composer; +// DB db; + +// const NT::address contract_address = 12345; +// const NT::fr msg_sender_private_key = 123456789; +// const NT::address msg_sender = +// NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, +// 0x2ef9f7f09867fd6eULL)); +// const NT::address tx_origin = msg_sender; + +// CallContext call_context = { +// .msg_sender = msg_sender, +// .storage_contract_address = contract_address, +// .tx_origin = msg_sender, +// .is_delegate_call = false, +// .is_static_call = false, +// }; + +// NativeOracle oracle = NativeOracle(db, call_context, msg_sender_private_key); +// OracleWrapper oracle_wrapper = OracleWrapper(composer, oracle); + +// FunctionExecutionContext exec_ctx(composer, oracle_wrapper); + +// auto amount = NT::fr(5); +// auto to = NT::address(657756); +// auto asset_id = NT::fr(1); +// auto memo = NT::fr(999); +// auto reveal_msg_sender_to_recipient = true; +// auto fee = NT::fr(2); + +// transfer(exec_ctx, amount, to, asset_id, memo, reveal_msg_sender_to_recipient, fee); + +// info("computed witness: ", composer.computed_witness); +// info("witness: ", composer.witness); +// // info("constant variables: ", composer.constant_variables); +// // info("variables: ", composer.variables); +// info("failed?: ", composer.failed); +// info("err: ", composer.err); +// info("n: ", composer.n); +// } + +// TEST(escrow_tests, test_withdraw) +// { + +// Composer composer; +// DB db; + +// const NT::address contract_address = 12345; +// const NT::fr msg_sender_private_key = 123456789; +// const NT::address msg_sender = +// NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, +// 0x2ef9f7f09867fd6eULL)); + +// CallContext call_context = { +// .msg_sender = msg_sender, +// .storage_contract_address = contract_address, +// .tx_origin = msg_sender, +// .is_delegate_call = false, +// .is_static_call = false, +// }; + +// NativeOracle oracle = NativeOracle(db, call_context, msg_sender_private_key); +// OracleWrapper oracle_wrapper = OracleWrapper(composer, oracle); + +// FunctionExecutionContext exec_ctx(composer, oracle_wrapper); + +// auto amount = NT::fr(5); +// auto asset_id = NT::fr(1); +// auto memo = NT::fr(999); +// auto l1_withdrawal_address = NT::fr(657756); +// auto fee = NT::fr(2); + +// withdraw(exec_ctx, amount, asset_id, memo, l1_withdrawal_address, fee); + +// info("computed witness: ", composer.computed_witness); +// info("witness: ", composer.witness); +// // info("constant variables: ", composer.constant_variables); +// // info("variables: ", composer.variables); +// info("failed?: ", composer.failed); +// info("err: ", composer.err); +// info("n: ", composer.n); +// } + +// } // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp index e9d76483603..5deda875252 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp @@ -1,35 +1,35 @@ -#pragma once +// #pragma once -#include "init.hpp" +// #include "init.hpp" -#include -#include +// #include +// #include -namespace aztec3::circuits::apps::test_apps::escrow { +// namespace aztec3::circuits::apps::test_apps::escrow { -inline Contract init_contract(FunctionExecutionContext& exec_ctx) -{ - Contract contract(exec_ctx, "Escrow"); +// inline Contract init_contract(FunctionExecutionContext& exec_ctx) +// { +// Contract contract(exec_ctx, "Escrow"); - // mapping(owner => mapping(asset_id => balance)) balances; - contract.declare_private_state_var("balances", { "owner", "asset_id" }); +// // mapping(owner => mapping(asset_id => balance)) balances; +// contract.declare_private_state_var("balances"); - // Solely used for assigning vk indices. - contract.set_functions({ - { .name = "deposit", .is_private = true }, - { .name = "transfer", .is_private = true }, - { .name = "withdraw", .is_private = true }, - }); +// // Solely used for assigning vk indices. +// contract.set_functions({ +// { .name = "deposit", .is_private = true }, +// { .name = "transfer", .is_private = true }, +// { .name = "withdraw", .is_private = true }, +// }); - // TODO: this L1 declaration interface is just to get something working. - contract.import_l1_function({ - .function_name = "withdraw", - .function_selector = 12345, - .num_params = 3, - }); +// // TODO: this L1 declaration interface is just to get something working. +// contract.import_l1_function({ +// .function_name = "withdraw", +// .function_selector = 12345, +// .num_params = 3, +// }); - // TODO: create a new FunctionExecutor(contract) and return it. - return contract; -} +// // TODO: create a new FunctionExecutor(contract) and return it. +// return contract; +// } -} // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file +// } // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp index c76ede9d290..59c44cea8c2 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp @@ -1,136 +1,137 @@ -#include "deposit.hpp" +// #include "deposit.hpp" -#include "contract.hpp" +// #include "contract.hpp" -#include -#include +// #include +// #include -namespace aztec3::circuits::apps::test_apps::escrow { +// namespace aztec3::circuits::apps::test_apps::escrow { -using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; +// using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; -OptionalPrivateCircuitPublicInputs deposit(FunctionExecutionContext& exec_ctx, - NT::fr const& _amount, - NT::fr const& _asset_id, - NT::fr const& _memo) -{ - auto& composer = exec_ctx.composer; - auto& oracle = exec_ctx.oracle; - Contract contract = init_contract(exec_ctx); +// OptionalPrivateCircuitPublicInputs deposit(FunctionExecutionContext& exec_ctx, +// NT::fr const& _amount, +// NT::fr const& _asset_id, +// NT::fr const& _memo) +// { +// auto& composer = exec_ctx.composer; +// auto& oracle = exec_ctx.oracle; +// Contract contract = init_contract(exec_ctx); - CT::fr amount = to_ct(composer, _amount); - CT::fr asset_id = to_ct(composer, _asset_id); - CT::fr memo = to_ct(composer, _memo); +// CT::fr amount = to_ct(composer, _amount); +// CT::fr asset_id = to_ct(composer, _asset_id); +// CT::fr memo = to_ct(composer, _memo); - CT::address msg_sender = oracle.get_msg_sender(); +// CT::address msg_sender = oracle.get_msg_sender(); - auto& balances = contract.get_private_state_var("balances"); +// auto& balances = contract.get_private_state_var("balances"); - balances.at({ msg_sender.to_field(), asset_id }) - .add({ - .value = amount, - .owner = msg_sender, - .creator_address = msg_sender, - .memo = memo, - }); +// balances.at({ msg_sender.to_field(), asset_id }) +// .add({ +// .value = amount, +// .owner = msg_sender, +// .creator_address = msg_sender, +// .memo = memo, +// }); - auto& public_inputs = exec_ctx.private_circuit_public_inputs; +// auto& public_inputs = exec_ctx.private_circuit_public_inputs; - public_inputs.args[0] = amount; - public_inputs.args[1] = asset_id; - public_inputs.args[2] = memo; +// public_inputs.args[0] = amount; +// public_inputs.args[1] = asset_id; +// public_inputs.args[2] = memo; - exec_ctx.finalise(); +// exec_ctx.finalise(); - info("public inputs: ", public_inputs); +// info("public inputs: ", public_inputs); - return public_inputs.to_native_type(); - // TODO: also return note preimages and nullifier preimages. -}; +// return public_inputs.to_native_type(); +// // TODO: also return note preimages and nullifier preimages. +// }; -} // namespace aztec3::circuits::apps::test_apps::escrow +// } // namespace aztec3::circuits::apps::test_apps::escrow -// require_pokosk(owner) +// // require_pokosk(owner) -// DEPOSIT : +// // DEPOSIT : -// balances[msg.sender] += amount; +// // balances[msg.sender] += amount; -// Either : -msg_sender == owner - msg_sender is populating the private state of some other owner, -// where the state is indexed _by_ the msg_sender +// // Either : -msg_sender == owner - msg_sender is populating the private state of some other owner, +// // where the state is indexed _by_ the msg_sender -// balances[msg_sender][asset_id] = h(storage_slot, value, owner, ...); +// // balances[msg_sender][asset_id] = h(storage_slot, value, owner, ...); -// Either : -to == owner - the state is indexed _by_ to, but the owner is someone else +// // Either : -to == owner - the state is indexed _by_ to, but the owner is someone else -// balances[to][asset_id] = h(storage_slot, value, owner); +// // balances[to][asset_id] = h(storage_slot, value, owner); -// transfer: +// // transfer: -// msg.sender needs to prove they know a private key to call this: +// // msg.sender needs to prove they know a private key to call this: -// balances[msg.sender] -= amount <-- msg.sender == owner in the commitment -// balances[to] += amount <-- to == owner in the commitment +// // balances[msg.sender] -= amount <-- msg.sender == owner in the commitment +// // balances[to] += amount <-- to == owner in the commitment -// So if this is called by a smart contract (rather than a person): -// - It works for regular public solidity -// - But in private land, we actually want to produce a nullifier, so it needs to be called by a person who knows a -// secret key, in order to produce a nullifier. +// // So if this is called by a smart contract (rather than a person): +// // - It works for regular public solidity +// // - But in private land, we actually want to produce a nullifier, so it needs to be called by a person who knows a +// // secret key, in order to produce a nullifier. -// Private approval feels difficult. +// // Private approval feels difficult. -// function approve(address spender, uint256 amount) public returns (bool success) -// { -// allowed[msg.sender][spender] = amount; -// emit Approval(msg.sender, spender, amount); -// return true; -// } +// // function approve(address spender, uint256 amount) public returns (bool success) +// // { +// // allowed[msg.sender][spender] = amount; +// // emit Approval(msg.sender, spender, amount); +// // return true; +// // } -// -- -- -- -- -- -- -- -- +// // -- -- -- -- -- -- -- -- -// mapping(address = > UTXOSet) balances; -// mapping(address = > mapping(address = > UTXO)) allowed; +// // mapping(address = > UTXOSet) balances; +// // mapping(address = > mapping(address = > UTXO)) allowed; -// deposit(uint amount) -// { -// balances[msg.sender].insert(amount, { owner : msg.sender }); // specify commitment owner? -// } +// // deposit(uint amount) +// // { +// // balances[msg.sender].insert(amount, { owner : msg.sender }); // specify commitment owner? +// // } -// transfer(uint amount, address to) -// { -// UTXO[2] notes = balances[msg.sender].get(2, sort, filter, { owner : msg.sender }); +// // transfer(uint amount, address to) +// // { +// // UTXO[2] notes = balances[msg.sender].get(2, sort, filter, { owner : msg.sender }); -// uint input_amount = notes[0].value + notes[1].value; -// require(input_amount >= amount); +// // uint input_amount = notes[0].value + notes[1].value; +// // require(input_amount >= amount); -// notes[0].remove(); -// notes[1].remove(); +// // notes[0].remove(); +// // notes[1].remove(); -// balances[msg.sender].insert(input_amount - amount, { owner : msg.sender }); +// // balances[msg.sender].insert(input_amount - amount, { owner : msg.sender }); -// balances[to].insert(amount, { owner : to }); -// } +// // balances[to].insert(amount, { owner : to }); +// // } -// approve(address spender, uint amount) -// { -// UTXO note = allowed[msg.sender][spender].get(1, { owner : msg.sender }); -// allowed[msg.sender][spender].replace(increase_amount, { owner : spender }); -// } +// // approve(address spender, uint amount) +// // { +// // UTXO note = allowed[msg.sender][spender].get(1, { owner : msg.sender }); +// // allowed[msg.sender][spender].replace(increase_amount, { owner : spender }); +// // } -// function transferFrom(address sender, address recipient, uint256 amount) -// { +// // function transferFrom(address sender, address recipient, uint256 amount) +// // { -// require(balances[sender] >= amount, "Insufficient balance."); -// require(allowed[sender][msg.sender] >= amount, "Insufficient allowance."); +// // require(balances[sender] >= amount, "Insufficient balance."); +// // require(allowed[sender][msg.sender] >= amount, "Insufficient allowance."); -// balances[sender] = balances[sender].sub(amount); -// allowed[sender][msg.sender] = allowed[sender][msg.sender].sub(amount); -// balances[recipient] = balances[recipient].add(amount); -// emit Transfer(sender, recipient, amount); -// return true; -// } +// // balances[sender] = balances[sender].sub(amount); +// // allowed[sender][msg.sender] = allowed[sender][msg.sender].sub(amount); +// // balances[recipient] = balances[recipient].add(amount); +// // emit Transfer(sender, recipient, amount); +// // return true; +// // } -// Initialising singleton UTXOs: -// - We want to ensure we never create more than 1 UTXO in the tree for such a variable. -// - So we can't use "optional" to get a dummy UTXO (because then a user could call the functoin multiple times, eeach -// time _get_ a dummy UTXO, and then create loads of competing notes for the same variable). \ No newline at end of file +// // Initialising singleton UTXOs: +// // - We want to ensure we never create more than 1 UTXO in the tree for such a variable. +// // - So we can't use "optional" to get a dummy UTXO (because then a user could call the functoin multiple times, +// eeach +// // time _get_ a dummy UTXO, and then create loads of competing notes for the same variable). \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.hpp index a4d066b12c3..59f3bbf2cfb 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.hpp @@ -1,17 +1,17 @@ -#pragma once +// #pragma once -#include "init.hpp" +// #include "init.hpp" -#include -#include +// #include +// #include -namespace aztec3::circuits::apps::test_apps::escrow { +// namespace aztec3::circuits::apps::test_apps::escrow { -using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; +// using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; -OptionalPrivateCircuitPublicInputs deposit(FunctionExecutionContext& exec_ctx, - NT::fr const& _amount, - NT::fr const& _asset_id, - NT::fr const& _memo); +// OptionalPrivateCircuitPublicInputs deposit(FunctionExecutionContext& exec_ctx, +// NT::fr const& _amount, +// NT::fr const& _asset_id, +// NT::fr const& _memo); -} // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file +// } // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/index.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/index.hpp index 4cf1909486f..55dfd98f087 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/index.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/index.hpp @@ -1,5 +1,5 @@ -#include "init.hpp" -#include "contract.hpp" -#include "deposit.hpp" -#include "transfer.hpp" -#include "withdraw.hpp" \ No newline at end of file +// #include "init.hpp" +// #include "contract.hpp" +// #include "deposit.hpp" +// #include "transfer.hpp" +// #include "withdraw.hpp" \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/init.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/init.hpp index 4087a5782e9..22996d6c982 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/init.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/init.hpp @@ -1,24 +1,24 @@ -#pragma once +// #pragma once -#include -#include +// #include +// #include -#include -#include -#include -#include +// #include +// #include +// #include +// #include -namespace aztec3::circuits::apps::test_apps::escrow { +// namespace aztec3::circuits::apps::test_apps::escrow { -using Composer = plonk::stdlib::types::turbo::Composer; +// using Composer = plonk::stdlib::types::turbo::Composer; -using CT = plonk::stdlib::types::CircuitTypes; -using NT = plonk::stdlib::types::NativeTypes; +// using CT = plonk::stdlib::types::CircuitTypes; +// using NT = plonk::stdlib::types::NativeTypes; -using DB = oracle::FakeDB; -using oracle::NativeOracle; -using OracleWrapper = OracleWrapperInterface; +// using DB = oracle::FakeDB; +// using oracle::NativeOracle; +// using OracleWrapper = OracleWrapperInterface; -using plonk::stdlib::types::to_ct; +// using plonk::stdlib::types::to_ct; -} // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file +// } // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp index 15f481a16f0..5566c2d0ede 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp @@ -1,88 +1,88 @@ -#include "transfer.hpp" +// #include "transfer.hpp" -#include "contract.hpp" +// #include "contract.hpp" -#include -#include +// #include +// #include -namespace aztec3::circuits::apps::test_apps::escrow { +// namespace aztec3::circuits::apps::test_apps::escrow { -using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; +// using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; -OptionalPrivateCircuitPublicInputs transfer(FunctionExecutionContext& exec_ctx, - NT::fr const& _amount, - NT::address const& _to, - NT::fr const& _asset_id, - NT::fr const& _memo, - NT::boolean const& _reveal_msg_sender_to_recipient, - NT::fr const& _fee) -{ - info("\n\nin transfer..."); +// OptionalPrivateCircuitPublicInputs transfer(FunctionExecutionContext& exec_ctx, +// NT::fr const& _amount, +// NT::address const& _to, +// NT::fr const& _asset_id, +// NT::fr const& _memo, +// NT::boolean const& _reveal_msg_sender_to_recipient, +// NT::fr const& _fee) +// { +// info("\n\nin transfer..."); - // Initialisation *************************************************************** +// // Initialisation *************************************************************** - auto& composer = exec_ctx.composer; - auto& oracle = exec_ctx.oracle; - Contract contract = init_contract(exec_ctx); +// auto& composer = exec_ctx.composer; +// auto& oracle = exec_ctx.oracle; +// Contract contract = init_contract(exec_ctx); - CT::fr amount = to_ct(composer, _amount); - CT::address to = to_ct(composer, _to); - CT::fr asset_id = to_ct(composer, _asset_id); - CT::fr memo = to_ct(composer, _memo); - CT::boolean reveal_msg_sender_to_recipient = to_ct(composer, _reveal_msg_sender_to_recipient); - CT::fr fee = to_ct(composer, _fee); +// CT::fr amount = to_ct(composer, _amount); +// CT::address to = to_ct(composer, _to); +// CT::fr asset_id = to_ct(composer, _asset_id); +// CT::fr memo = to_ct(composer, _memo); +// CT::boolean reveal_msg_sender_to_recipient = to_ct(composer, _reveal_msg_sender_to_recipient); +// CT::fr fee = to_ct(composer, _fee); - // Get states and globals ******************************************************* +// // Get states and globals ******************************************************* - CT::address msg_sender = oracle.get_msg_sender(); +// CT::address msg_sender = oracle.get_msg_sender(); - auto& balances = contract.get_private_state_var("balances"); +// auto& balances = contract.get_private_state_var("balances"); - // Circuit-specific logic ******************************************************* +// // Circuit-specific logic ******************************************************* - CT::address creator_address = - CT::address::conditional_assign(reveal_msg_sender_to_recipient, msg_sender, CT::address(0)); +// CT::address creator_address = +// CT::address::conditional_assign(reveal_msg_sender_to_recipient, msg_sender, CT::address(0)); - balances.at({ msg_sender.to_field(), asset_id }) - .subtract({ - .value = amount + fee, - .owner = msg_sender, - .creator_address = msg_sender, - .memo = memo, - }); +// balances.at({ msg_sender.to_field(), asset_id }) +// .subtract({ +// .value = amount + fee, +// .owner = msg_sender, +// .creator_address = msg_sender, +// .memo = memo, +// }); - balances.at({ to.to_field(), asset_id }) - .add({ - .value = amount, - .owner = to, - .creator_address = creator_address, - .memo = memo, - }); +// balances.at({ to.to_field(), asset_id }) +// .add({ +// .value = amount, +// .owner = to, +// .creator_address = creator_address, +// .memo = memo, +// }); - // Assign circuit-specific public inputs **************************************** +// // Assign circuit-specific public inputs **************************************** - auto& public_inputs = exec_ctx.private_circuit_public_inputs; +// auto& public_inputs = exec_ctx.private_circuit_public_inputs; - public_inputs.args[0] = amount; - public_inputs.args[1] = to.to_field(); - public_inputs.args[2] = asset_id; - public_inputs.args[3] = memo; - public_inputs.args[4] = CT::fr(reveal_msg_sender_to_recipient); - public_inputs.args[5] = fee; +// public_inputs.args[0] = amount; +// public_inputs.args[1] = to.to_field(); +// public_inputs.args[2] = asset_id; +// public_inputs.args[3] = memo; +// public_inputs.args[4] = CT::fr(reveal_msg_sender_to_recipient); +// public_inputs.args[5] = fee; - public_inputs.emitted_events[0] = CT::fr::copy_as_new_witness(composer, fee); - public_inputs.emitted_events[1] = CT::fr::copy_as_new_witness(composer, asset_id); +// public_inputs.emitted_events[0] = CT::fr::copy_as_new_witness(composer, fee); +// public_inputs.emitted_events[1] = CT::fr::copy_as_new_witness(composer, asset_id); - /// TODO: merkle membership check - // public_inputs.old_private_data_tree_root +// /// TODO: merkle membership check +// // public_inputs.old_private_data_tree_root - // Finalise ********************************************************************* +// // Finalise ********************************************************************* - exec_ctx.finalise(); +// exec_ctx.finalise(); - info("public inputs: ", public_inputs); +// info("public inputs: ", public_inputs); - return public_inputs.to_native_type(); -}; +// return public_inputs.to_native_type(); +// }; -} // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file +// } // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.hpp index 2e98db62781..f91e8e91497 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.hpp @@ -1,20 +1,20 @@ -#pragma once +// #pragma once -#include "init.hpp" +// #include "init.hpp" -#include -#include +// #include +// #include -namespace aztec3::circuits::apps::test_apps::escrow { +// namespace aztec3::circuits::apps::test_apps::escrow { -using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; +// using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; -OptionalPrivateCircuitPublicInputs transfer(FunctionExecutionContext& exec_ctx, - NT::fr const& _amount, - NT::address const& _to, - NT::fr const& _asset_id, - NT::fr const& _memo, - NT::boolean const& _reveal_msg_sender_to_recipient, - NT::fr const& _fee); +// OptionalPrivateCircuitPublicInputs transfer(FunctionExecutionContext& exec_ctx, +// NT::fr const& _amount, +// NT::address const& _to, +// NT::fr const& _asset_id, +// NT::fr const& _memo, +// NT::boolean const& _reveal_msg_sender_to_recipient, +// NT::fr const& _fee); -} // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file +// } // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp index 67b43a91cd7..8055b7001a7 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp @@ -1,78 +1,78 @@ -#include "withdraw.hpp" +// #include "withdraw.hpp" -#include "contract.hpp" +// #include "contract.hpp" -#include -#include +// #include +// #include -namespace aztec3::circuits::apps::test_apps::escrow { +// namespace aztec3::circuits::apps::test_apps::escrow { -using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; +// using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; -OptionalPrivateCircuitPublicInputs withdraw(FunctionExecutionContext& exec_ctx, - NT::fr const& _amount, - NT::fr const& _asset_id, - NT::fr const& _memo, - NT::fr const& _l1_withdrawal_address, - NT::fr const& _fee) -{ - info("\n\nin withdraw..."); +// OptionalPrivateCircuitPublicInputs withdraw(FunctionExecutionContext& exec_ctx, +// NT::fr const& _amount, +// NT::fr const& _asset_id, +// NT::fr const& _memo, +// NT::fr const& _l1_withdrawal_address, +// NT::fr const& _fee) +// { +// info("\n\nin withdraw..."); - // Initialisation *************************************************************** +// // Initialisation *************************************************************** - auto& composer = exec_ctx.composer; - auto& oracle = exec_ctx.oracle; - Contract contract = init_contract(exec_ctx); +// auto& composer = exec_ctx.composer; +// auto& oracle = exec_ctx.oracle; +// Contract contract = init_contract(exec_ctx); - CT::fr amount = to_ct(composer, _amount); - CT::fr asset_id = to_ct(composer, _asset_id); - CT::fr memo = to_ct(composer, _memo); - CT::fr l1_withdrawal_address = to_ct(composer, _l1_withdrawal_address); - CT::fr fee = to_ct(composer, _fee); +// CT::fr amount = to_ct(composer, _amount); +// CT::fr asset_id = to_ct(composer, _asset_id); +// CT::fr memo = to_ct(composer, _memo); +// CT::fr l1_withdrawal_address = to_ct(composer, _l1_withdrawal_address); +// CT::fr fee = to_ct(composer, _fee); - // Get states and globals ******************************************************* +// // Get states and globals ******************************************************* - CT::address msg_sender = oracle.get_msg_sender(); +// CT::address msg_sender = oracle.get_msg_sender(); - auto& balances = contract.get_private_state_var("balances"); +// auto& balances = contract.get_private_state_var("balances"); - // Circuit-specific logic ******************************************************* +// // Circuit-specific logic ******************************************************* - balances.at({ msg_sender.to_field(), asset_id }) - .subtract({ - .value = amount + fee, - .owner = msg_sender, - .creator_address = msg_sender, - .memo = memo, - }); +// balances.at({ msg_sender.to_field(), asset_id }) +// .subtract({ +// .value = amount + fee, +// .owner = msg_sender, +// .creator_address = msg_sender, +// .memo = memo, +// }); - auto& l1_withdraw_function = contract.get_l1_function("withdraw"); +// auto& l1_withdraw_function = contract.get_l1_function("withdraw"); - // TODO: this doesn't do anything at the moment: - l1_withdraw_function.call({ asset_id, amount, msg_sender.to_field() }); +// // TODO: this doesn't do anything at the moment: +// l1_withdraw_function.call({ asset_id, amount, msg_sender.to_field() }); - // Assign circuit-specific public inputs **************************************** +// // Assign circuit-specific public inputs **************************************** - auto& public_inputs = exec_ctx.private_circuit_public_inputs; +// auto& public_inputs = exec_ctx.private_circuit_public_inputs; - public_inputs.args[0] = amount; - public_inputs.args[1] = asset_id; - public_inputs.args[2] = memo; - public_inputs.args[3] = l1_withdrawal_address; - public_inputs.args[4] = fee; +// public_inputs.args[0] = amount; +// public_inputs.args[1] = asset_id; +// public_inputs.args[2] = memo; +// public_inputs.args[3] = l1_withdrawal_address; +// public_inputs.args[4] = fee; - public_inputs.emitted_events[0] = CT::fr::copy_as_new_witness(composer, l1_withdrawal_address); - public_inputs.emitted_events[1] = CT::fr::copy_as_new_witness(composer, asset_id); - public_inputs.emitted_events[2] = CT::fr::copy_as_new_witness(composer, fee); +// public_inputs.emitted_events[0] = CT::fr::copy_as_new_witness(composer, l1_withdrawal_address); +// public_inputs.emitted_events[1] = CT::fr::copy_as_new_witness(composer, asset_id); +// public_inputs.emitted_events[2] = CT::fr::copy_as_new_witness(composer, fee); - exec_ctx.finalise(); +// exec_ctx.finalise(); - /// TODO: merkle membership check - // public_inputs.old_private_data_tree_root +// /// TODO: merkle membership check +// // public_inputs.old_private_data_tree_root - info("public inputs: ", public_inputs); +// info("public inputs: ", public_inputs); - return public_inputs.to_native_type(); -}; +// return public_inputs.to_native_type(); +// }; -} // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file +// } // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.hpp index c655c9f84dc..1163bc7a011 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.hpp @@ -1,19 +1,19 @@ -#pragma once +// #pragma once -#include "init.hpp" +// #include "init.hpp" -#include -#include +// #include +// #include -namespace aztec3::circuits::apps::test_apps::escrow { +// namespace aztec3::circuits::apps::test_apps::escrow { -using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; +// using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; -OptionalPrivateCircuitPublicInputs withdraw(FunctionExecutionContext& exec_ctx, - NT::fr const& _amount, - NT::fr const& _asset_id, - NT::fr const& _memo, - NT::fr const& _l1_withdrawal_address, - NT::fr const& _fee); +// OptionalPrivateCircuitPublicInputs withdraw(FunctionExecutionContext& exec_ctx, +// NT::fr const& _amount, +// NT::fr const& _asset_id, +// NT::fr const& _memo, +// NT::fr const& _l1_withdrawal_address, +// NT::fr const& _fee); -} // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file +// } // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp index 5cd1a6d13d2..46a37e99797 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp @@ -1,42 +1,43 @@ -#include -#include -#include "index.hpp" +// #include +// #include +// #include "index.hpp" -namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { +// namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { -class private_to_private_function_call_tests : public ::testing::Test {}; +// class private_to_private_function_call_tests : public ::testing::Test {}; -TEST(private_to_private_function_call_tests, test_private_to_private_function_call) -{ +// TEST(private_to_private_function_call_tests, test_private_to_private_function_call) +// { - Composer fn1_composer; - DB db; +// Composer fn1_composer; +// DB db; - const NT::address contract_address = 12345; - const NT::fr msg_sender_private_key = 123456789; - const NT::address msg_sender = - NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); - const NT::address tx_origin = msg_sender; +// const NT::address contract_address = 12345; +// const NT::fr msg_sender_private_key = 123456789; +// const NT::address msg_sender = +// NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, +// 0x2ef9f7f09867fd6eULL)); +// const NT::address tx_origin = msg_sender; - NativeOracle fn1_oracle = NativeOracle(db, contract_address, msg_sender, tx_origin, msg_sender_private_key); - OracleWrapper fn1_oracle_wrapper = OracleWrapper(fn1_composer, fn1_oracle); +// NativeOracle fn1_oracle = NativeOracle(db, contract_address, msg_sender, tx_origin, msg_sender_private_key); +// OracleWrapper fn1_oracle_wrapper = OracleWrapper(fn1_composer, fn1_oracle); - FunctionExecutionContext fn1_exec_ctx(fn1_composer, fn1_oracle_wrapper); +// FunctionExecutionContext fn1_exec_ctx(fn1_composer, fn1_oracle_wrapper); - auto a = NT::fr(111); - auto b = NT::fr(222); - auto c = NT::fr(333); +// auto a = NT::fr(111); +// auto b = NT::fr(222); +// auto c = NT::fr(333); - auto result = function1(fn1_exec_ctx, a, b, c); - info("result: ", result); +// auto result = function1(fn1_exec_ctx, a, b, c); +// info("result: ", result); - info("computed witness: ", fn1_composer.computed_witness); - info("witness: ", fn1_composer.witness); - // info("constant variables: ", fn1_composer.constant_variables); - // info("variables: ", fn1_composer.variables); - info("failed?: ", fn1_composer.failed); - info("err: ", fn1_composer.err); - info("n: ", fn1_composer.n); -} +// info("computed witness: ", fn1_composer.computed_witness); +// info("witness: ", fn1_composer.witness); +// // info("constant variables: ", fn1_composer.constant_variables); +// // info("variables: ", fn1_composer.variables); +// info("failed?: ", fn1_composer.failed); +// info("err: ", fn1_composer.err); +// info("n: ", fn1_composer.n); +// } -} // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file +// } // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/contract.hpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/contract.hpp index df0b6ce0921..4363647ab6e 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/contract.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/contract.hpp @@ -1,25 +1,25 @@ -#pragma once -#include -#include -#include -#include "init.hpp" +// #pragma once +// #include +// #include +// #include +// #include "init.hpp" -namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { +// namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { -inline Contract init_contract(FunctionExecutionContext& exec_ctx) -{ - Contract contract(exec_ctx, "priv_to_priv_function_call"); +// inline Contract init_contract(FunctionExecutionContext& exec_ctx) +// { +// Contract contract(exec_ctx, "priv_to_priv_function_call"); - contract.declare_private_state_var("x"); - contract.declare_private_state_var("y"); +// contract.declare_private_state_var("x"); +// contract.declare_private_state_var("y"); - // Solely used for assigning vk indices. - contract.set_functions({ - { .name = "function1", .is_private = true }, - { .name = "function2", .is_private = true }, - }); +// // Solely used for assigning vk indices. +// contract.set_functions({ +// { .name = "function1", .is_private = true }, +// { .name = "function2", .is_private = true }, +// }); - return contract; -} +// return contract; +// } -} // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file +// } // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.cpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.cpp index d1988b3b010..256a9bd1634 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.cpp @@ -1,71 +1,73 @@ -#include "function1.hpp" -#include -#include -#include "contract.hpp" +// #include "function1.hpp" +// #include +// #include +// #include "contract.hpp" -namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { +// namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { -using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; +// using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; -OptionalPrivateCircuitPublicInputs function1(FunctionExecutionContext& exec_ctx, - NT::fr const& _a, - NT::fr const& _b, - NT::fr const& _c) -{ - auto& composer = exec_ctx.composer; - auto& oracle = exec_ctx.oracle; - Contract contract = init_contract(exec_ctx); +// OptionalPrivateCircuitPublicInputs function1(FunctionExecutionContext& exec_ctx, +// NT::fr const& _a, +// NT::fr const& _b, +// NT::fr const& _c) +// { +// auto& composer = exec_ctx.composer; +// auto& oracle = exec_ctx.oracle; +// Contract contract = init_contract(exec_ctx); - CT::fr a = to_ct(composer, _a); - CT::fr b = to_ct(composer, _b); - CT::fr c = to_ct(composer, _c); +// CT::fr a = to_ct(composer, _a); +// CT::fr b = to_ct(composer, _b); +// CT::fr c = to_ct(composer, _c); - CT::address msg_sender = oracle.get_msg_sender(); +// CT::address msg_sender = oracle.get_msg_sender(); - auto& x = contract.get_private_state_var("x"); +// auto& x = contract.get_private_state_var("x"); - x.add({ - .value = a, - .owner = msg_sender, - .creator_address = msg_sender, - .memo = 0, - }); +// x.add({ +// .value = a, +// .owner = msg_sender, +// .creator_address = msg_sender, +// .memo = 0, +// }); - // auto function2 = contract.get_function("function2"); - const NT::address fn2_contract_address = 23456; +// // auto function2 = contract.get_function("function2"); +// const NT::address fn2_contract_address = 23456; - Composer fn2_composer; +// Composer fn2_composer; - // Note: it's ok that we swap back into Native Types here - we don't need constraints. Creation of fn2_oracle is - // necessary for circuit construction only; it's not part of the circuit itself. We check that the call_contexts - // (msg_sender, contract_address, tx_origin) of functions 1 & 2 relate to one-another in the private kernel circuit, - // by comparing the functions' public inputs. - NativeOracle fn2_oracle = NativeOracle(oracle.oracle.db, - fn2_contract_address, - oracle.get_this_contract_address() - .to_field() - .get_value(), // TODO: add get_value() method to address type directly. - oracle.get_tx_origin().to_field().get_value()); - OracleWrapper fn2_oracle_wrapper = OracleWrapper(fn2_composer, fn2_oracle); +// // Note: it's ok that we swap back into Native Types here - we don't need constraints. Creation of fn2_oracle is +// // necessary for circuit construction only; it's not part of the circuit itself. We check that the call_contexts +// // (msg_sender, contract_address, tx_origin) of functions 1 & 2 relate to one-another in the private kernel +// circuit, +// // by comparing the functions' public inputs. +// NativeOracle fn2_oracle = NativeOracle(oracle.oracle.db, +// fn2_contract_address, +// oracle.get_this_contract_address() +// .to_field() +// .get_value(), // TODO: add get_value() method to address type +// directly. +// oracle.get_tx_origin().to_field().get_value()); +// OracleWrapper fn2_oracle_wrapper = OracleWrapper(fn2_composer, fn2_oracle); - FunctionExecutionContext fn1_exec_ctx(fn2_composer, fn2_oracle_wrapper); +// FunctionExecutionContext fn1_exec_ctx(fn2_composer, fn2_oracle_wrapper); - // auto result = function2.call(a, b, c); +// // auto result = function2.call(a, b, c); - auto& public_inputs = exec_ctx.private_circuit_public_inputs; +// auto& public_inputs = exec_ctx.private_circuit_public_inputs; - public_inputs.args[0] = a; - public_inputs.args[1] = b; - public_inputs.args[2] = c; +// public_inputs.args[0] = a; +// public_inputs.args[1] = b; +// public_inputs.args[2] = c; - // public_inputs.private_call_stack[0] = ... +// // public_inputs.private_call_stack[0] = ... - exec_ctx.finalise(); +// exec_ctx.finalise(); - info("public inputs: ", public_inputs); +// info("public inputs: ", public_inputs); - return public_inputs.to_native_type(); - // TODO: also return note preimages and nullifier preimages. -}; +// return public_inputs.to_native_type(); +// // TODO: also return note preimages and nullifier preimages. +// }; -} // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file +// } // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.hpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.hpp index 04f58ddd2b1..2a0754ff21e 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.hpp @@ -1,15 +1,15 @@ -#pragma once -#include "init.hpp" -#include -#include +// #pragma once +// #include "init.hpp" +// #include +// #include -namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { +// namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { -using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; +// using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; -OptionalPrivateCircuitPublicInputs function1(FunctionExecutionContext& exec_ctx, - NT::fr const& _a, - NT::fr const& _b, - NT::fr const& _c); +// OptionalPrivateCircuitPublicInputs function1(FunctionExecutionContext& exec_ctx, +// NT::fr const& _a, +// NT::fr const& _b, +// NT::fr const& _c); -} // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file +// } // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/index.hpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/index.hpp index 0e6564100ea..03f7484f7ee 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/index.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/index.hpp @@ -1,4 +1,4 @@ -#include "init.hpp" -#include "contract.hpp" -#include "function1.hpp" -// #include "function2.hpp" \ No newline at end of file +// #include "init.hpp" +// #include "contract.hpp" +// #include "function1.hpp" +// // #include "function2.hpp" \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/init.hpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/init.hpp index 15404f916c2..fbc4276329e 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/init.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/init.hpp @@ -1,21 +1,21 @@ -#pragma once -#include -#include -#include -#include -#include -#include +// #pragma once +// #include +// #include +// #include +// #include +// #include +// #include -namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { +// namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { -using Composer = plonk::stdlib::types::turbo::Composer; -using CT = plonk::stdlib::types::CircuitTypes; -using NT = plonk::stdlib::types::NativeTypes; +// using Composer = plonk::stdlib::types::turbo::Composer; +// using CT = plonk::stdlib::types::CircuitTypes; +// using NT = plonk::stdlib::types::NativeTypes; -using DB = oracle::FakeDB; -using oracle::NativeOracle; -using OracleWrapper = OracleWrapperInterface; +// using DB = oracle::FakeDB; +// using oracle::NativeOracle; +// using OracleWrapper = OracleWrapperInterface; -using plonk::stdlib::types::to_ct; +// using plonk::stdlib::types::to_ct; -} // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file +// } // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/kernel/private/.test.cpp b/circuits/src/aztec3/circuits/kernel/private/.test.cpp index c4af8b8da35..8d5e49b81b1 100644 --- a/circuits/src/aztec3/circuits/kernel/private/.test.cpp +++ b/circuits/src/aztec3/circuits/kernel/private/.test.cpp @@ -1,248 +1,251 @@ -// #include -// #include -// #include -// #include -// #include -#include "index.hpp" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +// // #include +// // #include +// // #include +// // #include +// // #include +// #include "index.hpp" + +// #include + +// #include +// #include +// #include +// #include +// #include +// #include +// #include // #include -// #include - -// #include -#include - -#include -#include -#include - -// #include -// #include -// #include - -namespace { - -using aztec3::circuits::abis::CallContext; -using aztec3::circuits::abis::CallStackItem; -using aztec3::circuits::abis::CallType; -using aztec3::circuits::abis::FunctionSignature; -using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; -using aztec3::circuits::abis::PrivateCircuitPublicInputs; -using aztec3::circuits::abis::SignedTxObject; -using aztec3::circuits::abis::TxContext; -using aztec3::circuits::abis::TxObject; - -using aztec3::circuits::abis::private_kernel::AccumulatedData; -using aztec3::circuits::abis::private_kernel::ConstantData; -using aztec3::circuits::abis::private_kernel::Globals; -using aztec3::circuits::abis::private_kernel::OldTreeRoots; -using aztec3::circuits::abis::private_kernel::PreviousKernelData; -using aztec3::circuits::abis::private_kernel::PrivateCallData; -using aztec3::circuits::abis::private_kernel::PrivateInputs; -using aztec3::circuits::abis::private_kernel::PublicInputs; - -using aztec3::circuits::apps::test_apps::escrow::deposit; - -// using aztec3::circuits::mock::mock_circuit; -using aztec3::circuits::mock::mock_kernel_circuit; - -} // namespace - -namespace aztec3::circuits::kernel::private_kernel { - -class private_kernel_tests : public ::testing::Test {}; - -TEST(private_kernel_tests, test_deposit) -{ - //*************************************************************************** - // Some private circuit proof (`deposit`, in this case) - //*************************************************************************** - - const NT::address escrow_contract_address = 12345; - const NT::fr escrow_contract_leaf_index = 1; - const NT::fr escrow_portal_contract_address = 23456; - - const NT::fr msg_sender_private_key = 123456789; - const NT::address msg_sender = - NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); - const NT::address tx_origin = msg_sender; - - Composer deposit_composer; - DB db; - - NativeOracle deposit_oracle = - NativeOracle(db, escrow_contract_address, msg_sender, tx_origin, msg_sender_private_key); - OracleWrapper deposit_oracle_wrapper = OracleWrapper(deposit_composer, deposit_oracle); - - FunctionExecutionContext deposit_ctx(deposit_composer, deposit_oracle_wrapper); - - auto amount = NT::fr(5); - auto asset_id = NT::fr(1); - auto memo = NT::fr(999); - - OptionalPrivateCircuitPublicInputs opt_deposit_public_inputs = deposit(deposit_ctx, amount, asset_id, memo); - PrivateCircuitPublicInputs deposit_public_inputs = opt_deposit_public_inputs.remove_optionality(); - - UnrolledProver deposit_prover = deposit_composer.create_unrolled_prover(); - NT::Proof deposit_proof = deposit_prover.construct_proof(); - // info("\ndeposit_proof: ", deposit_proof.proof_data); - - std::shared_ptr deposit_vk = deposit_composer.compute_verification_key(); - - //*************************************************************************** - // We can create a TxObject from some of the above data. Users must sign a TxObject in order to give permission for - // a tx to take place - creating a SignedTxObject. - //*************************************************************************** - - TxObject deposit_tx_object = TxObject{ - .from = tx_origin, - .to = escrow_contract_address, - .function_signature = - FunctionSignature{ - .vk_index = 0, // TODO: deduce this from the contract, somehow. - .is_private = true, - .is_constructor = false, - }, - .args = deposit_public_inputs.args, - .nonce = 0, - .tx_context = - TxContext{ - .called_from_l1 = false, - .called_from_public_l2 = false, - .is_fee_payment_tx = false, - .reference_block_num = 0, - }, - .chain_id = 1, - }; - - SignedTxObject signed_deposit_tx_object = SignedTxObject{ - .tx_object = deposit_tx_object, - - // .signature = TODO: need a method for signing a TxObject. - }; - - //*************************************************************************** - // We mock a kernel circuit proof for the base case of kernel recursion (because even the first iteration of the - // kernel circuit expects to verify some previous kernel circuit). - //*************************************************************************** - - Composer mock_kernel_composer; - - // TODO: we have a choice to make: - // Either the `end` state of the mock kernel's public inputs can be set equal to the public call we _want_ to - // verify in the first round of recursion, OR, we have some fiddly conditional logic in the circuit to ignore - // certain checks if we're handling the 'base case' of the recursion. - // I've chosen the former, for now. - const CallStackItem deposit_call_stack_item{ - .contract_address = deposit_tx_object.to, - - .function_signature = deposit_tx_object.function_signature, - - .public_inputs = deposit_public_inputs, - }; - - std::array initial_kernel_private_call_stack{}; - initial_kernel_private_call_stack[0] = deposit_call_stack_item.hash(); - - // Some test data: - auto mock_kernel_public_inputs = PublicInputs{ - .end = - AccumulatedData{ - .private_call_stack = initial_kernel_private_call_stack, - }, - - // These will be constant throughout all recursions, so can be set to those of the first function call - the - // deposit tx. - .constants = - ConstantData{ - .old_tree_roots = - OldTreeRoots{ - .private_data_tree_root = deposit_public_inputs.old_private_data_tree_root, - // .nullifier_tree_root = - // .contract_tree_root = - // .private_kernel_vk_tree_root = - }, - .tx_context = deposit_tx_object.tx_context, - }, - - .is_private = true, - // .is_public = false, - // .is_contract_deployment = false, - }; - - mock_kernel_circuit(mock_kernel_composer, mock_kernel_public_inputs); - - UnrolledProver mock_kernel_prover = mock_kernel_composer.create_unrolled_prover(); - NT::Proof mock_kernel_proof = mock_kernel_prover.construct_proof(); - // info("\nmock_kernel_proof: ", mock_kernel_proof.proof_data); - - std::shared_ptr mock_kernel_vk = mock_kernel_composer.compute_verification_key(); - - //*************************************************************************** - // Now we can execute and prove the first kernel iteration, with all the data generated above: - // - app proof, public inputs, etc. - // - mock kernel proof, public inputs, etc. - //*************************************************************************** - - Composer private_kernel_composer; - - // TODO: I think we need a different kind of oracle for the kernel circuits... - NativeOracle private_kernel_oracle = NativeOracle(db, escrow_contract_address, msg_sender, msg_sender_private_key); - OracleWrapper private_kernel_oracle_wrapper = OracleWrapper(private_kernel_composer, private_kernel_oracle); - - PrivateInputs private_inputs = PrivateInputs{ - .signed_tx_object = signed_deposit_tx_object, - - .previous_kernel = - PreviousKernelData{ - .public_inputs = mock_kernel_public_inputs, - .proof = mock_kernel_proof, - .vk = mock_kernel_vk, - }, - - .private_call = - PrivateCallData{ - .call_stack_item = deposit_call_stack_item, - // .call_context_reconciliation_data = TODO - - .proof = deposit_proof, - .vk = deposit_vk, - // .vk_path TODO - - // .contract_tree_root TODO - .contract_leaf_index = escrow_contract_leaf_index, - // .contract_path TODO - - .portal_contract_address = escrow_portal_contract_address, - }, - }; - - private_kernel_circuit(private_kernel_composer, private_kernel_oracle_wrapper, private_inputs); - - info("computed witness: ", private_kernel_composer.computed_witness); - info("witness: ", private_kernel_composer.witness); - // info("constant variables: ", private_kernel_composer.constant_variables); - // info("variables: ", private_kernel_composer.variables); - - // TODO: this fails intermittently, with: - // bigfield multiply range check failed - info("failed?: ", private_kernel_composer.failed); - info("err: ", private_kernel_composer.err); - info("n: ", private_kernel_composer.n); -} - -} // namespace aztec3::circuits::kernel::private_kernel \ No newline at end of file +// #include +// #include +// #include +// #include +// #include +// // #include +// // #include + +// // #include +// #include + +// #include +// #include +// #include + +// // #include +// // #include +// // #include + +// namespace { + +// using aztec3::circuits::abis::CallContext; +// using aztec3::circuits::abis::CallStackItem; +// using aztec3::circuits::abis::CallType; +// using aztec3::circuits::abis::FunctionSignature; +// using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; +// using aztec3::circuits::abis::PrivateCircuitPublicInputs; +// using aztec3::circuits::abis::SignedTxObject; +// using aztec3::circuits::abis::TxContext; +// using aztec3::circuits::abis::TxObject; + +// using aztec3::circuits::abis::private_kernel::AccumulatedData; +// using aztec3::circuits::abis::private_kernel::ConstantData; +// using aztec3::circuits::abis::private_kernel::Globals; +// using aztec3::circuits::abis::private_kernel::OldTreeRoots; +// using aztec3::circuits::abis::private_kernel::PreviousKernelData; +// using aztec3::circuits::abis::private_kernel::PrivateCallData; +// using aztec3::circuits::abis::private_kernel::PrivateInputs; +// using aztec3::circuits::abis::private_kernel::PublicInputs; + +// using aztec3::circuits::apps::test_apps::escrow::deposit; + +// // using aztec3::circuits::mock::mock_circuit; +// using aztec3::circuits::mock::mock_kernel_circuit; + +// } // namespace + +// namespace aztec3::circuits::kernel::private_kernel { + +// class private_kernel_tests : public ::testing::Test {}; + +// TEST(private_kernel_tests, test_deposit) +// { +// //*************************************************************************** +// // Some private circuit proof (`deposit`, in this case) +// //*************************************************************************** + +// const NT::address escrow_contract_address = 12345; +// const NT::fr escrow_contract_leaf_index = 1; +// const NT::fr escrow_portal_contract_address = 23456; + +// const NT::fr msg_sender_private_key = 123456789; +// const NT::address msg_sender = +// NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, +// 0x2ef9f7f09867fd6eULL)); +// const NT::address tx_origin = msg_sender; + +// Composer deposit_composer; +// DB db; + +// NativeOracle deposit_oracle = +// NativeOracle(db, escrow_contract_address, msg_sender, tx_origin, msg_sender_private_key); +// OracleWrapper deposit_oracle_wrapper = OracleWrapper(deposit_composer, deposit_oracle); + +// FunctionExecutionContext deposit_ctx(deposit_composer, deposit_oracle_wrapper); + +// auto amount = NT::fr(5); +// auto asset_id = NT::fr(1); +// auto memo = NT::fr(999); + +// OptionalPrivateCircuitPublicInputs opt_deposit_public_inputs = deposit(deposit_ctx, amount, asset_id, memo); +// PrivateCircuitPublicInputs deposit_public_inputs = opt_deposit_public_inputs.remove_optionality(); + +// UnrolledProver deposit_prover = deposit_composer.create_unrolled_prover(); +// NT::Proof deposit_proof = deposit_prover.construct_proof(); +// // info("\ndeposit_proof: ", deposit_proof.proof_data); + +// std::shared_ptr deposit_vk = deposit_composer.compute_verification_key(); + +// //*************************************************************************** +// // We can create a TxObject from some of the above data. Users must sign a TxObject in order to give permission +// for +// // a tx to take place - creating a SignedTxObject. +// //*************************************************************************** + +// TxObject deposit_tx_object = TxObject{ +// .from = tx_origin, +// .to = escrow_contract_address, +// .function_signature = +// FunctionSignature{ +// .vk_index = 0, // TODO: deduce this from the contract, somehow. +// .is_private = true, +// .is_constructor = false, +// }, +// .args = deposit_public_inputs.args, +// .nonce = 0, +// .tx_context = +// TxContext{ +// .called_from_l1 = false, +// .called_from_public_l2 = false, +// .is_fee_payment_tx = false, +// .reference_block_num = 0, +// }, +// .chain_id = 1, +// }; + +// SignedTxObject signed_deposit_tx_object = SignedTxObject{ +// .tx_object = deposit_tx_object, + +// // .signature = TODO: need a method for signing a TxObject. +// }; + +// //*************************************************************************** +// // We mock a kernel circuit proof for the base case of kernel recursion (because even the first iteration of the +// // kernel circuit expects to verify some previous kernel circuit). +// //*************************************************************************** + +// Composer mock_kernel_composer; + +// // TODO: we have a choice to make: +// // Either the `end` state of the mock kernel's public inputs can be set equal to the public call we _want_ to +// // verify in the first round of recursion, OR, we have some fiddly conditional logic in the circuit to ignore +// // certain checks if we're handling the 'base case' of the recursion. +// // I've chosen the former, for now. +// const CallStackItem deposit_call_stack_item{ +// .contract_address = deposit_tx_object.to, + +// .function_signature = deposit_tx_object.function_signature, + +// .public_inputs = deposit_public_inputs, +// }; + +// std::array initial_kernel_private_call_stack{}; +// initial_kernel_private_call_stack[0] = deposit_call_stack_item.hash(); + +// // Some test data: +// auto mock_kernel_public_inputs = PublicInputs{ +// .end = +// AccumulatedData{ +// .private_call_stack = initial_kernel_private_call_stack, +// }, + +// // These will be constant throughout all recursions, so can be set to those of the first function call - the +// // deposit tx. +// .constants = +// ConstantData{ +// .old_tree_roots = +// OldTreeRoots{ +// .private_data_tree_root = deposit_public_inputs.old_private_data_tree_root, +// // .nullifier_tree_root = +// // .contract_tree_root = +// // .private_kernel_vk_tree_root = +// }, +// .tx_context = deposit_tx_object.tx_context, +// }, + +// .is_private = true, +// // .is_public = false, +// // .is_contract_deployment = false, +// }; + +// mock_kernel_circuit(mock_kernel_composer, mock_kernel_public_inputs); + +// UnrolledProver mock_kernel_prover = mock_kernel_composer.create_unrolled_prover(); +// NT::Proof mock_kernel_proof = mock_kernel_prover.construct_proof(); +// // info("\nmock_kernel_proof: ", mock_kernel_proof.proof_data); + +// std::shared_ptr mock_kernel_vk = mock_kernel_composer.compute_verification_key(); + +// //*************************************************************************** +// // Now we can execute and prove the first kernel iteration, with all the data generated above: +// // - app proof, public inputs, etc. +// // - mock kernel proof, public inputs, etc. +// //*************************************************************************** + +// Composer private_kernel_composer; + +// // TODO: I think we need a different kind of oracle for the kernel circuits... +// NativeOracle private_kernel_oracle = NativeOracle(db, escrow_contract_address, msg_sender, +// msg_sender_private_key); OracleWrapper private_kernel_oracle_wrapper = OracleWrapper(private_kernel_composer, +// private_kernel_oracle); + +// PrivateInputs private_inputs = PrivateInputs{ +// .signed_tx_object = signed_deposit_tx_object, + +// .previous_kernel = +// PreviousKernelData{ +// .public_inputs = mock_kernel_public_inputs, +// .proof = mock_kernel_proof, +// .vk = mock_kernel_vk, +// }, + +// .private_call = +// PrivateCallData{ +// .call_stack_item = deposit_call_stack_item, +// // .call_context_reconciliation_data = TODO + +// .proof = deposit_proof, +// .vk = deposit_vk, +// // .vk_path TODO + +// // .contract_tree_root TODO +// .contract_leaf_index = escrow_contract_leaf_index, +// // .contract_path TODO + +// .portal_contract_address = escrow_portal_contract_address, +// }, +// }; + +// private_kernel_circuit(private_kernel_composer, private_kernel_oracle_wrapper, private_inputs); + +// info("computed witness: ", private_kernel_composer.computed_witness); +// info("witness: ", private_kernel_composer.witness); +// // info("constant variables: ", private_kernel_composer.constant_variables); +// // info("variables: ", private_kernel_composer.variables); + +// // TODO: this fails intermittently, with: +// // bigfield multiply range check failed +// info("failed?: ", private_kernel_composer.failed); +// info("err: ", private_kernel_composer.err); +// info("n: ", private_kernel_composer.n); +// } + +// } // namespace aztec3::circuits::kernel::private_kernel \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/kernel/private/index.hpp b/circuits/src/aztec3/circuits/kernel/private/index.hpp index f257de72825..753db228377 100644 --- a/circuits/src/aztec3/circuits/kernel/private/index.hpp +++ b/circuits/src/aztec3/circuits/kernel/private/index.hpp @@ -1,2 +1,2 @@ -#include "init.hpp" -#include "private_kernel_circuit.hpp" \ No newline at end of file +// #include "init.hpp" +// #include "private_kernel_circuit.hpp" \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/kernel/private/init.hpp b/circuits/src/aztec3/circuits/kernel/private/init.hpp index 0de9fc6ecfd..f3452ceaac7 100644 --- a/circuits/src/aztec3/circuits/kernel/private/init.hpp +++ b/circuits/src/aztec3/circuits/kernel/private/init.hpp @@ -1,34 +1,34 @@ -#pragma once -#include -#include -#include +// #pragma once +// #include +// #include +// #include -#include +// #include -#include +// #include -#include -#include -#include -#include +// #include +// #include +// #include +// #include -namespace aztec3::circuits::kernel::private_kernel { +// namespace aztec3::circuits::kernel::private_kernel { -// Turbo specific, at the moment: -using Composer = plonk::stdlib::types::turbo::Composer; -using plonk::stdlib::types::turbo::UnrolledProver; +// // Turbo specific, at the moment: +// using Composer = plonk::stdlib::types::turbo::Composer; +// using plonk::stdlib::types::turbo::UnrolledProver; -using Aggregator = aztec3::circuits::recursion::TurboAggregator; +// using Aggregator = aztec3::circuits::recursion::TurboAggregator; -// Generic: -using CT = plonk::stdlib::types::CircuitTypes; -using NT = plonk::stdlib::types::NativeTypes; -using plonk::stdlib::types::to_ct; +// // Generic: +// using CT = plonk::stdlib::types::CircuitTypes; +// using NT = plonk::stdlib::types::NativeTypes; +// using plonk::stdlib::types::to_ct; -using DB = oracle::FakeDB; -using oracle::NativeOracle; -using OracleWrapper = aztec3::circuits::apps::OracleWrapperInterface; +// using DB = oracle::FakeDB; +// using oracle::NativeOracle; +// using OracleWrapper = aztec3::circuits::apps::OracleWrapperInterface; -using FunctionExecutionContext = aztec3::circuits::apps::FunctionExecutionContext; +// using FunctionExecutionContext = aztec3::circuits::apps::FunctionExecutionContext; -} // namespace aztec3::circuits::kernel::private_kernel \ No newline at end of file +// } // namespace aztec3::circuits::kernel::private_kernel \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp b/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp index df636538723..2487c6fe396 100644 --- a/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp +++ b/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp @@ -1,296 +1,303 @@ -#include "init.hpp" - -#include -#include - -namespace aztec3::circuits::kernel::private_kernel { - -using aztec3::circuits::abis::private_kernel::PrivateInputs; -using aztec3::circuits::abis::private_kernel::PublicInputs; - -/****************************************************************************************************************** - * Calcs on circuit arrays. - * TODO: move these array calcs to a common/circuit_array.hpp file. - *****************************************************************************************************************/ - -/** - * Gets the number of contiguous nonzero values of an array. - * Note: this assumes `0` always means 'not used', so be careful. If you actually want `0` to be counted, you'll need - * something else. - */ -// TODO: move to own file of helper functions. -template CT::fr array_length(std::array const& arr) -{ - CT::fr length = 0; - CT::boolean hit_zero = false; - for (const auto& e : arr) { - hit_zero |= e == 0; - const CT::fr increment = !hit_zero; - length += increment; - } - return length; -}; - -/** - * Note: doesn't remove the last element from the array; only returns it! - * Note: this assumes `0` always means 'not used', so be careful. If you actually want `0` to be counted, you'll need - * something else. - * If it returns `0`, the array is considered 'empty'. - */ -template CT::fr array_pop(std::array const& arr) -{ - CT::fr popped_value; - CT::boolean already_popped = false; - for (size_t i = arr.size() - 1; i != (size_t)-1; i--) { - CT::boolean is_non_zero = arr[i] != 0; - popped_value = CT::fr::conditional_assign(!already_popped && is_non_zero, arr[i], popped_value); - - already_popped |= is_non_zero; - } - return popped_value; -}; - -/** - * Note: this assumes `0` always means 'not used', so be careful. If you actually want `0` to be counted, you'll need - * something else. - */ -template CT::boolean is_array_empty(std::array const& arr) -{ - CT::boolean nonzero_found = false; - for (size_t i = arr.size() - 1; i != (size_t)-1; i--) { - CT::boolean is_non_zero = arr[i] != 0; - nonzero_found |= is_non_zero; - } - return !nonzero_found; -}; - -/** - * Inserts the `source` array at the first zero-valued index of the `target` array. - * Fails if the `source` array is too large vs the remaining capacity of the `target` array. - */ -template -void push_array_to_array(std::array const& source, std::array& target) -{ - CT::fr target_length = array_length(target); - CT::fr source_length = array_length(source); - - CT::fr target_capacity = CT::fr(target.size()); - // TODO: using safe_fr for an underflow check, do: - // remaining_target_capacity = target_capacity.subtract(target_length + source_length); - - CT::fr t_i = 0; - CT::fr next_index = target_length; - for (const auto& s : source) { - for (auto& t : target) { - next_index.assert_not_equal(target_capacity, "Target array capacity exceeded"); - CT::boolean at_index = t_i == next_index; - t = CT::fr::conditional_assign(at_index, s, t); - next_index = CT::fr::conditional_assign(at_index, next_index + 1, next_index); - ++t_i; - } - } -} - -/*************************************************************************************************************** - * End of array calcs. - **************************************************************************************************************/ - -// TODO: NEED TO RECONCILE THE `proof`'s public inputs (which are uint8's) with the -// private_call.call_stack_item.public_inputs! -CT::AggregationObject verify_proofs(Composer& composer, - PrivateInputs const& private_inputs, - size_t const& num_private_call_public_inputs, - size_t const& num_private_kernel_public_inputs) -{ - CT::AggregationObject aggregation_object = Aggregator::aggregate( - &composer, private_inputs.private_call.vk, private_inputs.private_call.proof, num_private_call_public_inputs); - - Aggregator::aggregate(&composer, - private_inputs.previous_kernel.vk, - private_inputs.previous_kernel.proof, - num_private_kernel_public_inputs, - aggregation_object); - - return aggregation_object; -} - -void initialise_end_values(PrivateInputs const& private_inputs, PublicInputs& public_inputs) -{ - public_inputs.constants = private_inputs.previous_kernel.public_inputs.constants; - - // Ensure the arrays are the same as previously, before we start pushing more data onto them: - auto& end = public_inputs.end; - const auto& start = private_inputs.previous_kernel.public_inputs.end; - - end.output_commitments = start.output_commitments; - end.input_nullifiers = start.input_nullifiers; - - end.private_call_stack = start.private_call_stack; - end.public_call_stack = start.public_call_stack; - end.contract_deployment_call_stack = start.contract_deployment_call_stack; - end.l1_call_stack = start.l1_call_stack; - - end.optionally_revealed_data = start.optionally_revealed_data; -} - -void update_end_values(PrivateInputs const& private_inputs, PublicInputs& public_inputs) -{ - const auto private_call_public_inputs = private_inputs.private_call.call_stack_item.public_inputs; - - const auto& output_commitments = private_call_public_inputs.output_commitments; - const auto& input_nullifiers = private_call_public_inputs.input_nullifiers; - - const auto& is_static_call = private_inputs.private_call.call_stack_item.public_inputs.call_context.is_static_call; - - // No state changes are allowed for static calls: - is_static_call.must_imply(is_array_empty(output_commitments) == true); - is_static_call.must_imply(is_array_empty(input_nullifiers) == true); - - const auto& storage_contract_address = - private_inputs.private_call.call_stack_item.public_inputs.call_context.storage_contract_address; - - { // commitments & nullifiers - std::array siloed_output_commitments; - for (size_t i = 0; i < output_commitments.size(); ++i) { - siloed_output_commitments[i] = - CT::fr::conditional_assign(output_commitments[i] == 0, - 0, - CT::compress({ storage_contract_address.to_field(), output_commitments[i] }, - GeneratorIndex::OUTER_COMMITMENT)); - } - std::array siloed_input_nullifiers; - for (size_t i = 0; i < input_nullifiers.size(); ++i) { - siloed_input_nullifiers[i] = - CT::fr::conditional_assign(input_nullifiers[i] == 0, - 0, - CT::compress({ storage_contract_address.to_field(), input_nullifiers[i] }, - GeneratorIndex::OUTER_NULLIFIER)); - } - - push_array_to_array(siloed_output_commitments, public_inputs.end.output_commitments); - push_array_to_array(siloed_input_nullifiers, public_inputs.end.input_nullifiers); - } - - { - // TODO: we need to pass in UNPACKED stack data. I.e. the preimages of the call_stack_item hashes, so that data - // in the stack can be validated as being correct. (e.g. call_contexts of calls made by the private_call - // currently being validated). - - // So we'll need to ensure our test_apps return not only a PrivateCircuitPublicInputs object, but also an object - // containing a TONNE of preimage data. Stuff like: - // - Stack item preimages - // - Commitment and nullifier preimages - // - Hash paths and leaf indices - // - Any and all preimage data derived by the circuit or through oracle calls. - - // Update on this topic: I've created call_context_reconciliation_data, which allows the call_context to be - // efficiently unpacked from a call_stack_item_hash. We'll need some "functions calling functions" tests cases - // to see how best to move this data around neatly. - } - - const auto& portal_contract_address = private_inputs.private_call.portal_contract_address; - - { - const auto& partial_l1_call_stack = private_call_public_inputs.partial_l1_call_stack; - std::array l1_call_stack; - - for (size_t i = 0; i < partial_l1_call_stack.size(); ++i) { - l1_call_stack[i] = - CT::fr::conditional_assign(partial_l1_call_stack[i] == 0, - 0, - CT::compress({ portal_contract_address, partial_l1_call_stack[i] }, - GeneratorIndex::L1_CALL_STACK_ITEM)); - } - } -} - -void validate_private_call_hash(PrivateInputs const& private_inputs) -{ - const auto& start = private_inputs.previous_kernel.public_inputs.end; - const auto private_call_hash = array_pop(start.private_call_stack); - const auto calculated_private_call_hash = private_inputs.private_call.call_stack_item.hash(); - - private_call_hash.assert_equal(calculated_private_call_hash, "private_call_hash does not reconcile"); -}; - -void validate_inputs(PrivateInputs const& private_inputs) -{ - - const auto& next_call = private_inputs.private_call.call_stack_item; - - next_call.function_signature.is_private.assert_equal( - true, "Cannot execute a non-private function with the private kernel circuit"); - - const auto& start = private_inputs.previous_kernel.public_inputs.end; - - const CT::boolean is_base_case = start.private_call_count == 0; - const CT::boolean is_recursive_case = !is_base_case; - - CT::fr start_private_call_stack_length = array_length(start.private_call_stack); - CT::fr start_public_call_stack_length = array_length(start.public_call_stack); - CT::fr start_contract_deployment_call_stack_length = array_length(start.contract_deployment_call_stack); - CT::fr start_l1_call_stack_length = array_length(start.l1_call_stack); - - // Base Case - { - // Validate callstack lengths: - is_base_case.must_imply(start_private_call_stack_length == - 1 // TODO: might change to allow 2, so a fee can be paid. - && start_public_call_stack_length == 0 && - start_contract_deployment_call_stack_length == 0 && start_l1_call_stack_length == 0, - "Invalid callstacks for base case."); - - is_base_case.must_imply(next_call.public_inputs.call_context.is_delegate_call == false && - next_call.public_inputs.call_context.is_static_call == false, - "A user cannot make a delegatecall or staticcall"); - - // The below also prevents delegatecall/staticcall - is_base_case.must_imply(next_call.public_inputs.call_context.storage_contract_address == - next_call.contract_address, - "Storage contract address must be that of the called contract in the base case"); - } - - // Recursive Case - { - is_recursive_case.must_imply(private_inputs.previous_kernel.public_inputs.is_private == true, - "Cannot verify a non-private kernel snark in the private kernel circuit"); - - is_recursive_case.must_imply(next_call.function_signature.is_constructor == false, - "A constructor must be executed as the first tx in the recursion"); - - is_recursive_case.must_imply(start_private_call_stack_length != 0); - } +// #include "init.hpp" + +// #include +// #include + +// namespace aztec3::circuits::kernel::private_kernel { + +// using aztec3::circuits::abis::private_kernel::PrivateInputs; +// using aztec3::circuits::abis::private_kernel::PublicInputs; + +// /****************************************************************************************************************** +// * Calcs on circuit arrays. +// * TODO: move these array calcs to a common/circuit_array.hpp file. +// *****************************************************************************************************************/ + +// /** +// * Gets the number of contiguous nonzero values of an array. +// * Note: this assumes `0` always means 'not used', so be careful. If you actually want `0` to be counted, you'll need +// * something else. +// */ +// // TODO: move to own file of helper functions. +// template CT::fr array_length(std::array const& arr) +// { +// CT::fr length = 0; +// CT::boolean hit_zero = false; +// for (const auto& e : arr) { +// hit_zero |= e == 0; +// const CT::fr increment = !hit_zero; +// length += increment; +// } +// return length; +// }; + +// /** +// * Note: doesn't remove the last element from the array; only returns it! +// * Note: this assumes `0` always means 'not used', so be careful. If you actually want `0` to be counted, you'll need +// * something else. +// * If it returns `0`, the array is considered 'empty'. +// */ +// template CT::fr array_pop(std::array const& arr) +// { +// CT::fr popped_value; +// CT::boolean already_popped = false; +// for (size_t i = arr.size() - 1; i != (size_t)-1; i--) { +// CT::boolean is_non_zero = arr[i] != 0; +// popped_value = CT::fr::conditional_assign(!already_popped && is_non_zero, arr[i], popped_value); + +// already_popped |= is_non_zero; +// } +// return popped_value; +// }; + +// /** +// * Note: this assumes `0` always means 'not used', so be careful. If you actually want `0` to be counted, you'll need +// * something else. +// */ +// template CT::boolean is_array_empty(std::array const& arr) +// { +// CT::boolean nonzero_found = false; +// for (size_t i = arr.size() - 1; i != (size_t)-1; i--) { +// CT::boolean is_non_zero = arr[i] != 0; +// nonzero_found |= is_non_zero; +// } +// return !nonzero_found; +// }; + +// /** +// * Inserts the `source` array at the first zero-valued index of the `target` array. +// * Fails if the `source` array is too large vs the remaining capacity of the `target` array. +// */ +// template +// void push_array_to_array(std::array const& source, std::array& target) +// { +// CT::fr target_length = array_length(target); +// CT::fr source_length = array_length(source); + +// CT::fr target_capacity = CT::fr(target.size()); +// // TODO: using safe_fr for an underflow check, do: +// // remaining_target_capacity = target_capacity.subtract(target_length + source_length); + +// CT::fr t_i = 0; +// CT::fr next_index = target_length; +// for (const auto& s : source) { +// for (auto& t : target) { +// next_index.assert_not_equal(target_capacity, "Target array capacity exceeded"); +// CT::boolean at_index = t_i == next_index; +// t = CT::fr::conditional_assign(at_index, s, t); +// next_index = CT::fr::conditional_assign(at_index, next_index + 1, next_index); +// ++t_i; +// } +// } +// } + +// /*************************************************************************************************************** +// * End of array calcs. +// **************************************************************************************************************/ + +// // TODO: NEED TO RECONCILE THE `proof`'s public inputs (which are uint8's) with the +// // private_call.call_stack_item.public_inputs! +// CT::AggregationObject verify_proofs(Composer& composer, +// PrivateInputs const& private_inputs, +// size_t const& num_private_call_public_inputs, +// size_t const& num_private_kernel_public_inputs) +// { +// CT::AggregationObject aggregation_object = Aggregator::aggregate( +// &composer, private_inputs.private_call.vk, private_inputs.private_call.proof, +// num_private_call_public_inputs); + +// Aggregator::aggregate(&composer, +// private_inputs.previous_kernel.vk, +// private_inputs.previous_kernel.proof, +// num_private_kernel_public_inputs, +// aggregation_object); + +// return aggregation_object; +// } + +// void initialise_end_values(PrivateInputs const& private_inputs, PublicInputs& public_inputs) +// { +// public_inputs.constants = private_inputs.previous_kernel.public_inputs.constants; + +// // Ensure the arrays are the same as previously, before we start pushing more data onto them: +// auto& end = public_inputs.end; +// const auto& start = private_inputs.previous_kernel.public_inputs.end; + +// end.output_commitments = start.output_commitments; +// end.input_nullifiers = start.input_nullifiers; + +// end.private_call_stack = start.private_call_stack; +// end.public_call_stack = start.public_call_stack; +// end.contract_deployment_call_stack = start.contract_deployment_call_stack; +// end.l1_call_stack = start.l1_call_stack; + +// end.optionally_revealed_data = start.optionally_revealed_data; +// } + +// void update_end_values(PrivateInputs const& private_inputs, PublicInputs& public_inputs) +// { +// const auto private_call_public_inputs = private_inputs.private_call.call_stack_item.public_inputs; + +// const auto& output_commitments = private_call_public_inputs.output_commitments; +// const auto& input_nullifiers = private_call_public_inputs.input_nullifiers; + +// const auto& is_static_call = +// private_inputs.private_call.call_stack_item.public_inputs.call_context.is_static_call; + +// // No state changes are allowed for static calls: +// is_static_call.must_imply(is_array_empty(output_commitments) == true); +// is_static_call.must_imply(is_array_empty(input_nullifiers) == true); + +// const auto& storage_contract_address = +// private_inputs.private_call.call_stack_item.public_inputs.call_context.storage_contract_address; + +// { // commitments & nullifiers +// std::array siloed_output_commitments; +// for (size_t i = 0; i < output_commitments.size(); ++i) { +// siloed_output_commitments[i] = +// CT::fr::conditional_assign(output_commitments[i] == 0, +// 0, +// CT::compress({ storage_contract_address.to_field(), output_commitments[i] +// }, +// GeneratorIndex::OUTER_COMMITMENT)); +// } +// std::array siloed_input_nullifiers; +// for (size_t i = 0; i < input_nullifiers.size(); ++i) { +// siloed_input_nullifiers[i] = +// CT::fr::conditional_assign(input_nullifiers[i] == 0, +// 0, +// CT::compress({ storage_contract_address.to_field(), input_nullifiers[i] }, +// GeneratorIndex::OUTER_NULLIFIER)); +// } + +// push_array_to_array(siloed_output_commitments, public_inputs.end.output_commitments); +// push_array_to_array(siloed_input_nullifiers, public_inputs.end.input_nullifiers); +// } + +// { +// // TODO: we need to pass in UNPACKED stack data. I.e. the preimages of the call_stack_item hashes, so that +// data +// // in the stack can be validated as being correct. (e.g. call_contexts of calls made by the private_call +// // currently being validated). + +// // So we'll need to ensure our test_apps return not only a PrivateCircuitPublicInputs object, but also an +// object +// // containing a TONNE of preimage data. Stuff like: +// // - Stack item preimages +// // - Commitment and nullifier preimages +// // - Hash paths and leaf indices +// // - Any and all preimage data derived by the circuit or through oracle calls. + +// // Update on this topic: I've created call_context_reconciliation_data, which allows the call_context to be +// // efficiently unpacked from a call_stack_item_hash. We'll need some "functions calling functions" tests +// cases +// // to see how best to move this data around neatly. +// } + +// const auto& portal_contract_address = private_inputs.private_call.portal_contract_address; + +// { +// const auto& partial_l1_call_stack = private_call_public_inputs.partial_l1_call_stack; +// std::array l1_call_stack; + +// for (size_t i = 0; i < partial_l1_call_stack.size(); ++i) { +// l1_call_stack[i] = +// CT::fr::conditional_assign(partial_l1_call_stack[i] == 0, +// 0, +// CT::compress({ portal_contract_address, partial_l1_call_stack[i] }, +// GeneratorIndex::L1_CALL_STACK_ITEM)); +// } +// } +// } + +// void validate_private_call_hash(PrivateInputs const& private_inputs) +// { +// const auto& start = private_inputs.previous_kernel.public_inputs.end; +// const auto private_call_hash = array_pop(start.private_call_stack); +// const auto calculated_private_call_hash = private_inputs.private_call.call_stack_item.hash(); + +// private_call_hash.assert_equal(calculated_private_call_hash, "private_call_hash does not reconcile"); +// }; + +// void validate_inputs(PrivateInputs const& private_inputs) +// { + +// const auto& next_call = private_inputs.private_call.call_stack_item; + +// next_call.function_signature.is_private.assert_equal( +// true, "Cannot execute a non-private function with the private kernel circuit"); + +// const auto& start = private_inputs.previous_kernel.public_inputs.end; + +// const CT::boolean is_base_case = start.private_call_count == 0; +// const CT::boolean is_recursive_case = !is_base_case; + +// CT::fr start_private_call_stack_length = array_length(start.private_call_stack); +// CT::fr start_public_call_stack_length = array_length(start.public_call_stack); +// CT::fr start_contract_deployment_call_stack_length = array_length(start.contract_deployment_call_stack); +// CT::fr start_l1_call_stack_length = array_length(start.l1_call_stack); + +// // Base Case +// { +// // Validate callstack lengths: +// is_base_case.must_imply(start_private_call_stack_length == +// 1 // TODO: might change to allow 2, so a fee can be paid. +// && start_public_call_stack_length == 0 && +// start_contract_deployment_call_stack_length == 0 && start_l1_call_stack_length == +// 0, +// "Invalid callstacks for base case."); + +// is_base_case.must_imply(next_call.public_inputs.call_context.is_delegate_call == false && +// next_call.public_inputs.call_context.is_static_call == false, +// "A user cannot make a delegatecall or staticcall"); + +// // The below also prevents delegatecall/staticcall +// is_base_case.must_imply(next_call.public_inputs.call_context.storage_contract_address == +// next_call.contract_address, +// "Storage contract address must be that of the called contract in the base case"); +// } + +// // Recursive Case +// { +// is_recursive_case.must_imply(private_inputs.previous_kernel.public_inputs.is_private == true, +// "Cannot verify a non-private kernel snark in the private kernel circuit"); + +// is_recursive_case.must_imply(next_call.function_signature.is_constructor == false, +// "A constructor must be executed as the first tx in the recursion"); + +// is_recursive_case.must_imply(start_private_call_stack_length != 0); +// } - validate_private_call_hash(private_inputs); -} +// validate_private_call_hash(private_inputs); +// } -// TODO: decide what to return. -void private_kernel_circuit(Composer& composer, OracleWrapper& oracle, PrivateInputs const& _private_inputs) -{ - (void)oracle; // To avoid unused variable compiler errors whilst building. +// // TODO: decide what to return. +// void private_kernel_circuit(Composer& composer, OracleWrapper& oracle, PrivateInputs const& _private_inputs) +// { +// (void)oracle; // To avoid unused variable compiler errors whilst building. - const PrivateInputs private_inputs = _private_inputs.to_circuit_type(composer); - PublicInputs public_inputs; +// const PrivateInputs private_inputs = _private_inputs.to_circuit_type(composer); +// PublicInputs public_inputs; - // const auto& start = private_inputs.previous_kernel.public_inputs.end; +// // const auto& start = private_inputs.previous_kernel.public_inputs.end; - // const CT::boolean is_base_case = start.private_call_count == 0; - // const CT::boolean is_recursive_case = !is_base_case; +// // const CT::boolean is_base_case = start.private_call_count == 0; +// // const CT::boolean is_recursive_case = !is_base_case; - validate_inputs(private_inputs); +// validate_inputs(private_inputs); - initialise_end_values(private_inputs, public_inputs); +// initialise_end_values(private_inputs, public_inputs); - auto aggregation_object = verify_proofs(composer, - private_inputs, - _private_inputs.private_call.vk->num_public_inputs, - _private_inputs.previous_kernel.vk->num_public_inputs); +// auto aggregation_object = verify_proofs(composer, +// private_inputs, +// _private_inputs.private_call.vk->num_public_inputs, +// _private_inputs.previous_kernel.vk->num_public_inputs); - // TODO: kernel vk membership check! +// // TODO: kernel vk membership check! - public_inputs.end.aggregation_object = aggregation_object; +// public_inputs.end.aggregation_object = aggregation_object; - // public_inputs.set_public(); -}; +// // public_inputs.set_public(); +// }; -} // namespace aztec3::circuits::kernel::private_kernel \ No newline at end of file +// } // namespace aztec3::circuits::kernel::private_kernel \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.hpp b/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.hpp index 4b6f6b4b3b3..a0d12f2444a 100644 --- a/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.hpp +++ b/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.hpp @@ -1,16 +1,16 @@ -#pragma once +// #pragma once -#include "init.hpp" +// #include "init.hpp" -#include -// #include +// #include +// // #include -namespace aztec3::circuits::kernel::private_kernel { +// namespace aztec3::circuits::kernel::private_kernel { -using aztec3::circuits::abis::private_kernel::PrivateInputs; -// using abis::private_kernel::PublicInputs; +// using aztec3::circuits::abis::private_kernel::PrivateInputs; +// // using abis::private_kernel::PublicInputs; -// TODO: decide what to return. -void private_kernel_circuit(Composer& composer, OracleWrapper& oracle, PrivateInputs const& _private_inputs); +// // TODO: decide what to return. +// void private_kernel_circuit(Composer& composer, OracleWrapper& oracle, PrivateInputs const& _private_inputs); -} // namespace aztec3::circuits::kernel::private_kernel \ No newline at end of file +// } // namespace aztec3::circuits::kernel::private_kernel \ No newline at end of file From f536a804484b6ef8acfe169ec2479db74f44861c Mon Sep 17 00:00:00 2001 From: iAmMichaelConnor Date: Sun, 1 Jan 2023 20:40:51 +0000 Subject: [PATCH 019/166] wip: add more opcodes --- .../apps/function_execution_context.hpp | 1 + .../apps/notes/default_private_note/note.tpp | 16 +++-- .../default_private_note/note_preimage.hpp | 2 +- .../circuits/apps/notes/note_interface.hpp | 1 + .../aztec3/circuits/apps/opcodes/opcodes.hpp | 18 +++++- .../aztec3/circuits/apps/opcodes/opcodes.tpp | 59 ++++++++++++++++++- .../aztec3/circuits/apps/state_vars/.test.cpp | 13 ++-- .../apps/state_vars/utxo_state_var.hpp | 2 +- .../apps/state_vars/utxo_state_var.tpp | 11 ++-- 9 files changed, 99 insertions(+), 24 deletions(-) diff --git a/circuits/src/aztec3/circuits/apps/function_execution_context.hpp b/circuits/src/aztec3/circuits/apps/function_execution_context.hpp index b894b7d9211..26422730948 100644 --- a/circuits/src/aztec3/circuits/apps/function_execution_context.hpp +++ b/circuits/src/aztec3/circuits/apps/function_execution_context.hpp @@ -42,6 +42,7 @@ template class FunctionExecutionContext { std::vector> new_private_state_notes; std::vector new_commitments; + std::vector> new_nullifier_preimages; std::vector new_nullifiers; diff --git a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.tpp b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.tpp index 600ce22b150..2bdcda20fed 100644 --- a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.tpp +++ b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.tpp @@ -2,6 +2,7 @@ #include "nullifier_preimage.hpp" #include "../../oracle_wrapper.hpp" +#include "../../opcodes/opcodes.hpp" #include @@ -17,8 +18,12 @@ namespace aztec3::circuits::apps::notes { namespace { +using aztec3::circuits::apps::opcodes::Opcodes; + using aztec3::GeneratorIndex; + using crypto::pedersen::generator_index_t; + using plonk::stdlib::witness_t; using plonk::stdlib::types::CircuitTypes; using plonk::stdlib::types::NativeTypes; @@ -26,13 +31,12 @@ using plonk::stdlib::types::NativeTypes; template void DefaultPrivateNote::remove() { - auto [nullifier, nullifier_preimage] = compute_nullifier(); - - // auto& exec_ctx = utxo_state_var->exec_ctx; + // auto [nullifier, nullifier_preimage] = compute_nullifier(); - // TODO: implement this function! - (void)nullifier; - (void)nullifier_preimage; + // // TODO: implement this function! + // (void)nullifier; + // (void)nullifier_preimage; + Opcodes::UTXO_NULL(utxo_state_var, *this); } template bool DefaultPrivateNote::check_if_partial() const diff --git a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note_preimage.hpp b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note_preimage.hpp index 122ea448840..622860e44f9 100644 --- a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note_preimage.hpp +++ b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note_preimage.hpp @@ -29,7 +29,7 @@ template struct DefaultPrivateNotePreimage { std::optional salt; std::optional nonce; - boolean is_real; + boolean is_real = true; bool operator==(DefaultPrivateNotePreimage const&) const = default; diff --git a/circuits/src/aztec3/circuits/apps/notes/note_interface.hpp b/circuits/src/aztec3/circuits/apps/notes/note_interface.hpp index c48c7042e84..d100d057d04 100644 --- a/circuits/src/aztec3/circuits/apps/notes/note_interface.hpp +++ b/circuits/src/aztec3/circuits/apps/notes/note_interface.hpp @@ -7,6 +7,7 @@ namespace aztec3::circuits::apps::notes { +// TODO: remove this `using` declaration? using aztec3::circuits::apps::state_vars::UTXOStateVar; using plonk::stdlib::types::CircuitTypes; diff --git a/circuits/src/aztec3/circuits/apps/opcodes/opcodes.hpp b/circuits/src/aztec3/circuits/apps/opcodes/opcodes.hpp index b41b54624a6..14e13819504 100644 --- a/circuits/src/aztec3/circuits/apps/opcodes/opcodes.hpp +++ b/circuits/src/aztec3/circuits/apps/opcodes/opcodes.hpp @@ -20,10 +20,26 @@ template class Opcodes { typedef NativeTypes NT; /** - * @brief Load a singleton UTXOSLoadDatum from the Private Client's DB. + * @brief + * - Load a singleton UTXOSLoadDatum from the Private Client's DB + * - Generate constraints to prove its existence in the tree + * - Validate the data + * - Push new note data to the exec_ctx. */ template static Note UTXO_SLOAD(UTXOStateVar* utxo_state_var, typename Note::NotePreimage const& advice); + + /** + * @brief Compute and push a new nullifier to the public inputs of this exec_ctx. + */ + template static void UTXO_NULL(UTXOStateVar* utxo_state_var, Note& note); + + /** + * @brief Compute and push a new comitment to the public inputs of this exec_ctx. + */ + template + static void UTXO_SSTORE(UTXOStateVar* utxo_state_var, + typename Note::NotePreimage new_note_preimage); }; } // namespace aztec3::circuits::apps::opcodes diff --git a/circuits/src/aztec3/circuits/apps/opcodes/opcodes.tpp b/circuits/src/aztec3/circuits/apps/opcodes/opcodes.tpp index 582d67a1544..99fb47b6c4c 100644 --- a/circuits/src/aztec3/circuits/apps/opcodes/opcodes.tpp +++ b/circuits/src/aztec3/circuits/apps/opcodes/opcodes.tpp @@ -26,19 +26,72 @@ Note Opcodes::UTXO_SLOAD(UTXOStateVar* utxo_state_var, typename CT::grumpkin_point& storage_slot_point = utxo_state_var->storage_slot_point; + // Retrieve UTXO witness datum from the DB: UTXOSLoadDatum utxo_datum = oracle.template get_utxo_sload_datum(storage_slot_point, advice); Note new_note{ utxo_state_var, utxo_datum.preimage }; - oracle.get_contract_address().assert_equal(utxo_datum.contract_address, "UTXO_SLOAD: bad contract address"); - new_note.get_commitment().assert_equal(utxo_datum.commitment, "UTXO_SLOAD: bad commitment"); + oracle.get_contract_address().assert_equal(utxo_datum.contract_address, "UTXO_SLOAD: bad contract address"); + // TODO within this function: - // - Merkle Membership Check using utxo_datum.{sibling_path, leaf_index, old_private_data_tree_root} + // - constrain any of the `advice` fields which aren't std::nullopt (call upon a method in the note itself to + // `constrain_from_advice()`). + // - Merkle Membership Check using the contract_address, utxo_datum.{sibling_path, leaf_index, + // old_private_data_tree_root} return new_note; }; +template +template +void Opcodes::UTXO_NULL(UTXOStateVar* utxo_state_var, Note& note) +{ + auto [nullifier, nullifier_preimage] = note.compute_nullifier(); + + auto exec_ctx = utxo_state_var->exec_ctx; + + (void)exec_ctx; // TODO: finish function. + (void)nullifier; + (void)nullifier_preimage; + + // TODO: + // - Push the nullifier data to the exec_ctx +}; + +template +template +void Opcodes::UTXO_SSTORE(UTXOStateVar* utxo_state_var, + typename Note::NotePreimage new_note_preimage) +{ + + (void)utxo_state_var; + (void)new_note_preimage; + + // TODO: a salt (randomness for hiding) might not be needed for some custom Note types. Leave this to the + // `compute_commitment()` function of the Note instead (which will be called at FINALISATION of the notes, once + // enough nonces (nullifiers) are available). + + // auto& oracle = utxo_state_var->exec_ctx->oracle; + + // CT::fr salt = oracle.get_random_element(); + // new_note_preimage.salt = salt; + + // TODO within this function: + // - Push the commitment data to the exec_ctx, and maybe to the public inputs of the exec_ctx (although we might + // need to complete the commitments with a nonce using a UTXO_FINALISE() opcode!) + + // Note new_note{ utxo_state_var, new_note_preimage }; + // TODO: the code rightly complains when we try to commit, because we haven't chosen a nonce yet! Hence why we might + // need to defer committing until a FINALISE opcode at the end. + // auto [new_note_commitment, _] = new_note.compute_commitment(); + + // auto exec_ctx = utxo_state_var->exec_ctx; + + // (void)exec_ctx; // TODO: finish function. + // (void)new_note_commitment; +}; + } // namespace aztec3::circuits::apps::opcodes diff --git a/circuits/src/aztec3/circuits/apps/state_vars/.test.cpp b/circuits/src/aztec3/circuits/apps/state_vars/.test.cpp index 4eaa037dcc0..9c20de0bbd1 100644 --- a/circuits/src/aztec3/circuits/apps/state_vars/.test.cpp +++ b/circuits/src/aztec3/circuits/apps/state_vars/.test.cpp @@ -154,8 +154,6 @@ TEST_F(state_var_tests, utxo_of_default_private_note_fr) OracleWrapper oracle = OracleWrapper(composer, native_oracle); FunctionExecutionContext exec_ctx(composer, oracle); - using Note = DefaultPrivateNote; - // bool sort(NT::uint256 i, NT::uint256 j) // { // return (i < j); @@ -168,23 +166,26 @@ TEST_F(state_var_tests, utxo_of_default_private_note_fr) // FUNCTION: + using Note = DefaultPrivateNote; + UTXO my_utxo(&exec_ctx, "my_utxo"); const auto& msg_sender = oracle.get_msg_sender(); Note old_note = my_utxo.get({ .owner = msg_sender }); - info("old_note.get_preimage(): ", old_note.get_preimage()); - old_note.remove(); CT::fr old_value = *(old_note.get_preimage().value); CT::fr new_value = old_value + 5; - info("new_value: ", new_value); + my_utxo.insert({ .value = new_value, // + .owner = msg_sender, + .creator_address = msg_sender, + .memo = 1234 }); - // my_utxo.insert({ .value = new_value, .owner = msg_sender }); + // TODO: a UTXO_FINALISE() opcode? } } // namespace aztec3::circuits::apps::state_vars \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp b/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp index e184b189620..9d863101cef 100644 --- a/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp +++ b/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp @@ -44,7 +44,7 @@ template class UTXOStateVar : public StateVar */ Note get(NotePreimage const& advice); - // void insert(NotePreimage const& new_value); + void insert(NotePreimage new_note_preimage); }; } // namespace aztec3::circuits::apps::state_vars diff --git a/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.tpp b/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.tpp index 19a5908bca7..d6c05fe9d09 100644 --- a/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.tpp +++ b/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.tpp @@ -15,11 +15,10 @@ Note UTXOStateVar::get(typename Note::NotePreimage const& advice return Opcodes::template UTXO_SLOAD(this, advice); }; -// void insert(NotePreimage new_value); - -// template inline std::ostream& operator<<(std::ostream& os, UTXOStateVar const& v) -// { -// return os << v.value; -// } +template +void UTXOStateVar::insert(typename Note::NotePreimage new_note_preimage) +{ + return Opcodes::UTXO_SSTORE(this, new_note_preimage); +}; } // namespace aztec3::circuits::apps::state_vars From 3e52605d794dc40b1e471cbc583bed0633794385 Mon Sep 17 00:00:00 2001 From: iAmMichaelConnor Date: Tue, 3 Jan 2023 19:55:51 +0000 Subject: [PATCH 020/166] utxo finalise, and restricting permission to exec_ctx members to opcodes as friend class --- .../circuits/apps/{state_vars => }/.test.cpp | 36 ++- .../apps/function_execution_context.hpp | 155 +++++++++--- .../apps/notes/default_private_note/note.hpp | 66 +++--- .../apps/notes/default_private_note/note.tpp | 221 +++++++++++------- .../default_private_note/note_preimage.hpp | 13 +- .../nullifier_preimage.hpp | 10 +- .../circuits/apps/notes/note_interface.hpp | 17 +- .../aztec3/circuits/apps/opcodes/opcodes.hpp | 8 +- .../aztec3/circuits/apps/opcodes/opcodes.tpp | 36 +-- .../circuits/apps/private_state_note.hpp | 2 +- .../circuits/apps/private_state_note.tpp | 24 +- .../aztec3/circuits/apps/state_vars/index.hpp | 3 - .../apps/state_vars/mapping_state_var.hpp | 9 +- .../apps/state_vars/mapping_state_var.tpp | 23 ++ .../apps/state_vars/state_var_base.hpp | 18 +- .../apps/state_vars/state_var_base.tpp | 20 +- .../apps/state_vars/utxo_state_var.hpp | 11 +- .../apps/state_vars/utxo_state_var.tpp | 8 +- circuits/src/aztec3/constants.hpp | 2 +- circuits/src/aztec3/oracle/oracle.hpp | 2 +- 20 files changed, 452 insertions(+), 232 deletions(-) rename circuits/src/aztec3/circuits/apps/{state_vars => }/.test.cpp (82%) delete mode 100644 circuits/src/aztec3/circuits/apps/state_vars/index.hpp diff --git a/circuits/src/aztec3/circuits/apps/state_vars/.test.cpp b/circuits/src/aztec3/circuits/apps/.test.cpp similarity index 82% rename from circuits/src/aztec3/circuits/apps/state_vars/.test.cpp rename to circuits/src/aztec3/circuits/apps/.test.cpp index 9c20de0bbd1..3727b2c9b3c 100644 --- a/circuits/src/aztec3/circuits/apps/state_vars/.test.cpp +++ b/circuits/src/aztec3/circuits/apps/.test.cpp @@ -6,16 +6,20 @@ #include #include -#include "index.hpp" // #include "utxo_state_var.hpp" -#include "../notes/default_private_note/note.hpp" -#include "../notes/default_private_note/note_preimage.hpp" +#include "contract.hpp" +#include "function_execution_context.hpp" +#include "oracle_wrapper.hpp" +#include "utxo_datum.hpp" -#include "../contract.hpp" -#include "../function_execution_context.hpp" -#include "../oracle_wrapper.hpp" -#include "../utxo_datum.hpp" +#include "notes/note_interface.hpp" +#include "notes/default_private_note/note.hpp" +#include "notes/default_private_note/note_preimage.hpp" + +#include "state_vars/field_state_var.hpp" +#include "state_vars/mapping_state_var.hpp" +#include "state_vars/utxo_state_var.hpp" #include @@ -33,6 +37,9 @@ using CT = plonk::stdlib::types::CircuitTypes; using NT = plonk::stdlib::types::NativeTypes; using plonk::stdlib::types::to_ct; +// exec_ctx +// using aztec3::circuits::apps::FunctionExecutionContext; + // Oracle using DB = aztec3::oracle::FakeDB; using aztec3::oracle::NativeOracle; @@ -47,6 +54,7 @@ using aztec3::circuits::apps::state_vars::MappingStateVar; using aztec3::circuits::apps::state_vars::UTXOStateVar; using aztec3::circuits::apps::notes::DefaultPrivateNote; +using aztec3::circuits::apps::notes::NoteInterface; // using aztec3::circuits::apps::notes::DefaultPrivateNotePreimage; //******** @@ -66,7 +74,7 @@ using Field = FieldStateVar; } // namespace -namespace aztec3::circuits::apps::state_vars { +namespace aztec3::circuits::apps { class state_var_tests : public ::testing::Test { protected: @@ -185,7 +193,17 @@ TEST_F(state_var_tests, utxo_of_default_private_note_fr) .creator_address = msg_sender, .memo = 1234 }); + // Here, we test that the shared_ptr of a note, stored within the exec_ctx, works. TODO: put this in its own little + // test, instead of this ever-growing beast test. + auto new_note_pointers = exec_ctx.get_new_notes(); + std::shared_ptr debug_note = std::dynamic_pointer_cast(new_note_pointers[0]); + info("new_note_pointers: ", new_note_pointers); + info("*(new_note_pointers[0]): ", debug_note->get_preimage()); + + auto new_nullifiers = exec_ctx.get_new_nullifiers(); + info("new_nullifiers: ", new_nullifiers); + // TODO: a UTXO_FINALISE() opcode? } -} // namespace aztec3::circuits::apps::state_vars \ No newline at end of file +} // namespace aztec3::circuits::apps \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/function_execution_context.hpp b/circuits/src/aztec3/circuits/apps/function_execution_context.hpp index 26422730948..6a69cec115d 100644 --- a/circuits/src/aztec3/circuits/apps/function_execution_context.hpp +++ b/circuits/src/aztec3/circuits/apps/function_execution_context.hpp @@ -1,9 +1,14 @@ #pragma once + #include "contract.hpp" #include "nullifier_preimage.hpp" #include "oracle_wrapper.hpp" #include "private_state_note.hpp" +#include "notes/note_interface.hpp" + +#include "opcodes/opcodes.hpp" + #include #include #include @@ -20,32 +25,42 @@ namespace aztec3::circuits::apps { +using aztec3::circuits::abis::FunctionSignature; +using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; + +using aztec3::circuits::apps::notes::NoteInterface; + +using aztec3::circuits::apps::opcodes::Opcodes; + using plonk::stdlib::witness_t; using plonk::stdlib::types::CircuitTypes; using NT = plonk::stdlib::types::NativeTypes; -using aztec3::circuits::abis::FunctionSignature; -using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; template class FunctionExecutionContext { typedef CircuitTypes CT; typedef typename CT::fr fr; + // We restrict only the opcodes to be able to push to the private members of the exec_ctx. + // This will just help us build better separation of concerns. + friend class Opcodes; + public: Composer& composer; OracleWrapperInterface& oracle; Contract* contract = nullptr; - // std::shared_ptr> contract = nullptr; + private: OptionalPrivateCircuitPublicInputs private_circuit_public_inputs; - // UnpackedData unpacked_data; - std::vector> new_private_state_notes; + std::vector>> new_notes; std::vector new_commitments; - std::vector> new_nullifier_preimages; + // Nullifier preimages can be got from the corresponding Note that they nullify. + std::vector*> nullified_notes; std::vector new_nullifiers; + public: FunctionExecutionContext(Composer& composer, OracleWrapperInterface& oracle) : composer(composer) , oracle(oracle) @@ -62,43 +77,107 @@ template class FunctionExecutionContext { this->contract = contract; } - void push_new_note(PrivateStateNote const private_state_note) - { - new_private_state_notes.push_back(private_state_note); - } - - void push_new_nullifier_data(fr nullifier, NullifierPreimage nullifier_preimage) + // TODO: consider making this a debug-only method. + // Not a reference, because we won't want to allow unsafe access. Hmmm, except it's a vector of pointers, so one can + // still modify the pointers... But at least the original vector isn't being pushed-to or deleted-from. + std::vector>> get_new_notes() { return new_notes; } + std::vector get_new_nullifiers() { return new_nullifiers; } + + void push_new_note(NoteInterface* const note_ptr) { new_notes.push_back(note_ptr); } + + void push_newly_nullified_note(NoteInterface* note_ptr) { nullified_notes.push_back(note_ptr); } + + /** + * @brief This is an important optimisation, to save on the number of emitted nullifiers. + * + * A nullifier is ideal to serve as a nonce for a new note commitment, because its uniqueness is enforced by the + * Rollup circuit. But we won't know how many non-dummy nullifiers we have at our disposal (to inject into + * commitments) until the end of the function. + * + * Or to put it another way, at the time we want to create a new commitment (during a function's execution), we + * would need a nonce. We could certainly query the `exec_ctx` for any nullifiers which have already been created + * earlier in this function's execution, and we could use one of those. But there might not-yet have been any + * nullifiers created within the function. Now, at that point, we _could_ generate a dummy nullifier and use that as + * a nonce. But that uses up a precious slot in the circuit's nullifiers array (part of the circuit's public inputs + * abi). And it might be the case that later in the function, a load of non-dummy nullifiers get created. So as an + * optimisation, it would be better if we could use _those_ nullifiers, so as to minimise dummy values in the + * circuit's public inputs. + * + * And so, we provide the option here of deferring the injection of nonces into note_preimages (and hence deferring + * the computation of each new note commitment) until the very end of the function's execution, when we know how + * many non-dummy nullifiers we have to play with. If we find this circuit is creating more new commitments than new + * nullifiers, we can generate some dummy nullifiers at this stage to make up the difference. + * + * Note: Using a nullifier as a nonce is a very common and widely-applicable pattern. So much so that it feels + * acceptable to have this function execute regardless of the underlying Note types being used by the circuit. + * + * Note: It's up to the implementer of a custom Note type to decide how a nonce is derived, via the `set_nonce() + * override` method dictated by the NoteInterface. + * + * Note: Not all custom Note types will need a nonce of this kind in their NotePreimage. But they can simply + * implement an empty body in the `set_nonce() override`. + */ + void finalise_utxos() { - new_nullifiers.push_back(nullifier); - new_nullifier_preimages.push_back(nullifier_preimage); - } - - void finalise_private_state_changes() - { - if (new_private_state_notes.size() > new_nullifier_preimages.size()) { - // We've created more commitments than nullifiers so far. But we want to inject an input_nullifier into each - // new commitment. So, let's create more dummy nullifiers. - const auto& msg_sender_private_key = oracle.get_msg_sender_private_key(); - for (size_t i = new_nullifier_preimages.size(); i < new_private_state_notes.size(); ++i) { - auto dummy_commitment = oracle.generate_random_element(); - new_nullifier_preimages.push_back(NullifierPreimage{ - dummy_commitment, - msg_sender_private_key, - false, - }); - new_nullifiers.push_back( - PrivateStateNote::compute_dummy_nullifier(dummy_commitment, msg_sender_private_key)); - } - } - for (size_t i = 0; i < new_private_state_notes.size(); ++i) { - new_private_state_notes[i].preimage.nonce = new_nullifiers[i]; - new_commitments.push_back(new_private_state_notes[i].compute_commitment()); - } + // if (new_notes.size() > nullified_notes.size()) { + // // We've created more commitments than nullifiers so far. But we want to inject an input_nullifier into + // each + // // new commitment. So, let's create more dummy nullifiers. + // const auto& msg_sender_private_key = oracle.get_msg_sender_private_key(); + // for (size_t i = new_nullifier_preimages.size(); i < new_private_state_notes.size(); ++i) { + // auto dummy_commitment = oracle.generate_random_element(); + // new_nullifier_preimages.push_back(NullifierPreimage{ + // dummy_commitment, + // msg_sender_private_key, + // false, + // }); + // new_nullifiers.push_back( + // PrivateStateNote::compute_dummy_nullifier(dummy_commitment, msg_sender_private_key)); + // } + // } + + // Copy some vectors, as we can't control whether they'll be pushed-to further, when we call Note methods. + // auto new_commitments_copy = new_commitments; + // auto new_nullifiers_copy = new_nullifiers; + // auto new_notes_copy = new_notes; + + // size_t used_nullifiers_count = 0; + // bool next_nullifier_available = false; + // bool next_nullifier_used = false; + // std::optional next_nullifier; + // std::vector new_nonces; + + // for (size_t i = 0; i < new_notes.size(); ++i) { + // const& note = new_notes_copy[i]; + + // next_nullifier_available = nullified_notes.size() > used_nullifiers_count; + + // if (next_nullifier_available) { + // next_nullifier = nullified_notes[used_nullifiers_count++].nullifier; + // next_nullifier_used = new_notes[i].set_nonce(next_nullifier); + // } + + // if (!next_nullifier_used) { + // next_nullifier = nullified_notes.size() > used_nullifiers_count + // ? nullified_notes[used_nullifiers_count++].nullifier + // : std::nullopt; // Indicates that all the existing non-dummy nullifiers have + // // all been used-up. + // } else { + // std::optional new_nonce = new_notes[i].generate_nonce(); + // if (new_nonce) { + // new_nonces.push_back(*new_nonce); + // } + // } + + // new_commitments.push_back(new_notes[i].get_commitment()); + + // // Push new_nonces to the end of new_nullifiers: + // std::copy(new_nonces.begin(), new_nonces.end(), std::back_inserter(new_nullifiers)); } void finalise() { - finalise_private_state_changes(); + finalise_utxos(); private_circuit_public_inputs.set_commitments(new_commitments); private_circuit_public_inputs.set_nullifiers(new_nullifiers); private_circuit_public_inputs.set_public(composer); diff --git a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.hpp b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.hpp index b72851b6042..c96d3110a03 100644 --- a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.hpp +++ b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.hpp @@ -5,26 +5,27 @@ #include "note_preimage.hpp" #include "nullifier_preimage.hpp" -#include "../../state_vars/utxo_state_var.hpp" +// #include "../../state_vars/utxo_state_var.hpp" #include #include +// Forward-declare from this namespace in particular: +namespace aztec3::circuits::apps::state_vars { +template class UTXOStateVar; +} // namespace aztec3::circuits::apps::state_vars + namespace aztec3::circuits::apps::notes { -using aztec3::circuits::apps::state_vars::UTXOStateVar; +using aztec3::circuits::apps::state_vars::UTXOStateVar; // Don't #include it! using plonk::stdlib::types::CircuitTypes; using plonk::stdlib::types::NativeTypes; -// template class UTXOStateVar; // template struct DefaultPrivateNotePreimage; // template struct DefaultPrivateNoteNullifierPreimage; -template -class DefaultPrivateNote : public NoteInterface, ValueType>, - DefaultPrivateNoteNullifierPreimage>> { +template class DefaultPrivateNote : public NoteInterface { public: typedef CircuitTypes CT; typedef typename CT::fr fr; @@ -35,12 +36,26 @@ class DefaultPrivateNote : public NoteInterface, ValueType>; using NullifierPreimage = DefaultPrivateNoteNullifierPreimage>; + public: UTXOStateVar* utxo_state_var; + private: + std::optional commitment; + std::optional nullifier; + std::optional partial_commitment; + + // bool is_partial = false; + + NotePreimage note_preimage; + std::optional nullifier_preimage; + + public: DefaultPrivateNote(UTXOStateVar* utxo_state_var, NotePreimage note_preimage) : utxo_state_var(utxo_state_var) , note_preimage(note_preimage){}; + ~DefaultPrivateNote() {} + // bool operator==(PrivateStateNote const&) const = default; // METHODS @@ -54,15 +69,15 @@ class DefaultPrivateNote : public NoteInterface compute_commitment() override; + fr compute_commitment() override; - std::pair compute_nullifier() override; + fr compute_nullifier() override; - // std::pair> compute_partial_commitment() override; + // void finalise(std::optional nonce) override; + + auto& get_oracle(); + + grumpkin_point compute_partial_commitment(); + + fr compute_dummy_nullifier(); static fr compute_nullifier(fr const& commitment, fr const& owner_private_key, - boolean const& is_real_commitment = true); - - // static fr compute_dummy_nullifier(fr const& dummy_commitment, fr const& owner_private_key); + boolean const& is_dummy_commitment = false); NotePreimage& get_preimage() { return note_preimage; }; private: - bool check_if_partial() const; + bool is_partial_preimage() const; + bool is_partial_storage_slot() const; + bool is_partial() const; // bool check_if_partial() const = 0; - - std::optional commitment; - std::optional nullifier; - std::optional partial_commitment; - - bool is_partial = false; - - NotePreimage note_preimage; - std::optional nullifier_preimage; }; } // namespace aztec3::circuits::apps::notes diff --git a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.tpp b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.tpp index 2bdcda20fed..f282f0accf2 100644 --- a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.tpp +++ b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.tpp @@ -3,6 +3,7 @@ #include "../../oracle_wrapper.hpp" #include "../../opcodes/opcodes.hpp" +#include "../../state_vars/utxo_state_var.hpp" #include @@ -15,10 +16,12 @@ #include #include -namespace aztec3::circuits::apps::notes { - namespace { using aztec3::circuits::apps::opcodes::Opcodes; +using aztec3::circuits::apps::state_vars::UTXOStateVar; +} // namespace + +namespace aztec3::circuits::apps::notes { using aztec3::GeneratorIndex; @@ -27,37 +30,39 @@ using crypto::pedersen::generator_index_t; using plonk::stdlib::witness_t; using plonk::stdlib::types::CircuitTypes; using plonk::stdlib::types::NativeTypes; -} // namespace template void DefaultPrivateNote::remove() { - // auto [nullifier, nullifier_preimage] = compute_nullifier(); - - // // TODO: implement this function! - // (void)nullifier; - // (void)nullifier_preimage; Opcodes::UTXO_NULL(utxo_state_var, *this); } -template bool DefaultPrivateNote::check_if_partial() const +template auto& DefaultPrivateNote::get_oracle() { - const auto& [value, owner, creator_address, memo, salt, nonce, _] = this->note_preimage; + return utxo_state_var->exec_ctx->oracle; +} - if (!value || !owner || !creator_address || !memo || !salt || !nonce) { - return true; - } - if (utxo_state_var->is_partial_slot) { - return true; - } - return false; +template bool DefaultPrivateNote::is_partial_preimage() const +{ + const auto& [value, owner, creator_address, memo, salt, nonce, _] = note_preimage; + + return (!value || !owner || !creator_address || !memo || !salt || !nonce); +} + +template bool DefaultPrivateNote::is_partial_storage_slot() const +{ + return utxo_state_var->is_partial_slot; +} + +template bool DefaultPrivateNote::is_partial() const +{ + return is_partial_preimage() || is_partial_storage_slot(); } template -std::pair::fr, DefaultPrivateNotePreimage, V>> -DefaultPrivateNote::compute_commitment() +typename CircuitTypes::fr DefaultPrivateNote::compute_commitment() { if (commitment.has_value()) { - return std::make_pair(*commitment, this->note_preimage); + return *commitment; } grumpkin_point storage_slot_point = utxo_state_var->storage_slot_point; @@ -81,9 +86,13 @@ DefaultPrivateNote::compute_commitment() return std::make_pair(*input, generator_index_t({ GeneratorIndex::COMMITMENT, hash_sub_index })); }; - const auto& [value, owner, creator_address, memo, salt, nonce, is_real] = this->note_preimage; + if (!note_preimage.salt) { + note_preimage.salt = get_oracle().generate_random_element(); + } + + const auto& [value, owner, creator_address, memo, salt, nonce, is_dummy] = note_preimage; - const auto commitment_point = + const grumpkin_point commitment_point = storage_slot_point + CT::commit( { gen_pair_fr(value, PrivateStateNoteGeneratorIndex::VALUE), @@ -92,75 +101,73 @@ DefaultPrivateNote::compute_commitment() gen_pair_fr(memo, PrivateStateNoteGeneratorIndex::MEMO), gen_pair_fr(salt, PrivateStateNoteGeneratorIndex::SALT), gen_pair_fr(nonce, PrivateStateNoteGeneratorIndex::NONCE), - std::make_pair(is_real, - generator_index_t({ GeneratorIndex::COMMITMENT, PrivateStateNoteGeneratorIndex::IS_REAL })) + std::make_pair( + is_dummy, generator_index_t({ GeneratorIndex::COMMITMENT, PrivateStateNoteGeneratorIndex::IS_DUMMY })) }); commitment = commitment_point.x; - return std::make_pair(*commitment, note_preimage); + return *commitment; } -// template -// typename CircuitTypes::grumpkin_point DefaultPrivateNote::compute_partial_commitment() const -// { -// if (partial_commitment.has_value()) { -// info( -// "WARNING: you've already computed a partial commitment for this note. Now, you might have since changed " -// "the preimage and you want to update the partial commitment, and that's ok, so we won't throw an error " -// "here. But if that's not the case, you should call get_partial_commitment() instead, to save -// constraints."); -// } +template +typename CircuitTypes::grumpkin_point DefaultPrivateNote::compute_partial_commitment() +{ + if (partial_commitment.has_value()) { + info( + "WARNING: you've already computed a partial commitment for this note. Now, you might have since changed " + "the preimage and you want to update the partial commitment, and that's ok, so we won't throw an error " + "here. But if that's not the case, you should call get_partial_commitment() instead, to save constraints."); + } -// grumpkin_point storage_slot_point = private_state_var.storage_slot_point; - -// std::vector inputs; -// std::vector generators; - -// auto gen_pair_address = [&](std::optional
const& input, size_t const hash_sub_index) { -// return input ? std::make_pair((*input).to_field(), -// generator_index_t({ GeneratorIndex::COMMITMENT, hash_sub_index })) -// : std::make_pair(fr(1), -// generator_index_t({ GeneratorIndex::COMMITMENT_PLACEHOLDER, hash_sub_index })); -// }; - -// auto gen_pair_fr = [&](std::optional const& input, size_t const hash_sub_index) { -// return input ? std::make_pair(*input, generator_index_t({ GeneratorIndex::COMMITMENT, hash_sub_index })) -// : std::make_pair(fr(1), -// generator_index_t({ GeneratorIndex::COMMITMENT_PLACEHOLDER, hash_sub_index })); -// }; - -// const auto& [start_slot, -// mapping_key_values_by_key_name, -// value, -// owner, -// creator_address, -// salt, -// nonce, -// memo, -// is_real] = preimage; - -// return storage_slot_point + -// CT::commit({ gen_pair_fr(value, PrivateStateNoteGeneratorIndex::VALUE), -// gen_pair_address(owner, PrivateStateNoteGeneratorIndex::OWNER), -// gen_pair_address(creator_address, PrivateStateNoteGeneratorIndex::CREATOR), -// gen_pair_fr(salt, PrivateStateNoteGeneratorIndex::SALT), -// gen_pair_fr(nonce, PrivateStateNoteGeneratorIndex::NONCE), -// gen_pair_fr(memo, PrivateStateNoteGeneratorIndex::MEMO), -// std::make_pair( -// is_real, -// generator_index_t({ GeneratorIndex::COMMITMENT, PrivateStateNoteGeneratorIndex::IS_REAL -// })) - -// }); -// } + grumpkin_point storage_slot_point = utxo_state_var->storage_slot_point; + + std::vector inputs; + std::vector generators; + + auto gen_pair_address = [&](std::optional
const& input, size_t const hash_sub_index) { + return input ? std::make_pair((*input).to_field(), + generator_index_t({ GeneratorIndex::COMMITMENT, hash_sub_index })) + : std::make_pair(fr(1), + generator_index_t({ GeneratorIndex::COMMITMENT_PLACEHOLDER, hash_sub_index })); + }; + + auto gen_pair_fr = [&](std::optional const& input, size_t const hash_sub_index) { + return input ? std::make_pair(*input, generator_index_t({ GeneratorIndex::COMMITMENT, hash_sub_index })) + : std::make_pair(fr(1), + generator_index_t({ GeneratorIndex::COMMITMENT_PLACEHOLDER, hash_sub_index })); + }; + + if (!note_preimage.salt) { + note_preimage.salt = get_oracle().generate_random_element(); + } + + const auto& [value, owner, creator_address, memo, salt, nonce, is_dummy] = note_preimage; + + const grumpkin_point partial_commitment_point = + storage_slot_point + + CT::commit( + { gen_pair_fr(value, PrivateStateNoteGeneratorIndex::VALUE), + gen_pair_address(owner, PrivateStateNoteGeneratorIndex::OWNER), + gen_pair_address(creator_address, PrivateStateNoteGeneratorIndex::CREATOR), + gen_pair_fr(salt, PrivateStateNoteGeneratorIndex::SALT), + gen_pair_fr(nonce, PrivateStateNoteGeneratorIndex::NONCE), + gen_pair_fr(memo, PrivateStateNoteGeneratorIndex::MEMO), + std::make_pair( + is_dummy, generator_index_t({ GeneratorIndex::COMMITMENT, PrivateStateNoteGeneratorIndex::IS_DUMMY })) + + }); + + partial_commitment = partial_commitment_point; + + return *partial_commitment; +} template -std::pair::fr, DefaultPrivateNoteNullifierPreimage>> -DefaultPrivateNote::compute_nullifier() +typename CircuitTypes::fr DefaultPrivateNote::compute_nullifier() { - if (is_partial) { + if (is_partial()) { throw_or_abort("Can't nullify a partial note."); } if (!commitment) { @@ -168,24 +175,35 @@ DefaultPrivateNote::compute_nullifier() "note to include the `commit_on_init` bool."); } if (nullifier && nullifier_preimage) { - return std::make_pair(*nullifier, *nullifier_preimage); + return *nullifier; } - fr& owner_private_key = this->utxo_state_var->exec_ctx->oracle.get_msg_sender_private_key(); + fr& owner_private_key = get_oracle().get_msg_sender_private_key(); nullifier = - DefaultPrivateNote::compute_nullifier(*commitment, owner_private_key, note_preimage.is_real); + DefaultPrivateNote::compute_nullifier(*commitment, owner_private_key, note_preimage.is_dummy); nullifier_preimage = { *commitment, owner_private_key, - note_preimage.is_real, + note_preimage.is_dummy, }; - return std::make_pair(*nullifier, *nullifier_preimage); + return *nullifier; +}; + +template +typename CircuitTypes::fr DefaultPrivateNote::compute_dummy_nullifier() +{ + const auto& oracle = get_oracle(); + const fr dummy_commitment = oracle.generate_random_element(); + const fr owner_private_key = oracle.get_msg_sender_private_key(); + const boolean is_dummy_commitment = true; + + return DefaultPrivateNote::compute_nullifier(dummy_commitment, owner_private_key, is_dummy_commitment); }; template typename CircuitTypes::fr DefaultPrivateNote::compute_nullifier( - fr const& commitment, fr const& owner_private_key, boolean const& is_real_commitment) + fr const& commitment, fr const& owner_private_key, boolean const& is_dummy_commitment) { /** * Hashing the private key in this way enables the following use case: @@ -200,7 +218,7 @@ typename CircuitTypes::fr DefaultPrivateNote::compute_nul commitment, hashed_private_key.x, hashed_private_key.y, - is_real_commitment, + is_dummy_commitment, }; // We compress the hash_inputs with Pedersen, because that's cheaper (constraint-wise) than compressing @@ -211,8 +229,8 @@ typename CircuitTypes::fr DefaultPrivateNote::compute_nul // compression. /** E.g. we can extract a representation of the hashed_pk: * Paraphrasing, if: - * nullifier = note_comm * G1 + hashed_pk * G2 + is_real_note * G3 - * Then an observer can derive hashed_pk * G2 = nullifier - note_comm * G1 - is_real_note * G3 + * nullifier = note_comm * G1 + hashed_pk * G2 + is_dummy_note * G3 + * Then an observer can derive hashed_pk * G2 = nullifier - note_comm * G1 - is_dummy_note * G3 * They can derive this for every tx, to link which txs are being sent by the same user. * Notably, at the point someone withdraws, the observer would be able to connect `hashed_pk * G2` with a * specific eth address. @@ -222,6 +240,31 @@ typename CircuitTypes::fr DefaultPrivateNote::compute_nul return fr(blake_result); }; +// template bool DefaultPrivateNote::needs_nonce() +// { +// return !note_preimage.nonce; +// } + +// template +// bool DefaultPrivateNote::set_nonce(typename CircuitTypes::fr nonce) +// { +// if (!note_preimage.nonce) { +// note_preimage.nonce = nonce; +// return true; // "We have used the nonce provided" +// } +// return false; // "We did not used the provided nonce. +// }; + +// template +// std::optional::fr> DefaultPrivateNote::generate_nonce() +// { +// if (!note_preimage.nonce) { +// note_preimage.nonce = compute_dummy_nullifier(); +// return std::make_optional; // "We are returning a new dummy nonce" +// } +// return std::nullopt; // "We are not returning a new dummy nonce" +// }; + // template // typename CircuitTypes::fr DefaultPrivateNote::compute_dummy_nullifier(fr const& dummy_commitment, // fr const& diff --git a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note_preimage.hpp b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note_preimage.hpp index 622860e44f9..6ee2810e003 100644 --- a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note_preimage.hpp +++ b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note_preimage.hpp @@ -29,7 +29,7 @@ template struct DefaultPrivateNotePreimage { std::optional salt; std::optional nonce; - boolean is_real = true; + boolean is_dummy = false; bool operator==(DefaultPrivateNotePreimage const&) const = default; @@ -63,7 +63,8 @@ template struct DefaultPrivateNotePreimage { // circuit types (for the return values) (in order to make the calling syntax cleaner) with the below `decltype` // deduction of the _circuit_ version of template type `V`. DefaultPrivateNotePreimage, typename decltype(circuit_value)::value_type> preimage = { - circuit_value, to_ct(owner), to_ct(creator_address), to_ct(memo), to_ct(salt), to_ct(nonce), to_ct(is_real), + circuit_value, to_ct(owner), to_ct(creator_address), to_ct(memo), + to_ct(salt), to_ct(nonce), to_ct(is_dummy), }; return preimage; @@ -93,7 +94,7 @@ template struct DefaultPrivateNotePreimage { (); DefaultPrivateNotePreimage preimage = { - native_value, to_nt(owner), to_nt(creator_address), to_nt(memo), to_nt(salt), to_nt(nonce), to_nt(is_real), + native_value, to_nt(owner), to_nt(creator_address), to_nt(memo), to_nt(salt), to_nt(nonce), to_nt(is_dummy), }; return preimage; @@ -110,7 +111,7 @@ template void read(uint8_t const*& it, DefaultPrivate read(it, preimage.memo); read(it, preimage.salt); read(it, preimage.nonce); - read(it, preimage.is_real); + read(it, preimage.is_dummy); }; template @@ -124,7 +125,7 @@ void write(std::vector& buf, DefaultPrivateNotePreimage const& write(buf, preimage.memo); write(buf, preimage.salt); write(buf, preimage.nonce); - write(buf, preimage.is_real); + write(buf, preimage.is_dummy); }; template @@ -136,7 +137,7 @@ std::ostream& operator<<(std::ostream& os, DefaultPrivateNotePreimage co << "memo: " << preimage.memo << "\n" << "salt: " << preimage.salt << "\n" << "nonce: " << preimage.nonce << "\n" - << "is_real: " << preimage.is_real << "\n"; + << "is_dummy: " << preimage.is_dummy << "\n"; } // template using MappingKeyValues = std::map>; diff --git a/circuits/src/aztec3/circuits/apps/notes/default_private_note/nullifier_preimage.hpp b/circuits/src/aztec3/circuits/apps/notes/default_private_note/nullifier_preimage.hpp index eee508234cb..f123eb472f5 100644 --- a/circuits/src/aztec3/circuits/apps/notes/default_private_note/nullifier_preimage.hpp +++ b/circuits/src/aztec3/circuits/apps/notes/default_private_note/nullifier_preimage.hpp @@ -18,7 +18,7 @@ template struct DefaultPrivateNoteNullifierPreimage { fr commitment; fr owner_private_key; - boolean is_real; + boolean is_dummy = false; bool operator==(DefaultPrivateNoteNullifierPreimage const&) const = default; @@ -33,7 +33,7 @@ template struct DefaultPrivateNoteNullifierPreimage { DefaultPrivateNoteNullifierPreimage> preimage = { to_ct(commitment), to_ct(owner_private_key), - to_ct(is_real), + to_ct(is_dummy), }; return preimage; @@ -46,7 +46,7 @@ template void read(uint8_t const*& it, DefaultPrivateNoteNullifie read(it, preimage.commitment); read(it, preimage.owner_private_key); - read(it, preimage.is_real); + read(it, preimage.is_dummy); }; template void write(std::vector& buf, DefaultPrivateNoteNullifierPreimage const& preimage) @@ -55,7 +55,7 @@ template void write(std::vector& buf, DefaultPrivateNote write(buf, preimage.commitment); write(buf, preimage.owner_private_key); - write(buf, preimage.is_real); + write(buf, preimage.is_dummy); }; template @@ -63,7 +63,7 @@ std::ostream& operator<<(std::ostream& os, DefaultPrivateNoteNullifierPreimage struct PrivateStateNotePreimage; -template class NoteInterface { +template class NoteInterface { public: typedef CircuitTypes CT; typedef typename CT::fr fr; @@ -34,6 +34,11 @@ template compute_commitment() = 0; + virtual fr compute_commitment() = 0; + + virtual fr compute_nullifier() = 0; - virtual std::pair compute_nullifier() = 0; + // virtual void finalise(std::optional nonce) = 0; // virtual std::pair compute_partial_commitment() = 0; @@ -62,7 +69,7 @@ template #include #include +namespace aztec3::circuits::apps::state_vars { +template class UTXOStateVar; +} + namespace aztec3::circuits::apps::opcodes { -using aztec3::circuits::apps::state_vars::UTXOStateVar; +using aztec3::circuits::apps::state_vars::UTXOStateVar; // Don't #include it! using plonk::stdlib::witness_t; using plonk::stdlib::types::CircuitTypes; diff --git a/circuits/src/aztec3/circuits/apps/opcodes/opcodes.tpp b/circuits/src/aztec3/circuits/apps/opcodes/opcodes.tpp index 99fb47b6c4c..58fa558259f 100644 --- a/circuits/src/aztec3/circuits/apps/opcodes/opcodes.tpp +++ b/circuits/src/aztec3/circuits/apps/opcodes/opcodes.tpp @@ -1,17 +1,23 @@ #pragma once +#include "../function_execution_context.hpp" #include "../utxo_datum.hpp" -#include "../state_vars/state_var_base.hpp" +// #include "../state_vars/state_var_base.hpp" #include "../state_vars/utxo_state_var.hpp" #include #include #include +namespace { +// Declared here, so that `opcodes.hpp` doesn't see it; thereby preventing circular dependencies. +using aztec3::circuits::apps::state_vars::UTXOStateVar; +} // namespace + namespace aztec3::circuits::apps::opcodes { -using aztec3::circuits::apps::state_vars::UTXOStateVar; +using aztec3::circuits::apps::FunctionExecutionContext; using plonk::stdlib::witness_t; using plonk::stdlib::types::CircuitTypes; @@ -49,16 +55,11 @@ template template void Opcodes::UTXO_NULL(UTXOStateVar* utxo_state_var, Note& note) { - auto [nullifier, nullifier_preimage] = note.compute_nullifier(); - - auto exec_ctx = utxo_state_var->exec_ctx; + typename CT::fr nullifier = note.compute_nullifier(); - (void)exec_ctx; // TODO: finish function. - (void)nullifier; - (void)nullifier_preimage; + auto& exec_ctx = utxo_state_var->exec_ctx; - // TODO: - // - Push the nullifier data to the exec_ctx + exec_ctx->new_nullifiers.push_back(nullifier); }; template @@ -70,15 +71,8 @@ void Opcodes::UTXO_SSTORE(UTXOStateVar* utxo_state_var (void)utxo_state_var; (void)new_note_preimage; - // TODO: a salt (randomness for hiding) might not be needed for some custom Note types. Leave this to the - // `compute_commitment()` function of the Note instead (which will be called at FINALISATION of the notes, once - // enough nonces (nullifiers) are available). - // auto& oracle = utxo_state_var->exec_ctx->oracle; - // CT::fr salt = oracle.get_random_element(); - // new_note_preimage.salt = salt; - // TODO within this function: // - Push the commitment data to the exec_ctx, and maybe to the public inputs of the exec_ctx (although we might // need to complete the commitments with a nonce using a UTXO_FINALISE() opcode!) @@ -88,7 +82,13 @@ void Opcodes::UTXO_SSTORE(UTXOStateVar* utxo_state_var // need to defer committing until a FINALISE opcode at the end. // auto [new_note_commitment, _] = new_note.compute_commitment(); - // auto exec_ctx = utxo_state_var->exec_ctx; + auto& exec_ctx = utxo_state_var->exec_ctx; + + // Make a shared pointer, so we don't end up with a dangling pointer in the exec_ctx when this temp `new_note` + // immediately goes out of scope. + std::shared_ptr new_note = std::make_shared(utxo_state_var, new_note_preimage); + + exec_ctx->new_notes.push_back(new_note); // (void)exec_ctx; // TODO: finish function. // (void)new_note_commitment; diff --git a/circuits/src/aztec3/circuits/apps/private_state_note.hpp b/circuits/src/aztec3/circuits/apps/private_state_note.hpp index 10d846ec81f..1ebcf6a88dc 100644 --- a/circuits/src/aztec3/circuits/apps/private_state_note.hpp +++ b/circuits/src/aztec3/circuits/apps/private_state_note.hpp @@ -65,7 +65,7 @@ template class PrivateStateNote { static fr compute_nullifier(fr const& commitment, fr const& owner_private_key, - boolean const& is_real_commitment = true); + boolean const& is_dummy_commitment = false); static fr compute_dummy_nullifier(fr const& dummy_commitment, fr const& owner_private_key); diff --git a/circuits/src/aztec3/circuits/apps/private_state_note.tpp b/circuits/src/aztec3/circuits/apps/private_state_note.tpp index abf9f3d658e..4186779e99a 100644 --- a/circuits/src/aztec3/circuits/apps/private_state_note.tpp +++ b/circuits/src/aztec3/circuits/apps/private_state_note.tpp @@ -88,7 +88,7 @@ template typename CircuitTypes::fr PrivateStateNot salt, nonce, memo, - is_real] = preimage; + is_dummy] = preimage; const auto commitment_point = storage_slot_point + @@ -99,8 +99,8 @@ template typename CircuitTypes::fr PrivateStateNot gen_pair_fr(salt, PrivateStateNoteGeneratorIndex::SALT), gen_pair_fr(nonce, PrivateStateNoteGeneratorIndex::NONCE), gen_pair_fr(memo, PrivateStateNoteGeneratorIndex::MEMO), - std::make_pair(is_real, - generator_index_t({ GeneratorIndex::COMMITMENT, PrivateStateNoteGeneratorIndex::IS_REAL })) + std::make_pair( + is_dummy, generator_index_t({ GeneratorIndex::COMMITMENT, PrivateStateNoteGeneratorIndex::IS_DUMMY })) }); @@ -143,7 +143,7 @@ typename CircuitTypes::grumpkin_point PrivateStateNote::comp salt, nonce, memo, - is_real] = preimage; + is_dummy] = preimage; return storage_slot_point + CT::commit({ gen_pair_fr(value, PrivateStateNoteGeneratorIndex::VALUE), @@ -153,8 +153,8 @@ typename CircuitTypes::grumpkin_point PrivateStateNote::comp gen_pair_fr(nonce, PrivateStateNoteGeneratorIndex::NONCE), gen_pair_fr(memo, PrivateStateNoteGeneratorIndex::MEMO), std::make_pair( - is_real, - generator_index_t({ GeneratorIndex::COMMITMENT, PrivateStateNoteGeneratorIndex::IS_REAL })) + is_dummy, + generator_index_t({ GeneratorIndex::COMMITMENT, PrivateStateNoteGeneratorIndex::IS_DUMMY })) }); } @@ -173,11 +173,11 @@ std::pair::fr, NullifierPreimage::compute_nullifier(*commitment, owner_private_key, preimage.is_real); + nullifier = PrivateStateNote::compute_nullifier(*commitment, owner_private_key, preimage.is_dummy); nullifier_preimage = { *commitment, owner_private_key, - preimage.is_real, + preimage.is_dummy, }; return std::make_pair(*nullifier, *nullifier_preimage); }; @@ -185,7 +185,7 @@ std::pair::fr, NullifierPreimage typename CircuitTypes::fr PrivateStateNote::compute_nullifier(fr const& commitment, fr const& owner_private_key, - boolean const& is_real_commitment) + boolean const& is_dummy_commitment) { /** * Hashing the private key in this way enables the following use case: @@ -200,7 +200,7 @@ typename CircuitTypes::fr PrivateStateNote::compute_nullifie commitment, hashed_private_key.x, hashed_private_key.y, - is_real_commitment, + is_dummy_commitment, }; // We compress the hash_inputs with Pedersen, because that's cheaper (constraint-wise) than compressing @@ -211,8 +211,8 @@ typename CircuitTypes::fr PrivateStateNote::compute_nullifie // compression. /** E.g. we can extract a representation of the hashed_pk: * Paraphrasing, if: - * nullifier = note_comm * G1 + hashed_pk * G2 + is_real_note * G3 - * Then an observer can derive hashed_pk * G2 = nullifier - note_comm * G1 - is_real_note * G3 + * nullifier = note_comm * G1 + hashed_pk * G2 + is_dummy_note * G3 + * Then an observer can derive hashed_pk * G2 = nullifier - note_comm * G1 - is_dummy_note * G3 * They can derive this for every tx, to link which txs are being sent by the same user. * Notably, at the point someone withdraws, the observer would be able to connect `hashed_pk * G2` with a * specific eth address. diff --git a/circuits/src/aztec3/circuits/apps/state_vars/index.hpp b/circuits/src/aztec3/circuits/apps/state_vars/index.hpp deleted file mode 100644 index d0c69b2c882..00000000000 --- a/circuits/src/aztec3/circuits/apps/state_vars/index.hpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "field_state_var.hpp" -#include "mapping_state_var.hpp" -#include "utxo_state_var.hpp" \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.hpp b/circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.hpp index f6b4e58742a..dcd35b7b6d8 100644 --- a/circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.hpp +++ b/circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.hpp @@ -1,13 +1,20 @@ #pragma once #include "state_var_base.hpp" -#include "../function_execution_context.hpp" +// #include "../function_execution_context.hpp" #include #include +// Forward-declare from this namespace in particular: +namespace aztec3::circuits::apps { +template class FunctionExecutionContext; +} + namespace aztec3::circuits::apps::state_vars { +using aztec3::circuits::apps::FunctionExecutionContext; // Don't #include it! + using plonk::stdlib::types::CircuitTypes; using plonk::stdlib::types::NativeTypes; diff --git a/circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.tpp b/circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.tpp index 684d51a102c..f32bde86f3e 100644 --- a/circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.tpp +++ b/circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.tpp @@ -4,6 +4,9 @@ // #include "private_state_note.hpp" // #include "private_state_note_preimage.hpp" // #include "private_state_operand.hpp" + +#include "../function_execution_context.hpp" + #include "plonk/composer/turbo_composer.hpp" #include @@ -14,12 +17,32 @@ #include #include +namespace { +using aztec3::circuits::apps::FunctionExecutionContext; +} // namespace + namespace aztec3::circuits::apps::state_vars { using crypto::pedersen::generator_index_t; + using plonk::stdlib::types::CircuitTypes; using plonk::stdlib::types::NativeTypes; +// template +// MappingStateVar::MappingStateVar(FunctionExecutionContext* exec_ctx, +// std::string const& state_var_name) +// : StateVar(exec_ctx, state_var_name) +// {} + +// template +// MappingStateVar::MappingStateVar(FunctionExecutionContext* exec_ctx, +// std::string const& state_var_name, +// grumpkin_point const& storage_slot_point, +// size_t level_of_container_nesting, +// bool is_partial_slot) +// : StateVar(exec_ctx, state_var_name, storage_slot_point, level_of_container_nesting, is_partial_slot) +// {} + // Fr: start_slot // // mapping(fr => V): diff --git a/circuits/src/aztec3/circuits/apps/state_vars/state_var_base.hpp b/circuits/src/aztec3/circuits/apps/state_vars/state_var_base.hpp index 543a39da003..c4589d36617 100644 --- a/circuits/src/aztec3/circuits/apps/state_vars/state_var_base.hpp +++ b/circuits/src/aztec3/circuits/apps/state_vars/state_var_base.hpp @@ -1,12 +1,19 @@ #pragma once -#include "../function_execution_context.hpp" +// #include "../function_execution_context.hpp" #include #include +// Forward-declare from this namespace in particular: +namespace aztec3::circuits::apps { +template class FunctionExecutionContext; +} + namespace aztec3::circuits::apps::state_vars { +using aztec3::circuits::apps::FunctionExecutionContext; // Don't #include it! + using plonk::stdlib::types::CircuitTypes; using plonk::stdlib::types::NativeTypes; @@ -58,14 +65,7 @@ template class StateVar { StateVar(){}; // Instantiate a top-level state: - StateVar(FunctionExecutionContext* exec_ctx, std::string const& state_var_name) - : exec_ctx(exec_ctx) - , state_var_name(state_var_name) - - { - start_slot = exec_ctx->contract->get_start_slot(state_var_name); - storage_slot_point = compute_slot_point(); - }; + StateVar(FunctionExecutionContext* exec_ctx, std::string const& state_var_name); // Instantiate a nested state: StateVar( diff --git a/circuits/src/aztec3/circuits/apps/state_vars/state_var_base.tpp b/circuits/src/aztec3/circuits/apps/state_vars/state_var_base.tpp index 82e66fc9e66..72586a9d022 100644 --- a/circuits/src/aztec3/circuits/apps/state_vars/state_var_base.tpp +++ b/circuits/src/aztec3/circuits/apps/state_vars/state_var_base.tpp @@ -4,7 +4,12 @@ // #include "private_state_note.hpp" // #include "private_state_note_preimage.hpp" // #include "private_state_operand.hpp" -#include "plonk/composer/turbo_composer.hpp" + +// TODO: remove redundant includes: + +#include "../function_execution_context.hpp" + +#include #include #include @@ -14,6 +19,10 @@ #include #include +namespace { +using aztec3::circuits::apps::FunctionExecutionContext; +} + namespace aztec3::circuits::apps::state_vars { using crypto::pedersen::generator_index_t; @@ -32,6 +41,15 @@ using plonk::stdlib::types::NativeTypes; // start_slot_point becomes: prev_start_slot_point + k1 * B // at(k2).slot = new_start_slot_point + k2 * C +template +StateVar::StateVar(FunctionExecutionContext* exec_ctx, std::string const& state_var_name) + : exec_ctx(exec_ctx) + , state_var_name(state_var_name) +{ + start_slot = exec_ctx->contract->get_start_slot(state_var_name); + storage_slot_point = compute_slot_point(); +} + template typename CircuitTypes::grumpkin_point StateVar::compute_slot_point() { ASSERT(level_of_container_nesting == 0); diff --git a/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp b/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp index 9d863101cef..27e05c4954b 100644 --- a/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp +++ b/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp @@ -2,13 +2,22 @@ #include "state_var_base.hpp" -#include "../function_execution_context.hpp" +// #include "../function_execution_context.hpp" #include #include +// Forward-declare from this namespace in particular: +namespace aztec3::circuits::apps { +template class FunctionExecutionContext; +} + namespace aztec3::circuits::apps::state_vars { +using aztec3::circuits::apps::FunctionExecutionContext; // Don't #include it! + +// template class FunctionExecutionContext; + using plonk::stdlib::types::CircuitTypes; using plonk::stdlib::types::NativeTypes; diff --git a/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.tpp b/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.tpp index d6c05fe9d09..0638009f4b0 100644 --- a/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.tpp +++ b/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.tpp @@ -5,9 +5,11 @@ #include #include -namespace aztec3::circuits::apps::state_vars { - +namespace { using aztec3::circuits::apps::opcodes::Opcodes; +} // namespace + +namespace aztec3::circuits::apps::state_vars { template Note UTXOStateVar::get(typename Note::NotePreimage const& advice) @@ -21,4 +23,4 @@ void UTXOStateVar::insert(typename Note::NotePreimage new_note_p return Opcodes::UTXO_SSTORE(this, new_note_preimage); }; -} // namespace aztec3::circuits::apps::state_vars +} // namespace aztec3::circuits::apps::state_vars \ No newline at end of file diff --git a/circuits/src/aztec3/constants.hpp b/circuits/src/aztec3/constants.hpp index 128acf1ce85..b23fb9b99b2 100644 --- a/circuits/src/aztec3/constants.hpp +++ b/circuits/src/aztec3/constants.hpp @@ -68,7 +68,7 @@ enum PrivateStateNoteGeneratorIndex { SALT, NONCE, MEMO, - IS_REAL, + IS_DUMMY, }; enum PrivateStateType { PARTITIONED = 1, WHOLE }; diff --git a/circuits/src/aztec3/oracle/oracle.hpp b/circuits/src/aztec3/oracle/oracle.hpp index 28081198799..8b73a02fef2 100644 --- a/circuits/src/aztec3/oracle/oracle.hpp +++ b/circuits/src/aztec3/oracle/oracle.hpp @@ -172,7 +172,7 @@ class FakeDB { .memo = 3456, .salt = 1234, .nonce = 2345, - .is_real = true, + .is_dummy = false, }; const size_t utxo_tree_depth = 32; From c46760038ada3c3effe77bef1b52f0fbd7d4942c Mon Sep 17 00:00:00 2001 From: iAmMichaelConnor Date: Wed, 4 Jan 2023 11:09:11 +0000 Subject: [PATCH 021/166] finalise utxos --- circuits/src/aztec3/circuits/apps/.test.cpp | 2 +- .../apps/function_execution_context.hpp | 82 +++++++------------ .../apps/notes/default_private_note/note.hpp | 16 +++- .../apps/notes/default_private_note/note.tpp | 73 +++++++++++------ .../circuits/apps/notes/note_interface.hpp | 14 ++-- .../aztec3/circuits/apps/opcodes/opcodes.tpp | 25 +----- 6 files changed, 99 insertions(+), 113 deletions(-) diff --git a/circuits/src/aztec3/circuits/apps/.test.cpp b/circuits/src/aztec3/circuits/apps/.test.cpp index 3727b2c9b3c..05f2e7cb34d 100644 --- a/circuits/src/aztec3/circuits/apps/.test.cpp +++ b/circuits/src/aztec3/circuits/apps/.test.cpp @@ -203,7 +203,7 @@ TEST_F(state_var_tests, utxo_of_default_private_note_fr) auto new_nullifiers = exec_ctx.get_new_nullifiers(); info("new_nullifiers: ", new_nullifiers); - // TODO: a UTXO_FINALISE() opcode? + exec_ctx.finalise(); } } // namespace aztec3::circuits::apps \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/function_execution_context.hpp b/circuits/src/aztec3/circuits/apps/function_execution_context.hpp index 6a69cec115d..eefbf705786 100644 --- a/circuits/src/aztec3/circuits/apps/function_execution_context.hpp +++ b/circuits/src/aztec3/circuits/apps/function_execution_context.hpp @@ -116,63 +116,39 @@ template class FunctionExecutionContext { * * Note: Not all custom Note types will need a nonce of this kind in their NotePreimage. But they can simply * implement an empty body in the `set_nonce() override`. + * + * TODO: Might need some refactoring. Roles between: Opcodes modifying exec_ctx members; and the exec_ctx directly + * modifying its members, are somewhat blurred at the moment. */ void finalise_utxos() { - // if (new_notes.size() > nullified_notes.size()) { - // // We've created more commitments than nullifiers so far. But we want to inject an input_nullifier into - // each - // // new commitment. So, let's create more dummy nullifiers. - // const auto& msg_sender_private_key = oracle.get_msg_sender_private_key(); - // for (size_t i = new_nullifier_preimages.size(); i < new_private_state_notes.size(); ++i) { - // auto dummy_commitment = oracle.generate_random_element(); - // new_nullifier_preimages.push_back(NullifierPreimage{ - // dummy_commitment, - // msg_sender_private_key, - // false, - // }); - // new_nullifiers.push_back( - // PrivateStateNote::compute_dummy_nullifier(dummy_commitment, msg_sender_private_key)); - // } - // } - // Copy some vectors, as we can't control whether they'll be pushed-to further, when we call Note methods. - // auto new_commitments_copy = new_commitments; - // auto new_nullifiers_copy = new_nullifiers; - // auto new_notes_copy = new_notes; - - // size_t used_nullifiers_count = 0; - // bool next_nullifier_available = false; - // bool next_nullifier_used = false; - // std::optional next_nullifier; - // std::vector new_nonces; - - // for (size_t i = 0; i < new_notes.size(); ++i) { - // const& note = new_notes_copy[i]; - - // next_nullifier_available = nullified_notes.size() > used_nullifiers_count; - - // if (next_nullifier_available) { - // next_nullifier = nullified_notes[used_nullifiers_count++].nullifier; - // next_nullifier_used = new_notes[i].set_nonce(next_nullifier); - // } - - // if (!next_nullifier_used) { - // next_nullifier = nullified_notes.size() > used_nullifiers_count - // ? nullified_notes[used_nullifiers_count++].nullifier - // : std::nullopt; // Indicates that all the existing non-dummy nullifiers have - // // all been used-up. - // } else { - // std::optional new_nonce = new_notes[i].generate_nonce(); - // if (new_nonce) { - // new_nonces.push_back(*new_nonce); - // } - // } - - // new_commitments.push_back(new_notes[i].get_commitment()); - - // // Push new_nonces to the end of new_nullifiers: - // std::copy(new_nonces.begin(), new_nonces.end(), std::back_inserter(new_nullifiers)); + auto new_nullifiers_copy = new_nullifiers; + + size_t used_nullifiers_count = 0; + fr next_nullifier; + std::vector new_nonces; + + for (size_t i = 0; i < new_notes.size(); ++i) { + NoteInterface& note = *new_notes[i]; + + if (note.needs_nonce()) { + const bool next_nullifier_available = new_nullifiers_copy.size() > used_nullifiers_count; + + if (next_nullifier_available) { + next_nullifier = new_nullifiers_copy[used_nullifiers_count++]; + note.set_nonce(next_nullifier); + } else { + const fr new_nonce = note.generate_nonce(); + new_nonces.push_back(new_nonce); + } + } + + new_commitments.push_back(note.get_commitment()); + } + + // Push new_nonces to the end of new_nullifiers: + std::copy(new_nonces.begin(), new_nonces.end(), std::back_inserter(new_nullifiers)); } void finalise() diff --git a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.hpp b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.hpp index c96d3110a03..c6f4b1707df 100644 --- a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.hpp +++ b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.hpp @@ -50,15 +50,15 @@ template class DefaultPrivateNote : publ std::optional nullifier_preimage; public: + // CUSTOM CONSTRUCTORS: + DefaultPrivateNote(UTXOStateVar* utxo_state_var, NotePreimage note_preimage) : utxo_state_var(utxo_state_var) , note_preimage(note_preimage){}; ~DefaultPrivateNote() {} - // bool operator==(PrivateStateNote const&) const = default; - - // METHODS + // OVERRIDE METHODS: void remove() override; @@ -94,7 +94,15 @@ template class DefaultPrivateNote : publ fr compute_nullifier() override; - // void finalise(std::optional nonce) override; + void constrain_against_advice(NoteInterface const& advice_note) override; + + bool needs_nonce() override; + + void set_nonce(fr nonce) override; + + fr generate_nonce() override; + + // CUSTOM METHODS auto& get_oracle(); diff --git a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.tpp b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.tpp index f282f0accf2..c70d3fe44b3 100644 --- a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.tpp +++ b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.tpp @@ -1,6 +1,8 @@ #include "note_preimage.hpp" #include "nullifier_preimage.hpp" +#include "../note_interface.hpp" + #include "../../oracle_wrapper.hpp" #include "../../opcodes/opcodes.hpp" #include "../../state_vars/utxo_state_var.hpp" @@ -193,9 +195,9 @@ typename CircuitTypes::fr DefaultPrivateNote::compute_nul template typename CircuitTypes::fr DefaultPrivateNote::compute_dummy_nullifier() { - const auto& oracle = get_oracle(); - const fr dummy_commitment = oracle.generate_random_element(); - const fr owner_private_key = oracle.get_msg_sender_private_key(); + auto& oracle = get_oracle(); + fr dummy_commitment = oracle.generate_random_element(); + fr& owner_private_key = oracle.get_msg_sender_private_key(); const boolean is_dummy_commitment = true; return DefaultPrivateNote::compute_nullifier(dummy_commitment, owner_private_key, is_dummy_commitment); @@ -240,30 +242,49 @@ typename CircuitTypes::fr DefaultPrivateNote::compute_nul return fr(blake_result); }; -// template bool DefaultPrivateNote::needs_nonce() -// { -// return !note_preimage.nonce; -// } +template +void DefaultPrivateNote::constrain_against_advice(NoteInterface const& advice_note) +{ + // Cast from a ref to the base (interface) type to a ref to this derived type: + const DefaultPrivateNote& advice_note_ref = + dynamic_cast&>(advice_note); -// template -// bool DefaultPrivateNote::set_nonce(typename CircuitTypes::fr nonce) -// { -// if (!note_preimage.nonce) { -// note_preimage.nonce = nonce; -// return true; // "We have used the nonce provided" -// } -// return false; // "We did not used the provided nonce. -// }; - -// template -// std::optional::fr> DefaultPrivateNote::generate_nonce() -// { -// if (!note_preimage.nonce) { -// note_preimage.nonce = compute_dummy_nullifier(); -// return std::make_optional; // "We are returning a new dummy nonce" -// } -// return std::nullopt; // "We are not returning a new dummy nonce" -// }; + auto assert_equal = [](std::optional& this_member, std::optional const& advice_member) { + if (advice_member) { + (*this_member).assert_equal(*advice_member); + } + }; + + const auto& advice_preimage = advice_note_ref.note_preimage; + auto& this_preimage = note_preimage; + + assert_equal(this_preimage.value, advice_preimage.value); + assert_equal(this_preimage.owner, advice_preimage.owner); + assert_equal(this_preimage.creator_address, advice_preimage.creator_address); + assert_equal(this_preimage.memo, advice_preimage.memo); + assert_equal(this_preimage.salt, advice_preimage.salt); + assert_equal(this_preimage.nonce, advice_preimage.nonce); +} + +template bool DefaultPrivateNote::needs_nonce() +{ + return !note_preimage.nonce; +} + +template +void DefaultPrivateNote::set_nonce(typename CircuitTypes::fr nonce) +{ + ASSERT(!note_preimage.nonce); + note_preimage.nonce = nonce; +}; + +template +typename CircuitTypes::fr DefaultPrivateNote::generate_nonce() +{ + ASSERT(!note_preimage.nonce); + note_preimage.nonce = compute_dummy_nullifier(); + return *(note_preimage.nonce); +}; // template // typename CircuitTypes::fr DefaultPrivateNote::compute_dummy_nullifier(fr const& dummy_commitment, diff --git a/circuits/src/aztec3/circuits/apps/notes/note_interface.hpp b/circuits/src/aztec3/circuits/apps/notes/note_interface.hpp index 0cf823584c5..ce94f6c9644 100644 --- a/circuits/src/aztec3/circuits/apps/notes/note_interface.hpp +++ b/circuits/src/aztec3/circuits/apps/notes/note_interface.hpp @@ -26,8 +26,6 @@ template class NoteInterface { typedef typename CT::address address; typedef typename CT::boolean boolean; - // bool operator==(PrivateStateNote const&) const = default; - // UTXOStateVar* utxo_state_var; // NoteInterface(UTXOStateVar* utxo_state_var, NotePreimage note_preimage) @@ -39,12 +37,8 @@ template class NoteInterface { // object is deleted through a pointer to this base class. (In many places in the code, files handle // `NoteInterface*` pointers instead of the derived class). - // METHODS - virtual void remove() = 0; - // HOOKS - virtual fr get_commitment() = 0; virtual fr get_nullifier() = 0; @@ -59,12 +53,16 @@ template class NoteInterface { virtual fr compute_nullifier() = 0; + virtual void constrain_against_advice(NoteInterface const& advice_note) = 0; + + virtual bool needs_nonce() = 0; + virtual void set_nonce(fr nonce) = 0; + virtual fr generate_nonce() = 0; + // virtual void finalise(std::optional nonce) = 0; // virtual std::pair compute_partial_commitment() = 0; - // STATIC HOOKS: - // static fr compute_dummy_commitment() = 0; // static fr compute_nullifier(fr const& commitment, diff --git a/circuits/src/aztec3/circuits/apps/opcodes/opcodes.tpp b/circuits/src/aztec3/circuits/apps/opcodes/opcodes.tpp index 58fa558259f..b6f242f4494 100644 --- a/circuits/src/aztec3/circuits/apps/opcodes/opcodes.tpp +++ b/circuits/src/aztec3/circuits/apps/opcodes/opcodes.tpp @@ -37,14 +37,15 @@ Note Opcodes::UTXO_SLOAD(UTXOStateVar* utxo_state_var, oracle.template get_utxo_sload_datum(storage_slot_point, advice); Note new_note{ utxo_state_var, utxo_datum.preimage }; + Note advice_note{ utxo_state_var, advice }; + + new_note.constrain_against_advice(advice_note); new_note.get_commitment().assert_equal(utxo_datum.commitment, "UTXO_SLOAD: bad commitment"); oracle.get_contract_address().assert_equal(utxo_datum.contract_address, "UTXO_SLOAD: bad contract address"); // TODO within this function: - // - constrain any of the `advice` fields which aren't std::nullopt (call upon a method in the note itself to - // `constrain_from_advice()`). // - Merkle Membership Check using the contract_address, utxo_datum.{sibling_path, leaf_index, // old_private_data_tree_root} @@ -67,31 +68,13 @@ template void Opcodes::UTXO_SSTORE(UTXOStateVar* utxo_state_var, typename Note::NotePreimage new_note_preimage) { - - (void)utxo_state_var; - (void)new_note_preimage; - - // auto& oracle = utxo_state_var->exec_ctx->oracle; - - // TODO within this function: - // - Push the commitment data to the exec_ctx, and maybe to the public inputs of the exec_ctx (although we might - // need to complete the commitments with a nonce using a UTXO_FINALISE() opcode!) - - // Note new_note{ utxo_state_var, new_note_preimage }; - // TODO: the code rightly complains when we try to commit, because we haven't chosen a nonce yet! Hence why we might - // need to defer committing until a FINALISE opcode at the end. - // auto [new_note_commitment, _] = new_note.compute_commitment(); - auto& exec_ctx = utxo_state_var->exec_ctx; - // Make a shared pointer, so we don't end up with a dangling pointer in the exec_ctx when this temp `new_note` + // Make a shared pointer, so we don't end up with a dangling pointer in the exec_ctx when this `new_note` // immediately goes out of scope. std::shared_ptr new_note = std::make_shared(utxo_state_var, new_note_preimage); exec_ctx->new_notes.push_back(new_note); - - // (void)exec_ctx; // TODO: finish function. - // (void)new_note_commitment; }; } // namespace aztec3::circuits::apps::opcodes From c3799e9af454e637a5bedc4186a7c881bb6fd123 Mon Sep 17 00:00:00 2001 From: iAmMichaelConnor Date: Wed, 4 Jan 2023 21:37:55 +0000 Subject: [PATCH 022/166] deposit & transfer examples working with newer utxo syntax --- circuits/src/aztec3/circuits/apps/.test.cpp | 70 ++++- .../src/aztec3/circuits/apps/contract.hpp | 1 - .../src/aztec3/circuits/apps/contract.tpp | 7 +- .../apps/function_execution_context.hpp | 6 +- circuits/src/aztec3/circuits/apps/index.hpp | 4 - .../apps/notes/default_private_note/note.hpp | 18 +- .../apps/notes/default_private_note/note.tpp | 17 +- .../circuits/apps/nullifier_preimage.hpp | 67 ---- .../aztec3/circuits/apps/opcodes/opcodes.hpp | 30 +- .../aztec3/circuits/apps/opcodes/opcodes.tpp | 64 +++- .../aztec3/circuits/apps/oracle_wrapper.hpp | 29 +- .../circuits/apps/private_state.test.cpp | 184 +++++------ .../circuits/apps/private_state_note.hpp | 141 --------- .../circuits/apps/private_state_note.tpp | 234 -------------- .../apps/private_state_note_preimage.hpp | 118 ------- .../circuits/apps/private_state_operand.hpp | 44 --- .../circuits/apps/private_state_var.hpp | 141 --------- .../circuits/apps/private_state_var.tpp | 291 ------------------ .../apps/state_vars/field_state_var.hpp | 5 +- .../apps/state_vars/state_var_base.hpp | 13 +- .../apps/state_vars/utxo_set_state_var.hpp | 62 ++++ .../apps/state_vars/utxo_set_state_var.tpp | 27 ++ .../apps/state_vars/utxo_state_var.hpp | 3 +- .../apps/state_vars/utxo_state_var.tpp | 2 +- .../circuits/apps/test_apps/escrow/.test.cpp | 178 ++++++----- .../apps/test_apps/escrow/contract.hpp | 50 ++- .../apps/test_apps/escrow/deposit.cpp | 170 ++++------ .../apps/test_apps/escrow/deposit.hpp | 22 +- .../circuits/apps/test_apps/escrow/index.hpp | 10 +- .../circuits/apps/test_apps/escrow/init.hpp | 56 +++- .../apps/test_apps/escrow/transfer.cpp | 145 +++++---- .../apps/test_apps/escrow/transfer.hpp | 28 +- circuits/src/aztec3/oracle/oracle.hpp | 96 +++--- 33 files changed, 754 insertions(+), 1579 deletions(-) delete mode 100644 circuits/src/aztec3/circuits/apps/index.hpp delete mode 100644 circuits/src/aztec3/circuits/apps/nullifier_preimage.hpp delete mode 100644 circuits/src/aztec3/circuits/apps/private_state_note.hpp delete mode 100644 circuits/src/aztec3/circuits/apps/private_state_note.tpp delete mode 100644 circuits/src/aztec3/circuits/apps/private_state_note_preimage.hpp delete mode 100644 circuits/src/aztec3/circuits/apps/private_state_operand.hpp delete mode 100644 circuits/src/aztec3/circuits/apps/private_state_var.hpp delete mode 100644 circuits/src/aztec3/circuits/apps/private_state_var.tpp create mode 100644 circuits/src/aztec3/circuits/apps/state_vars/utxo_set_state_var.hpp create mode 100644 circuits/src/aztec3/circuits/apps/state_vars/utxo_set_state_var.tpp diff --git a/circuits/src/aztec3/circuits/apps/.test.cpp b/circuits/src/aztec3/circuits/apps/.test.cpp index 05f2e7cb34d..fb905f48915 100644 --- a/circuits/src/aztec3/circuits/apps/.test.cpp +++ b/circuits/src/aztec3/circuits/apps/.test.cpp @@ -20,6 +20,7 @@ #include "state_vars/field_state_var.hpp" #include "state_vars/mapping_state_var.hpp" #include "state_vars/utxo_state_var.hpp" +#include "state_vars/utxo_set_state_var.hpp" #include @@ -51,6 +52,7 @@ using Contract = aztec3::circuits::apps::Contract; // StateVars using aztec3::circuits::apps::state_vars::FieldStateVar; using aztec3::circuits::apps::state_vars::MappingStateVar; +using aztec3::circuits::apps::state_vars::UTXOSetStateVar; using aztec3::circuits::apps::state_vars::UTXOStateVar; using aztec3::circuits::apps::notes::DefaultPrivateNote; @@ -62,11 +64,13 @@ using aztec3::circuits::apps::notes::NoteInterface; template struct SpecialisedTypes { typedef MappingStateVar mapping; typedef UTXOStateVar utxo; + typedef UTXOSetStateVar utxo_set; }; template using Mapping = typename SpecialisedTypes::mapping; template using UTXO = typename SpecialisedTypes::utxo; +template using UTXOSet = typename SpecialisedTypes::utxo_set; using Field = FieldStateVar; @@ -162,15 +166,8 @@ TEST_F(state_var_tests, utxo_of_default_private_note_fr) OracleWrapper oracle = OracleWrapper(composer, native_oracle); FunctionExecutionContext exec_ctx(composer, oracle); - // bool sort(NT::uint256 i, NT::uint256 j) - // { - // return (i < j); - // }; - - // { Contract contract(exec_ctx, "TestContract"); contract.declare_state_var("my_utxo"); - // } // FUNCTION: @@ -193,6 +190,8 @@ TEST_F(state_var_tests, utxo_of_default_private_note_fr) .creator_address = msg_sender, .memo = 1234 }); + exec_ctx.finalise(); + // Here, we test that the shared_ptr of a note, stored within the exec_ctx, works. TODO: put this in its own little // test, instead of this ever-growing beast test. auto new_note_pointers = exec_ctx.get_new_notes(); @@ -202,8 +201,65 @@ TEST_F(state_var_tests, utxo_of_default_private_note_fr) auto new_nullifiers = exec_ctx.get_new_nullifiers(); info("new_nullifiers: ", new_nullifiers); +} + +TEST_F(state_var_tests, utxo_set_of_default_private_notes_fr) +{ + C composer; + NativeOracle native_oracle = get_test_native_oracle(); + OracleWrapper oracle = OracleWrapper(composer, native_oracle); + FunctionExecutionContext exec_ctx(composer, oracle); + + // bool sort(NT::uint256 i, NT::uint256 j) + // { + // return (i < j); + // }; + + Contract contract(exec_ctx, "TestContract"); + contract.declare_state_var("balances"); + + // FUNCTION: + + using Note = DefaultPrivateNote; + + UTXOSet balances(&exec_ctx, "balances"); + + // Imagine these were passed into the function as args: + CT::fr amount = 5; + CT::address to_address = 765976; + + const auto& msg_sender = oracle.get_msg_sender(); + + std::vector old_balance_notes = balances.get(2, { .owner = msg_sender }); + + CT::fr old_value_1 = *(old_balance_notes[0].get_preimage().value); + CT::fr old_value_2 = *(old_balance_notes[1].get_preimage().value); + + old_balance_notes[0].remove(); + old_balance_notes[1].remove(); + + // MISSING: overflow & underflow checks, but I can't be bothered with safe_uint or range checks yet. + + CT::fr new_value = (old_value_1 + old_value_2) - amount; + + balances.insert({ + .value = new_value, + .owner = to_address, + .creator_address = msg_sender, + .memo = 1234, + }); exec_ctx.finalise(); + + // Here, we test that the shared_ptr of a note, stored within the exec_ctx, works. TODO: put this in its own little + // test, instead of this ever-growing beast test. + auto new_note_pointers = exec_ctx.get_new_notes(); + std::shared_ptr debug_note = std::dynamic_pointer_cast(new_note_pointers[0]); + info("new_note_pointers: ", new_note_pointers); + info("*(new_note_pointers[0]): ", debug_note->get_preimage()); + + auto new_nullifiers = exec_ctx.get_new_nullifiers(); + info("new_nullifiers: ", new_nullifiers); } } // namespace aztec3::circuits::apps \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/contract.hpp b/circuits/src/aztec3/circuits/apps/contract.hpp index 1e52afedf79..fee61740a2a 100644 --- a/circuits/src/aztec3/circuits/apps/contract.hpp +++ b/circuits/src/aztec3/circuits/apps/contract.hpp @@ -1,7 +1,6 @@ #pragma once #include "function_declaration.hpp" -#include "private_state_var.hpp" #include "l1_function_interface.hpp" #include diff --git a/circuits/src/aztec3/circuits/apps/contract.tpp b/circuits/src/aztec3/circuits/apps/contract.tpp index f11e86a027b..bc3f5101b59 100644 --- a/circuits/src/aztec3/circuits/apps/contract.tpp +++ b/circuits/src/aztec3/circuits/apps/contract.tpp @@ -1,13 +1,16 @@ #pragma once #include "function_execution_context.hpp" -#include "private_state_var.hpp" #include "function_declaration.hpp" #include "l1_function_interface.hpp" + #include + #include -#include + #include +#include + namespace aztec3::circuits::apps { using plonk::stdlib::witness_t; diff --git a/circuits/src/aztec3/circuits/apps/function_execution_context.hpp b/circuits/src/aztec3/circuits/apps/function_execution_context.hpp index eefbf705786..21e03a1f2fb 100644 --- a/circuits/src/aztec3/circuits/apps/function_execution_context.hpp +++ b/circuits/src/aztec3/circuits/apps/function_execution_context.hpp @@ -1,9 +1,7 @@ #pragma once #include "contract.hpp" -#include "nullifier_preimage.hpp" #include "oracle_wrapper.hpp" -#include "private_state_note.hpp" #include "notes/note_interface.hpp" @@ -50,9 +48,10 @@ template class FunctionExecutionContext { Contract* contract = nullptr; - private: + // TODO: make this private! OptionalPrivateCircuitPublicInputs private_circuit_public_inputs; + private: std::vector>> new_notes; std::vector new_commitments; @@ -129,6 +128,7 @@ template class FunctionExecutionContext { fr next_nullifier; std::vector new_nonces; + // This is almost a visitor pattern. Call methods on each note. The note will choose what to do. for (size_t i = 0; i < new_notes.size(); ++i) { NoteInterface& note = *new_notes[i]; diff --git a/circuits/src/aztec3/circuits/apps/index.hpp b/circuits/src/aztec3/circuits/apps/index.hpp deleted file mode 100644 index 0ae8d268c7f..00000000000 --- a/circuits/src/aztec3/circuits/apps/index.hpp +++ /dev/null @@ -1,4 +0,0 @@ -#include "private_state_var.hpp" -#include "private_state_note.hpp" -#include "private_state_note_preimage.hpp" -// #include "completable_private_state_note_preimage.hpp" \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.hpp b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.hpp index c6f4b1707df..a520aac9e41 100644 --- a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.hpp +++ b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.hpp @@ -5,19 +5,23 @@ #include "note_preimage.hpp" #include "nullifier_preimage.hpp" -// #include "../../state_vars/utxo_state_var.hpp" - #include #include +#include + // Forward-declare from this namespace in particular: namespace aztec3::circuits::apps::state_vars { +template class StateVar; template class UTXOStateVar; +template class UTXOSetStateVar; } // namespace aztec3::circuits::apps::state_vars namespace aztec3::circuits::apps::notes { -using aztec3::circuits::apps::state_vars::UTXOStateVar; // Don't #include it! +using aztec3::circuits::apps::state_vars::StateVar; // Don't #include it! +using aztec3::circuits::apps::state_vars::UTXOSetStateVar; // Don't #include it! +using aztec3::circuits::apps::state_vars::UTXOStateVar; // Don't #include it! using plonk::stdlib::types::CircuitTypes; using plonk::stdlib::types::NativeTypes; @@ -33,11 +37,13 @@ template class DefaultPrivateNote : publ typedef typename CT::address address; typedef typename CT::boolean boolean; + // using VariantUTXOStateVar = + // std::variant, UTXOSetStateVar>; using NotePreimage = DefaultPrivateNotePreimage, ValueType>; using NullifierPreimage = DefaultPrivateNoteNullifierPreimage>; public: - UTXOStateVar* utxo_state_var; + StateVar* state_var; private: std::optional commitment; @@ -52,8 +58,8 @@ template class DefaultPrivateNote : publ public: // CUSTOM CONSTRUCTORS: - DefaultPrivateNote(UTXOStateVar* utxo_state_var, NotePreimage note_preimage) - : utxo_state_var(utxo_state_var) + DefaultPrivateNote(StateVar* state_var, NotePreimage note_preimage) + : state_var(state_var) , note_preimage(note_preimage){}; ~DefaultPrivateNote() {} diff --git a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.tpp b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.tpp index c70d3fe44b3..2c94448004b 100644 --- a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.tpp +++ b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.tpp @@ -5,7 +5,10 @@ #include "../../oracle_wrapper.hpp" #include "../../opcodes/opcodes.hpp" + +#include "../../state_vars/state_var_base.hpp" #include "../../state_vars/utxo_state_var.hpp" +#include "../../state_vars/utxo_set_state_var.hpp" #include @@ -18,8 +21,12 @@ #include #include +#include + namespace { using aztec3::circuits::apps::opcodes::Opcodes; +using aztec3::circuits::apps::state_vars::StateVar; +using aztec3::circuits::apps::state_vars::UTXOSetStateVar; using aztec3::circuits::apps::state_vars::UTXOStateVar; } // namespace @@ -35,12 +42,12 @@ using plonk::stdlib::types::NativeTypes; template void DefaultPrivateNote::remove() { - Opcodes::UTXO_NULL(utxo_state_var, *this); + Opcodes::UTXO_NULL(state_var, *this); } template auto& DefaultPrivateNote::get_oracle() { - return utxo_state_var->exec_ctx->oracle; + return state_var->exec_ctx->oracle; } template bool DefaultPrivateNote::is_partial_preimage() const @@ -52,7 +59,7 @@ template bool DefaultPrivateNote::i template bool DefaultPrivateNote::is_partial_storage_slot() const { - return utxo_state_var->is_partial_slot; + return state_var->is_partial_slot; } template bool DefaultPrivateNote::is_partial() const @@ -67,7 +74,7 @@ typename CircuitTypes::fr DefaultPrivateNote::compute_com return *commitment; } - grumpkin_point storage_slot_point = utxo_state_var->storage_slot_point; + grumpkin_point storage_slot_point = state_var->storage_slot_point; std::vector inputs; std::vector generators; @@ -123,7 +130,7 @@ typename CircuitTypes::grumpkin_point DefaultPrivateNote: "here. But if that's not the case, you should call get_partial_commitment() instead, to save constraints."); } - grumpkin_point storage_slot_point = utxo_state_var->storage_slot_point; + grumpkin_point storage_slot_point = state_var->storage_slot_point; std::vector inputs; std::vector generators; diff --git a/circuits/src/aztec3/circuits/apps/nullifier_preimage.hpp b/circuits/src/aztec3/circuits/apps/nullifier_preimage.hpp deleted file mode 100644 index 83663eb8bb9..00000000000 --- a/circuits/src/aztec3/circuits/apps/nullifier_preimage.hpp +++ /dev/null @@ -1,67 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include - -namespace aztec3::circuits::apps { - -using crypto::pedersen::generator_index_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; - -template struct NullifierPreimage { - typedef typename NCT::fr fr; - typedef typename NCT::boolean boolean; - - fr commitment; - fr owner_private_key; - boolean is_real; - - bool operator==(NullifierPreimage const&) const = default; - - template NullifierPreimage> to_circuit_type(Composer& composer) const - { - static_assert((std::is_same::value)); - - // Capture the composer: - auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; - - NullifierPreimage> preimage = { - to_ct(commitment), - to_ct(owner_private_key), - to_ct(is_real), - }; - - return preimage; - }; -}; - -template void read(uint8_t const*& it, NullifierPreimage& preimage) -{ - using serialize::read; - - read(it, preimage.commitment); - read(it, preimage.owner_private_key); - read(it, preimage.is_real); -}; - -template void write(std::vector& buf, NullifierPreimage const& preimage) -{ - using serialize::write; - - write(buf, preimage.commitment); - write(buf, preimage.owner_private_key); - write(buf, preimage.is_real); -}; - -template std::ostream& operator<<(std::ostream& os, NullifierPreimage const& preimage) -{ - return os << "commitment: " << preimage.commitment << "\n" - << "owner_private_key: " << preimage.owner_private_key << "\n" - << "is_real: " << preimage.is_real << "\n"; -} - -} // namespace aztec3::circuits::apps \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/opcodes/opcodes.hpp b/circuits/src/aztec3/circuits/apps/opcodes/opcodes.hpp index f98708acf1c..d9240419a8c 100644 --- a/circuits/src/aztec3/circuits/apps/opcodes/opcodes.hpp +++ b/circuits/src/aztec3/circuits/apps/opcodes/opcodes.hpp @@ -6,13 +6,19 @@ #include #include +#include + namespace aztec3::circuits::apps::state_vars { +template class StateVar; template class UTXOStateVar; -} +template class UTXOSetStateVar; +} // namespace aztec3::circuits::apps::state_vars namespace aztec3::circuits::apps::opcodes { -using aztec3::circuits::apps::state_vars::UTXOStateVar; // Don't #include it! +using aztec3::circuits::apps::state_vars::StateVar; // Don't #include it! +using aztec3::circuits::apps::state_vars::UTXOSetStateVar; // Don't #include it! +using aztec3::circuits::apps::state_vars::UTXOStateVar; // Don't #include it! using plonk::stdlib::witness_t; using plonk::stdlib::types::CircuitTypes; @@ -23,27 +29,39 @@ template class Opcodes { typedef CircuitTypes CT; typedef NativeTypes NT; + template + using VariantUTXOStateVar = std::variant, UTXOSetStateVar>; + /** * @brief * - Load a singleton UTXOSLoadDatum from the Private Client's DB * - Generate constraints to prove its existence in the tree * - Validate the data - * - Push new note data to the exec_ctx. */ template static Note UTXO_SLOAD(UTXOStateVar* utxo_state_var, typename Note::NotePreimage const& advice); + /** + * @brief + * - Load a subset of `UTXOSLoadDatum`s (which belong to a particular UTXOSetStateVar), from the Private Client's DB + * - Generate constraints to prove each datum's existence in the tree + * - Validate the data + */ + template + static std::vector UTXO_SLOAD(UTXOSetStateVar* utxo_set_state_var, + size_t const& num_notes, + typename Note::NotePreimage const& advice); + /** * @brief Compute and push a new nullifier to the public inputs of this exec_ctx. */ - template static void UTXO_NULL(UTXOStateVar* utxo_state_var, Note& note); + template static void UTXO_NULL(StateVar* state_var, Note& note); /** * @brief Compute and push a new comitment to the public inputs of this exec_ctx. */ template - static void UTXO_SSTORE(UTXOStateVar* utxo_state_var, - typename Note::NotePreimage new_note_preimage); + static void UTXO_SSTORE(StateVar* state_var, typename Note::NotePreimage new_note_preimage); }; } // namespace aztec3::circuits::apps::opcodes diff --git a/circuits/src/aztec3/circuits/apps/opcodes/opcodes.tpp b/circuits/src/aztec3/circuits/apps/opcodes/opcodes.tpp index b6f242f4494..5c4c3cafebd 100644 --- a/circuits/src/aztec3/circuits/apps/opcodes/opcodes.tpp +++ b/circuits/src/aztec3/circuits/apps/opcodes/opcodes.tpp @@ -3,8 +3,9 @@ #include "../function_execution_context.hpp" #include "../utxo_datum.hpp" -// #include "../state_vars/state_var_base.hpp" +#include "../state_vars/state_var_base.hpp" #include "../state_vars/utxo_state_var.hpp" +#include "../state_vars/utxo_set_state_var.hpp" #include #include @@ -12,6 +13,8 @@ namespace { // Declared here, so that `opcodes.hpp` doesn't see it; thereby preventing circular dependencies. +using aztec3::circuits::apps::state_vars::StateVar; +using aztec3::circuits::apps::state_vars::UTXOSetStateVar; using aztec3::circuits::apps::state_vars::UTXOStateVar; } // namespace @@ -41,6 +44,10 @@ Note Opcodes::UTXO_SLOAD(UTXOStateVar* utxo_state_var, new_note.constrain_against_advice(advice_note); + info("calculated commitment: ", new_note.get_commitment()); + info("retrieved commitment: ", utxo_datum.commitment); + // TODO: hard-code or calculate the correct commitment in the FakeDB stub, so that the returned data passes this + // check. new_note.get_commitment().assert_equal(utxo_datum.commitment, "UTXO_SLOAD: bad commitment"); oracle.get_contract_address().assert_equal(utxo_datum.contract_address, "UTXO_SLOAD: bad contract address"); @@ -54,25 +61,68 @@ Note Opcodes::UTXO_SLOAD(UTXOStateVar* utxo_state_var, template template -void Opcodes::UTXO_NULL(UTXOStateVar* utxo_state_var, Note& note) +std::vector Opcodes::UTXO_SLOAD(UTXOSetStateVar* utxo_set_state_var, + size_t const& num_notes, + typename Note::NotePreimage const& advice) +{ + auto& oracle = utxo_set_state_var->exec_ctx->oracle; + + typename CT::grumpkin_point& storage_slot_point = utxo_set_state_var->storage_slot_point; + + // Retrieve multiple UTXO witness datum's from the DB: + std::vector> utxo_data = + oracle.template get_utxo_sload_data(storage_slot_point, num_notes, advice); + + // Rely on the oracle to pad the data set with dummies, if there aren't enough notes in the DB. + ASSERT(utxo_data.size() == num_notes); + + std::vector new_notes; + + for (size_t i = 0; i < num_notes; i++) { + auto& utxo_datum = utxo_data[i]; + Note new_note{ utxo_set_state_var, utxo_datum.preimage }; + Note advice_note{ utxo_set_state_var, advice }; + + new_note.constrain_against_advice(advice_note); + + info("calculated commitment: ", new_note.get_commitment()); + info("retrieved commitment: ", utxo_datum.commitment); + // TODO: hard-code or calculate the correct commitment in the FakeDB stub, so that the returned data passes this + // check. + new_note.get_commitment().assert_equal(utxo_datum.commitment, "UTXO_SLOAD: bad commitment"); + + oracle.get_contract_address().assert_equal(utxo_datum.contract_address, "UTXO_SLOAD: bad contract address"); + + // TODO within this function: + // - Merkle Membership Check using the contract_address, utxo_datum.{sibling_path, leaf_index, + // old_private_data_tree_root} + + new_notes.push_back(new_note); + } + + return new_notes; +}; + +template +template +void Opcodes::UTXO_NULL(StateVar* state_var, Note& note) { typename CT::fr nullifier = note.compute_nullifier(); - auto& exec_ctx = utxo_state_var->exec_ctx; + auto& exec_ctx = state_var->exec_ctx; exec_ctx->new_nullifiers.push_back(nullifier); }; template template -void Opcodes::UTXO_SSTORE(UTXOStateVar* utxo_state_var, - typename Note::NotePreimage new_note_preimage) +void Opcodes::UTXO_SSTORE(StateVar* state_var, typename Note::NotePreimage new_note_preimage) { - auto& exec_ctx = utxo_state_var->exec_ctx; + auto& exec_ctx = state_var->exec_ctx; // Make a shared pointer, so we don't end up with a dangling pointer in the exec_ctx when this `new_note` // immediately goes out of scope. - std::shared_ptr new_note = std::make_shared(utxo_state_var, new_note_preimage); + std::shared_ptr new_note = std::make_shared(state_var, new_note_preimage); exec_ctx->new_notes.push_back(new_note); }; diff --git a/circuits/src/aztec3/circuits/apps/oracle_wrapper.hpp b/circuits/src/aztec3/circuits/apps/oracle_wrapper.hpp index d00c0d1941e..254ec7e9e08 100644 --- a/circuits/src/aztec3/circuits/apps/oracle_wrapper.hpp +++ b/circuits/src/aztec3/circuits/apps/oracle_wrapper.hpp @@ -1,8 +1,9 @@ #pragma once #include -#include #include +#include + #include #include #include @@ -72,16 +73,6 @@ template class OracleWrapperInterface { return plonk::stdlib::types::to_ct(composer, oracle.generate_random_element()); } - std::pair, PrivateStateNotePreimage> - get_private_state_note_preimages_for_subtraction(fr const& storage_slot, address const& owner, fr const& subtrahend) - { - std::pair, PrivateStateNotePreimage> native_preimages = - oracle.get_private_state_note_preimages_for_subtraction( - storage_slot.get_value(), NT::address(owner.to_field().get_value()), subtrahend.get_value()); - return std::make_pair(native_preimages.first.to_circuit_type(composer), - native_preimages.second.to_circuit_type(composer)); - } - template auto get_utxo_sload_datum(grumpkin_point const& storage_slot_point, NotePreimage const& advice) { @@ -94,6 +85,22 @@ template class OracleWrapperInterface { return native_utxo_sload_datum.to_circuit_type(composer); } + template + auto get_utxo_sload_data(grumpkin_point const& storage_slot_point, + size_t const& num_notes, + NotePreimage const& advice) + { + auto native_storage_slot_point = plonk::stdlib::types::to_nt(storage_slot_point); + + auto native_advice = advice.template to_native_type(); + + auto native_utxo_sload_data = oracle.get_utxo_sload_data(native_storage_slot_point, num_notes, native_advice); + + auto to_circuit_type = [&](auto& e) { return e.to_circuit_type(composer); }; + + return map(native_utxo_sload_data, to_circuit_type); + } + private: std::optional> call_context; std::optional msg_sender_private_key; diff --git a/circuits/src/aztec3/circuits/apps/private_state.test.cpp b/circuits/src/aztec3/circuits/apps/private_state.test.cpp index e9304ccc511..7d8859991ea 100644 --- a/circuits/src/aztec3/circuits/apps/private_state.test.cpp +++ b/circuits/src/aztec3/circuits/apps/private_state.test.cpp @@ -1,119 +1,123 @@ -#include "index.hpp" +// #include "index.hpp" -#include -#include -#include -// #include -#include -// #include -// #include -// #include +// #include +// #include +// #include +// // #include +// #include +// // #include +// // #include +// // #include + +// namespace aztec3::circuits::apps { + +// namespace { +// using TurboComposer = plonk::stdlib::types::turbo::Composer; +// using CT = plonk::stdlib::types::CircuitTypes; +// using NT = plonk::stdlib::types::NativeTypes; +// // using plonk::stdlib::pedersen; +// } // namespace -namespace aztec3::circuits::apps { +// class private_state_tests : public ::testing::Test {}; -namespace { -using TurboComposer = plonk::stdlib::types::turbo::Composer; -using CT = plonk::stdlib::types::CircuitTypes; -using NT = plonk::stdlib::types::NativeTypes; -// using plonk::stdlib::pedersen; -} // namespace +// // TEST(private_state_tests, test_native_private_state) +// // { +// // StateFactory state_factory("MyContract"); +// // PrivateStateVar x = state_factory.declare_private_state_var("x"); -class private_state_tests : public ::testing::Test {}; +// // PrivateStateVar native_private_state = PrivateStateVar(x); -// TEST(private_state_tests, test_native_private_state) -// { -// StateFactory state_factory("MyContract"); -// PrivateStateVar x = state_factory.declare_private_state_var("x"); +// // auto buffer = to_buffer(native_private_state); -// PrivateStateVar native_private_state = PrivateStateVar(x); +// // auto native_private_state_2 = from_buffer>(buffer.data()); -// auto buffer = to_buffer(native_private_state); +// // EXPECT_EQ(native_private_state, native_private_state_2); +// // } -// auto native_private_state_2 = from_buffer>(buffer.data()); +// // TEST(private_state_tests, test_create_private_state) +// // { +// // StateFactory state_factory("MyContract"); -// EXPECT_EQ(native_private_state, native_private_state_2); -// } +// // state_factory.declare_private_state_var("balances", { "asset_id", "owner" }); -// TEST(private_state_tests, test_create_private_state) -// { -// StateFactory state_factory("MyContract"); +// // state_factory.declare_private_state_var("x"); -// state_factory.declare_private_state_var("balances", { "asset_id", "owner" }); +// // // info("state_factory: ", state_factory); +// // } -// state_factory.declare_private_state_var("x"); +// // TEST(private_state_tests, test_native_private_state_note_preimage) +// // { +// // StateFactory state_factory("MyContract"); +// // PrivateStateVar x = state_factory.declare_private_state_var("x"); -// // info("state_factory: ", state_factory); -// } +// // PrivateStateNotePreimage native_preimage = { +// // .value = 2, +// // .owner = 3, +// // .creator_address = NT::address(4), +// // .salt = 5, +// // .nonce = 6, +// // .memo = 7, +// // }; -// TEST(private_state_tests, test_native_private_state_note_preimage) -// { -// StateFactory state_factory("MyContract"); -// PrivateStateVar x = state_factory.declare_private_state_var("x"); +// // auto buffer = to_buffer(native_preimage); -// PrivateStateNotePreimage native_preimage = { -// .value = 2, -// .owner = 3, -// .creator_address = NT::address(4), -// .salt = 5, -// .nonce = 6, -// .memo = 7, -// }; +// // auto native_preimage_2 = from_buffer>(buffer.data()); -// auto buffer = to_buffer(native_preimage); +// // EXPECT_EQ(native_preimage, native_preimage_2); +// // } -// auto native_preimage_2 = from_buffer>(buffer.data()); +// // TEST(private_state_tests, test_native_private_state_note_preimage_mapping) +// // { +// // StateFactory state_factory("MyContract"); +// // PrivateStateVar x = state_factory.declare_private_state_var("x", { "mapping_key_name_1", +// "mapping_key_name_2" +// // }); -// EXPECT_EQ(native_preimage, native_preimage_2); -// } +// // PrivateStateNotePreimage native_preimage = { +// // .mapping_key_values_by_key_name = std::map>({ { "mapping_key_name_2", 5 } +// }), +// // .value = 2, +// // .owner = 3, +// // .creator_address = NT::address(4), +// // .salt = 5, +// // .nonce = 6, +// // .memo = 7, +// // }; -// TEST(private_state_tests, test_native_private_state_note_preimage_mapping) -// { -// StateFactory state_factory("MyContract"); -// PrivateStateVar x = state_factory.declare_private_state_var("x", { "mapping_key_name_1", "mapping_key_name_2" -// }); +// // auto buffer = to_buffer(native_preimage); -// PrivateStateNotePreimage native_preimage = { -// .mapping_key_values_by_key_name = std::map>({ { "mapping_key_name_2", 5 } }), -// .value = 2, -// .owner = 3, -// .creator_address = NT::address(4), -// .salt = 5, -// .nonce = 6, -// .memo = 7, -// }; +// // auto native_preimage_2 = from_buffer>(buffer.data()); -// auto buffer = to_buffer(native_preimage); +// // EXPECT_EQ(native_preimage, native_preimage_2); +// // } -// auto native_preimage_2 = from_buffer>(buffer.data()); +// // TEST(private_state_tests, test_native_private_state_note_mapping) +// // { +// // StateFactory state_factory("MyContract"); +// // PrivateStateVar x = state_factory.declare_private_state_var("x", { "mapping_key_name_1", +// "mapping_key_name_2" +// // }); -// EXPECT_EQ(native_preimage, native_preimage_2); -// } +// // PrivateStateNotePreimage private_state_preimage = { +// // .mapping_key_values_by_key_name = std::map>({ { "mapping_key_name_2", 5 } +// }), +// // .value = 2, +// // .owner = 3, +// // .creator_address = NT::address(4), +// // .salt = 5, +// // .nonce = 6, +// // .memo = 7, +// // }; -// TEST(private_state_tests, test_native_private_state_note_mapping) -// { -// StateFactory state_factory("MyContract"); -// PrivateStateVar x = state_factory.declare_private_state_var("x", { "mapping_key_name_1", "mapping_key_name_2" -// }); +// // PrivateStateNote private_state_note = PrivateStateNote(x, private_state_preimage); -// PrivateStateNotePreimage private_state_preimage = { -// .mapping_key_values_by_key_name = std::map>({ { "mapping_key_name_2", 5 } }), -// .value = 2, -// .owner = 3, -// .creator_address = NT::address(4), -// .salt = 5, -// .nonce = 6, -// .memo = 7, -// }; +// // auto buffer = to_buffer(private_state_note); -// PrivateStateNote private_state_note = PrivateStateNote(x, private_state_preimage); +// // auto private_state_note_2 = from_buffer>(buffer.data()); -// auto buffer = to_buffer(private_state_note); +// // EXPECT_EQ(private_state_note, private_state_note_2); +// // } -// auto private_state_note_2 = from_buffer>(buffer.data()); +// /// TODO: figure out how to catch and test errors in gtest. -// EXPECT_EQ(private_state_note, private_state_note_2); -// } - -/// TODO: figure out how to catch and test errors in gtest. - -} // namespace aztec3::circuits::apps \ No newline at end of file +// } // namespace aztec3::circuits::apps \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/private_state_note.hpp b/circuits/src/aztec3/circuits/apps/private_state_note.hpp deleted file mode 100644 index 1ebcf6a88dc..00000000000 --- a/circuits/src/aztec3/circuits/apps/private_state_note.hpp +++ /dev/null @@ -1,141 +0,0 @@ -#pragma once -#include "nullifier_preimage.hpp" -#include -#include - -namespace aztec3::circuits::apps { - -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; - -template class PrivateStateVar; -template struct PrivateStateNotePreimage; - -template class PrivateStateNote { - public: - typedef CircuitTypes CT; - typedef typename CT::fr fr; - typedef typename CT::grumpkin_point grumpkin_point; - typedef typename CT::address address; - typedef typename CT::boolean boolean; - - PrivateStateVar& private_state_var; - PrivateStateNotePreimage preimage; - - bool is_partial = false; - - PrivateStateNote(PrivateStateVar& private_state_var, - PrivateStateNotePreimage preimage, - bool commit_on_init = false); - - bool operator==(PrivateStateNote const&) const = default; - - fr get_commitment() const - { - if (!commitment) { - throw_or_abort("No commitment exists for this note. Are you sure you haven't accidentally created a " - "partial commitment? Make sure to populate all preimage values."); - } - return *commitment; - }; - - grumpkin_point get_partial_commitment() const - { - if (!partial_commitment) { - throw_or_abort( - "No partial_commitment exists for this note. Are you sure you haven't accidentally created a " - "complete commitment?"); - } - return *partial_commitment; - }; - - fr get_nullifier() const - { - if (!nullifier) { - throw_or_abort("No nullifier exists for this note yet. Call compute_nullifier() first."); - } - return *nullifier; - }; - - fr compute_commitment() const; - - grumpkin_point compute_partial_commitment() const; - - std::pair> compute_nullifier(fr const& owner_private_key); - - static fr compute_nullifier(fr const& commitment, - fr const& owner_private_key, - boolean const& is_dummy_commitment = false); - - static fr compute_dummy_nullifier(fr const& dummy_commitment, fr const& owner_private_key); - - private: - bool check_if_partial() const; - - std::optional partial_commitment; - std::optional commitment; - std::optional nullifier; - std::optional> nullifier_preimage; -}; - -// // template PrivateStateNote from_buffer(B const& buffer, size_t offset = 0) -// // { -// // using serialize::read; -// // auto ptr = (uint8_t const*)&buffer[offset]; - -// // PrivateStateVar private_state_var; -// // PrivateStateNotePreimage preimage; - -// // read(ptr, private_state_var); -// // read(ptr, preimage); - -// // PrivateStateNote private_state_note = PrivateStateNote(private_state_var, preimage); - -// // return private_state_note; -// // }; - -// template void read(uint8_t const*& it, PrivateStateNote& note) -// { -// using serialize::read; - -// read(it, note.private_state_var); -// read(it, note.preimage); -// read(it, note.is_partial); -// read(it, note.partial_commitment); -// read(it, note.commitment); -// read(it, note.nullifier); -// }; - -// template -// void write(std::vector& buf, PrivateStateNote const& note) -// { -// using serialize::write; - -// write(buf, note.private_state_var); -// write(buf, note.preimage); -// write(buf, note.is_partial); -// write(buf, note.partial_commitment); -// write(buf, note.commitment); -// write(buf, note.nullifier); -// }; - -// template -// std::ostream& operator<<(std::ostream& os, PrivateStateNote const& note) -// { -// return os << "private_state_var: " << note.private_state_var << "\n" -// << "preimage: " << note.preimage << "\n" -// << "is_partial: " << note.is_partial << "\n" -// << "partial_commitment: " << note.partial_commitment << "\n" -// << "commitment: " << note.commitment << "\n" -// << "nullifier: " << note.nullifier << "\n"; -// } - -} // namespace aztec3::circuits::apps - -// Importing in this way (rather than explicit instantiation of a template class at the bottom of a .cpp file) preserves -// the following: -// - We retain implicit instantiation of templates, meaning we can pick and choose (with static_assert) which class -// methods support native, -// circuit or both types. -// - We don't implement method definitions in this file, to avoid a circular dependency with state_factory.hpp. -#include "private_state_note.tpp" \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/private_state_note.tpp b/circuits/src/aztec3/circuits/apps/private_state_note.tpp deleted file mode 100644 index 4186779e99a..00000000000 --- a/circuits/src/aztec3/circuits/apps/private_state_note.tpp +++ /dev/null @@ -1,234 +0,0 @@ -// TODO: remove unused inclusions -// #include "private_state_note.hpp" -#include "oracle_wrapper.hpp" -#include "private_state_var.hpp" -#include "private_state_note_preimage.hpp" -#include "plonk/composer/turbo_composer.hpp" - -#include -#include -#include -#include -#include -#include -#include - -namespace aztec3::circuits::apps { - -namespace { -using aztec3::GeneratorIndex; -using crypto::pedersen::generator_index_t; -using plonk::stdlib::witness_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; -} // namespace - -template -PrivateStateNote::PrivateStateNote(PrivateStateVar& private_state_var, - PrivateStateNotePreimage preimage, - bool commit_on_init) - : private_state_var(private_state_var) - , preimage(preimage) - , is_partial(check_if_partial()) -{ - if (commit_on_init) { - if (is_partial) { - partial_commitment = compute_partial_commitment(); - } else { - commitment = compute_commitment(); - } - } -} - -template bool PrivateStateNote::check_if_partial() const -{ - const auto& [start_slot, storage_slot_point, value, owner, creator_address, salt, nonce, memo, _] = preimage; - - if (!value || !owner || !creator_address || !salt || !nonce || !memo) { - return true; - } - if (private_state_var.is_partial_slot) { - return true; - } - return false; -} - -template typename CircuitTypes::fr PrivateStateNote::compute_commitment() const -{ - if (commitment.has_value()) { - return *commitment; - } - - grumpkin_point storage_slot_point = private_state_var.storage_slot_point; - - std::vector inputs; - std::vector generators; - - auto gen_pair_address = [&](std::optional
const& input, size_t const hash_sub_index) { - if (!input) { - throw_or_abort("Cannot commit to a partial preimage. Call compute_partial_commitment instead, or complete " - "the preimage."); - } - return std::make_pair((*input).to_field(), generator_index_t({ GeneratorIndex::COMMITMENT, hash_sub_index })); - }; - - auto gen_pair_fr = [&](std::optional const& input, size_t const hash_sub_index) { - if (!input) { - throw_or_abort("Cannot commit to a partial preimage. Call compute_partial_commitment instead, or complete " - "the preimage."); - } - return std::make_pair(*input, generator_index_t({ GeneratorIndex::COMMITMENT, hash_sub_index })); - }; - - const auto& [start_slot, - mapping_key_values_by_key_name, - value, - owner, - creator_address, - salt, - nonce, - memo, - is_dummy] = preimage; - - const auto commitment_point = - storage_slot_point + - CT::commit( - { gen_pair_fr(value, PrivateStateNoteGeneratorIndex::VALUE), - gen_pair_address(owner, PrivateStateNoteGeneratorIndex::OWNER), - gen_pair_address(creator_address, PrivateStateNoteGeneratorIndex::CREATOR), - gen_pair_fr(salt, PrivateStateNoteGeneratorIndex::SALT), - gen_pair_fr(nonce, PrivateStateNoteGeneratorIndex::NONCE), - gen_pair_fr(memo, PrivateStateNoteGeneratorIndex::MEMO), - std::make_pair( - is_dummy, generator_index_t({ GeneratorIndex::COMMITMENT, PrivateStateNoteGeneratorIndex::IS_DUMMY })) - - }); - - return commitment_point.x; -} - -template -typename CircuitTypes::grumpkin_point PrivateStateNote::compute_partial_commitment() const -{ - if (partial_commitment.has_value()) { - info( - "WARNING: you've already computed a partial commitment for this note. Now, you might have since changed " - "the preimage and you want to update the partial commitment, and that's ok, so we won't throw an error " - "here. But if that's not the case, you should call get_partial_commitment() instead, to save constraints."); - } - - grumpkin_point storage_slot_point = private_state_var.storage_slot_point; - - std::vector inputs; - std::vector generators; - - auto gen_pair_address = [&](std::optional
const& input, size_t const hash_sub_index) { - return input ? std::make_pair((*input).to_field(), - generator_index_t({ GeneratorIndex::COMMITMENT, hash_sub_index })) - : std::make_pair(fr(1), - generator_index_t({ GeneratorIndex::COMMITMENT_PLACEHOLDER, hash_sub_index })); - }; - - auto gen_pair_fr = [&](std::optional const& input, size_t const hash_sub_index) { - return input ? std::make_pair(*input, generator_index_t({ GeneratorIndex::COMMITMENT, hash_sub_index })) - : std::make_pair(fr(1), - generator_index_t({ GeneratorIndex::COMMITMENT_PLACEHOLDER, hash_sub_index })); - }; - - const auto& [start_slot, - mapping_key_values_by_key_name, - value, - owner, - creator_address, - salt, - nonce, - memo, - is_dummy] = preimage; - - return storage_slot_point + - CT::commit({ gen_pair_fr(value, PrivateStateNoteGeneratorIndex::VALUE), - gen_pair_address(owner, PrivateStateNoteGeneratorIndex::OWNER), - gen_pair_address(creator_address, PrivateStateNoteGeneratorIndex::CREATOR), - gen_pair_fr(salt, PrivateStateNoteGeneratorIndex::SALT), - gen_pair_fr(nonce, PrivateStateNoteGeneratorIndex::NONCE), - gen_pair_fr(memo, PrivateStateNoteGeneratorIndex::MEMO), - std::make_pair( - is_dummy, - generator_index_t({ GeneratorIndex::COMMITMENT, PrivateStateNoteGeneratorIndex::IS_DUMMY })) - - }); -} - -template -std::pair::fr, NullifierPreimage>> PrivateStateNote< - Composer>::compute_nullifier(fr const& owner_private_key) -{ - if (is_partial) { - throw_or_abort("Can't nullify a partial note."); - } - if (!commitment) { - throw_or_abort("Commitment not yet calculated. Call compute_commitment() or change how you initialise this " - "note to include the `commit_on_init` bool."); - } - if (nullifier && nullifier_preimage) { - return std::make_pair(*nullifier, *nullifier_preimage); - } - nullifier = PrivateStateNote::compute_nullifier(*commitment, owner_private_key, preimage.is_dummy); - nullifier_preimage = { - *commitment, - owner_private_key, - preimage.is_dummy, - }; - return std::make_pair(*nullifier, *nullifier_preimage); -}; - -template -typename CircuitTypes::fr PrivateStateNote::compute_nullifier(fr const& commitment, - fr const& owner_private_key, - boolean const& is_dummy_commitment) -{ - /** - * Hashing the private key in this way enables the following use case: - * - A user can demonstrate to a 3rd party that they have spent a note, by providing the - hashed_private_key - * and the note_commitment. The 3rd party can then recalculate the nullifier. This does not reveal the - * underlying private_key to the 3rd party. */ - const grumpkin_point hashed_private_key = CT::grumpkin_group::template fixed_base_scalar_mul<254>( - owner_private_key, GeneratorIndex::NULLIFIER_HASHED_PRIVATE_KEY); - - const std::vector hash_inputs{ - commitment, - hashed_private_key.x, - hashed_private_key.y, - is_dummy_commitment, - }; - - // We compress the hash_inputs with Pedersen, because that's cheaper (constraint-wise) than compressing - // the data directly with Blake2s in the next step. - const fr compressed_inputs = CT::compress(hash_inputs, GeneratorIndex::NULLIFIER); - - // Blake2s hash the compressed result. Without this it's possible to leak info from the pedersen - // compression. - /** E.g. we can extract a representation of the hashed_pk: - * Paraphrasing, if: - * nullifier = note_comm * G1 + hashed_pk * G2 + is_dummy_note * G3 - * Then an observer can derive hashed_pk * G2 = nullifier - note_comm * G1 - is_dummy_note * G3 - * They can derive this for every tx, to link which txs are being sent by the same user. - * Notably, at the point someone withdraws, the observer would be able to connect `hashed_pk * G2` with a - * specific eth address. - */ - auto blake_input = typename CT::byte_array(compressed_inputs); - auto blake_result = CT::blake2s(blake_input); - return fr(blake_result); -}; - -template -typename CircuitTypes::fr PrivateStateNote::compute_dummy_nullifier(fr const& dummy_commitment, - fr const& owner_private_key) -{ - return PrivateStateNote::compute_nullifier(dummy_commitment, owner_private_key, false); -} - -// template class PrivateStateNote; - -} // namespace aztec3::circuits::apps \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/private_state_note_preimage.hpp b/circuits/src/aztec3/circuits/apps/private_state_note_preimage.hpp deleted file mode 100644 index b5a247c70a6..00000000000 --- a/circuits/src/aztec3/circuits/apps/private_state_note_preimage.hpp +++ /dev/null @@ -1,118 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include - -namespace aztec3::circuits::apps { - -using crypto::pedersen::generator_index_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; - -template struct PrivateStateNotePreimage { - typedef typename NCT::fr fr; - typedef typename NCT::grumpkin_point grumpkin_point; - typedef typename NCT::address address; - typedef typename NCT::boolean boolean; - - // No custom constructors so that designated initializers can be used (for readability of test circuits). - - std::optional start_slot; // TODO: remove optionality - std::optional storage_slot_point; // TODO: remove optionality? - - // TODO: MAKE THIS A PAYLOAD LIKE ZEXE????? - std::optional value; - std::optional
owner; - std::optional
creator_address; - std::optional memo; // numerical representation of a string - - std::optional salt; - std::optional nonce; - - boolean is_real; - - bool operator==(PrivateStateNotePreimage const&) const = default; - - template - PrivateStateNotePreimage> to_circuit_type(Composer& composer) const - { - static_assert((std::is_same::value)); - - // Capture the composer: - auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; - - PrivateStateNotePreimage> preimage = { - to_ct(start_slot), - to_ct(storage_slot_point), - to_ct(value), - to_ct(owner), - to_ct(creator_address), - to_ct(memo), - to_ct(salt), - to_ct(nonce), - to_ct(is_real), - }; - - return preimage; - }; - - fr hash() const {} - - PrivateStateNotePreimage utxo_sload_hook(){}; - - PrivateStateNotePreimage utxo_sstore_hook(){ - // maybe call the oracle to generate a salt? But that would require us to pass in the oracle, which feels messy - // / wrong... - // We'd also need to generate a nonce... - }; -}; - -template void read(uint8_t const*& it, PrivateStateNotePreimage& preimage) -{ - using serialize::read; - - read(it, preimage.start_slot); - read(it, preimage.storage_slot_point); - read(it, preimage.value); - read(it, preimage.owner); - read(it, preimage.creator_address); - read(it, preimage.memo); - read(it, preimage.salt); - read(it, preimage.nonce); - read(it, preimage.is_real); -}; - -template void write(std::vector& buf, PrivateStateNotePreimage const& preimage) -{ - using serialize::write; - - write(buf, preimage.start_slot); - write(buf, preimage.storage_slot_point); - write(buf, preimage.value); - write(buf, preimage.owner); - write(buf, preimage.creator_address); - write(buf, preimage.memo); - write(buf, preimage.salt); - write(buf, preimage.nonce); - write(buf, preimage.is_real); -}; - -template std::ostream& operator<<(std::ostream& os, PrivateStateNotePreimage const& preimage) -{ - return os << "start_slot: " << preimage.start_slot << "\n" - << "storage_slot_point: " << preimage.storage_slot_point << "\n" - << "value: " << preimage.value << "\n" - << "owner: " << preimage.owner << "\n" - << "creator_address: " << preimage.creator_address << "\n" - << "memo: " << preimage.memo << "\n" - << "salt: " << preimage.salt << "\n" - << "nonce: " << preimage.nonce << "\n" - << "is_real: " << preimage.is_real << "\n"; -} - -// template using MappingKeyValues = std::map>; - -} // namespace aztec3::circuits::apps \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/private_state_operand.hpp b/circuits/src/aztec3/circuits/apps/private_state_operand.hpp deleted file mode 100644 index 7c171c6f914..00000000000 --- a/circuits/src/aztec3/circuits/apps/private_state_operand.hpp +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include - -namespace aztec3::circuits::apps { - -using crypto::pedersen::generator_index_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; - -template struct PrivateStateOperand { - typedef typename NCT::fr fr; - typedef typename NCT::address address; - - fr value; - address owner; - std::optional
creator_address; - std::optional memo; // numerical representation of a string - - bool operator==(PrivateStateOperand const&) const = default; - - template PrivateStateOperand> to_circuit_type(Composer& composer) const - { - static_assert((std::is_same::value)); - - // Capture the composer: - auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; - - PrivateStateOperand> preimage = { - to_ct(value), - to_ct(owner), - to_ct(creator_address), - to_ct(memo), - }; - - return preimage; - }; -}; - -} // namespace aztec3::circuits::apps \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/private_state_var.hpp b/circuits/src/aztec3/circuits/apps/private_state_var.hpp deleted file mode 100644 index b23549d2066..00000000000 --- a/circuits/src/aztec3/circuits/apps/private_state_var.hpp +++ /dev/null @@ -1,141 +0,0 @@ -#pragma once -#include "private_state_note.hpp" -#include "private_state_note_preimage.hpp" -#include "private_state_operand.hpp" - -#include - -#include -#include - -namespace aztec3::circuits::apps { - -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; - -template class FunctionExecutionContext; - -template class PrivateStateVar { - public: - typedef CircuitTypes CT; - typedef typename CT::fr fr; - typedef typename CT::address address; - typedef typename CT::grumpkin_point grumpkin_point; - - FunctionExecutionContext* - exec_ctx; // Pointer, because PrivateStateVar can't hold a reference (because it gets initialised as a member of - // a map within the Contract class, so might not be passed data upon initialisation) - - PrivateStateType private_state_type; - std::string name; - fr start_slot; - grumpkin_point storage_slot_point; /// TODO: make this std::optional (since mapping vars won't have this (only - /// specific mapping values will))? - - // A mapping var (in particular) can point to many private_states: - std::map> private_states; - - bool is_mapping = false; - std::optional> mapping_key_names = std::nullopt; - - bool is_partial_slot = false; - - PrivateStateVar(){}; - - PrivateStateVar(PrivateStateVar const& private_state_var) - : exec_ctx(private_state_var.exec_ctx) - , private_state_type(private_state_var.private_state_type) - , name(private_state_var.name) - , start_slot(private_state_var.start_slot) - , storage_slot_point(private_state_var.storage_slot_point) - , is_mapping(private_state_var.is_mapping) - , mapping_key_names(private_state_var.mapping_key_names) - , is_partial_slot(private_state_var.is_partial_slot){}; - - // For initialising a basic fr state: - PrivateStateVar(FunctionExecutionContext* exec_ctx, - PrivateStateType const& private_state_type, - std::string const& name, - fr const& start_slot) - : exec_ctx(exec_ctx) - , private_state_type(private_state_type) - , name(name) - , start_slot(start_slot) - { - storage_slot_point = compute_start_slot_point(); - }; - - // For initialising a mapping var: - PrivateStateVar(FunctionExecutionContext* exec_ctx, - PrivateStateType const& private_state_type, - std::string const& name, - fr const start_slot, - std::vector const& mapping_key_names) - : exec_ctx(exec_ctx) - , private_state_type(private_state_type) - , name(name) - , start_slot(start_slot) - , is_mapping(mapping_key_names.size() > 0) - , mapping_key_names(mapping_key_names.size() > 0 ? std::make_optional(mapping_key_names) : std::nullopt) - , is_partial_slot(true) - { - if (mapping_key_names.size() == 0) { - throw_or_abort("Error. Empty mapping_key_names argument. Try calling the other constructor if you don't " - "want to initialise a mapping state."); - } - }; - - bool operator==(PrivateStateVar const&) const = default; - - PrivateStateVar& at(std::optional const& key) { return at(std::vector>{ key }); }; - - PrivateStateVar& at(std::vector> const& keys); - - std::vector get_mapping_key_names() const; - - size_t get_index_of_mapping_key_name(std::string const& mapping_key_name) const; - - PrivateStateNote new_note(PrivateStateNotePreimage& preimage); - - // Arithmetic on private states: - void add(PrivateStateOperand const& operand); - - void subtract(PrivateStateOperand const& operant); - - static std::tuple compute_slot_point_at_mapping_keys( - NativeTypes::fr const& start_slot, std::vector> const& keys); - - std::tuple compute_slot_point_at_mapping_keys(std::vector> const& keys); - - private: - // For initialising an fr state from within a mapping: - PrivateStateVar(FunctionExecutionContext* exec_ctx, - PrivateStateType const& private_state_type, - std::string const& name, - fr const& start_slot, - grumpkin_point const& storage_slot_point, - bool const& is_partial_slot) - : exec_ctx(exec_ctx) - , private_state_type(private_state_type) - , name(name) - , start_slot(start_slot) - , storage_slot_point(storage_slot_point) - , is_partial_slot(is_partial_slot){}; - - size_t op_count = 0; - - grumpkin_point compute_start_slot_point(); - void arithmetic_checks(); - void validate_operand(PrivateStateOperand const& operand) const; -}; - -} // namespace aztec3::circuits::apps - -// Importing in this way (rather than explicit instantiation of a template class at the bottom of a .cpp file) preserves -// the following: -// - We retain implicit instantiation of templates, meaning we can pick and choose (with static_assert) which class -// methods support native, -// circuit or both types. -// - We don't implement method definitions in this file, to avoid a circular dependency with -// function_execution_context.hpp. -#include "private_state_var.tpp" diff --git a/circuits/src/aztec3/circuits/apps/private_state_var.tpp b/circuits/src/aztec3/circuits/apps/private_state_var.tpp deleted file mode 100644 index 2f248a3495c..00000000000 --- a/circuits/src/aztec3/circuits/apps/private_state_var.tpp +++ /dev/null @@ -1,291 +0,0 @@ -#pragma once - -#include "oracle_wrapper.hpp" -#include "private_state_note.hpp" -#include "private_state_note_preimage.hpp" -#include "private_state_operand.hpp" - -#include -#include - -#include - -#include - -#include -#include -#include -#include - -namespace aztec3::circuits::apps { - -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; - -// Fr: |> start_slot * A -// M1: start_slot * A + mk1 * B |> -// M2: start_slot * A + mk1 * B + mk2 * C |> -template -typename CircuitTypes::grumpkin_point PrivateStateVar::compute_start_slot_point() -{ - return CT::commit({ start_slot }, { StorageSlotGeneratorIndex::MAPPING_SLOT }); -} - -template -std::tuple PrivateStateVar::compute_slot_point_at_mapping_keys( - NativeTypes::fr const& start_slot, std::vector> const& keys) -{ - bool is_partial_slot = false; - - std::vector> input_pairs; - - input_pairs.push_back(std::make_pair(start_slot, - generator_index_t({ StorageSlotGeneratorIndex::MAPPING_SLOT, - 0 }))); // hash_sub_index 0 is reserved for the start_slot. - - for (size_t i = 0; i < keys.size(); ++i) { - if (keys[i]) { - input_pairs.push_back( - std::make_pair(*keys[i], - generator_index_t({ StorageSlotGeneratorIndex::MAPPING_SLOT, - i + 1 }))); // hash_sub_index 0 is reserved for the start_slot. - } else { - // If this mapping key has no mapping_key_value (std::nullopt), then we must be partially committing and - // omitting this mapping key from that partial commitment. - // So use a placeholder generator for this mapping key, to signify "this mapping key is missing". - // Note: we can't just commit to a value of `0` for this mapping key, since `0` is a valid value to - // commit to, and so "missing" is distinguished as follows. - input_pairs.push_back(std::make_pair( - NativeTypes::fr(1), generator_index_t({ StorageSlotGeneratorIndex::MAPPING_SLOT_PLACEHOLDER, i + 1 }))); - } - } - - return std::make_tuple(NativeTypes::commit(input_pairs), is_partial_slot); -} - -template -std::tuple::grumpkin_point, bool> PrivateStateVar< - Composer>::compute_slot_point_at_mapping_keys(std::vector> const& keys) -{ - bool is_partial_slot = false; - - std::vector> input_pairs; - - input_pairs.push_back(std::make_pair(start_slot, - generator_index_t({ StorageSlotGeneratorIndex::MAPPING_SLOT, - 0 }))); // hash_sub_index 0 is reserved for the start_slot. - - for (size_t i = 0; i < keys.size(); ++i) { - if (keys[i]) { - input_pairs.push_back( - std::make_pair(*keys[i], - generator_index_t({ StorageSlotGeneratorIndex::MAPPING_SLOT, - i + 1 }))); // hash_sub_index 0 is reserved for the start_slot. - } else { - // If this mapping key has no mapping_key_value (std::nullopt), then we must be partially committing and - // omitting this mapping key from that partial commitment. - // So use a placeholder generator for this mapping key, to signify "this mapping key is missing". - // Note: we can't just commit to a value of `0` for this mapping key, since `0` is a valid value to - // commit to, and so "missing" is distinguished as follows. - input_pairs.push_back(std::make_pair( - fr(1), generator_index_t({ StorageSlotGeneratorIndex::MAPPING_SLOT_PLACEHOLDER, i + 1 }))); - } - } - - return std::make_tuple(CT::commit(input_pairs), is_partial_slot); -} - -template -PrivateStateVar& PrivateStateVar::at(std::vector> const& keys) -{ - if (!is_mapping) { - throw_or_abort("var is not a mapping - cannot call `at()`"); - } - - if (keys.size() != (*mapping_key_names).size()) { - throw_or_abort("Need to provide a vector of length equal to this mapping's # keys, even if some are keys are " - "intentionally blank (std::optional, for partially-committing"); - } - - // First calculate natively and check to see if we've already calculated this state's slot and stored it in the - // cache, so we don't create unnecessary circuit gates: - std::vector> native_keys; - for (const auto& key : keys) { - std::optional native_key; - if (!key) { - native_key = std::nullopt; - } else { - native_key = NativeTypes::fr((*key).get_value()); - } - native_keys.push_back(native_key); - } - - bool is_partial_slot; - NativeTypes::grumpkin_point native_new_slot_point; - std::tie(native_new_slot_point, is_partial_slot) = - PrivateStateVar::compute_slot_point_at_mapping_keys(start_slot.get_value(), native_keys); - NativeTypes::fr native_lookup = native_new_slot_point.x; - - // Check cache - if (private_states.contains(native_lookup)) { - return private_states[native_lookup]; - } - - // Create gates: - grumpkin_point new_slot_point; - std::tie(new_slot_point, is_partial_slot) = compute_slot_point_at_mapping_keys(keys); - NativeTypes::fr lookup = new_slot_point.x.get_value(); - - if (lookup != native_lookup) { - throw_or_abort("Expected lookup calcs to be equal!"); - } - - PrivateStateVar new_state = - PrivateStateVar(exec_ctx, private_state_type, name, start_slot, new_slot_point, is_partial_slot); - - private_states[lookup] = new_state; - - return private_states[lookup]; -} - -template std::vector PrivateStateVar::get_mapping_key_names() const -{ - if (!mapping_key_names) { - throw_or_abort("Not a mapping."); - } - return *mapping_key_names; -} - -template -size_t PrivateStateVar::get_index_of_mapping_key_name(std::string const& mapping_key_name) const -{ - if (mapping_key_names) { - auto begin = (*mapping_key_names).begin(); - auto end = (*mapping_key_names).end(); - auto itr = std::find(begin, end, mapping_key_name); - if (itr != end) { - return size_t(itr - begin); - } else { - throw_or_abort("mapping key name not found"); - } - } else { - throw_or_abort("This private state is not a mapping."); - } -} - -template void PrivateStateVar::arithmetic_checks() -{ - if (private_state_type == WHOLE) { - throw_or_abort("Code not yet written to support 'whole' private states"); - } - - if (is_partial_slot) { - throw_or_abort("Arithmetic on a partial state is not supported"); - } - - if (op_count > 0) { - throw_or_abort("Cannot perform more than one operation on this state."); - } - ++op_count; -} - -template -void PrivateStateVar::validate_operand(PrivateStateOperand const& operand) const -{ - if (operand.creator_address) { - auto& oracle = exec_ctx->oracle; - const auto& msg_sender = oracle.get_msg_sender(); - (*operand.creator_address).assert_is_in_set({ msg_sender, address(0) }); - } -} - -// TODO: move this to a new PrivateState class. -template -void PrivateStateVar::add(PrivateStateOperand> const& operand) -{ - arithmetic_checks(); - validate_operand(operand); - - auto& oracle = exec_ctx->oracle; - auto& composer = oracle.composer; - - PrivateStateNotePreimage new_note_preimage = PrivateStateNotePreimage{ - .start_slot = start_slot, - .storage_slot_point = storage_slot_point, - .value = operand.value, - .owner = operand.owner, - .creator_address = operand.creator_address, - .memo = operand.memo, - .salt = oracle.generate_salt(), - // .nonce = // this will be injected by the exec_ctx at 'finalise' - .is_real = plonk::stdlib::types::to_ct(composer, true), - }; - - auto new_note = PrivateStateNote(*this, new_note_preimage); - - exec_ctx->push_new_note(new_note); -} - -template -void PrivateStateVar::subtract(PrivateStateOperand> const& operand) -{ - arithmetic_checks(); - validate_operand(operand); - - // Terminology: difference = minuend - subtrahend - - auto& oracle = exec_ctx->oracle; - auto& composer = oracle.composer; - - const fr& subtrahend = operand.value; - - auto [minuend_preimage_1, minuend_preimage_2] = - oracle.get_private_state_note_preimages_for_subtraction(storage_slot_point.x, operand.owner, subtrahend); - - (*minuend_preimage_1.start_slot).assert_equal(start_slot); - (*minuend_preimage_1.storage_slot_point).assert_equal(storage_slot_point); - // value enforced through the below subtraction. - (*minuend_preimage_1.owner).assert_equal(operand.owner); - // other info about notes being spent is irrelevant. - - (*minuend_preimage_2.start_slot).assert_equal(start_slot); - (*minuend_preimage_2.storage_slot_point).assert_equal(storage_slot_point); - // value enforced through the below subtraction. - (*minuend_preimage_2.owner).assert_equal(operand.owner); - // other info about notes being spent is irrelevant. - - const fr& minuend = *minuend_preimage_1.value + *minuend_preimage_2.value; - - const fr& difference = minuend - subtrahend; /// TODO: prevent underflow - - auto difference_preimage = PrivateStateNotePreimage{ - .start_slot = start_slot, - .storage_slot_point = storage_slot_point, - .value = difference, - .owner = operand.owner, - .creator_address = operand.creator_address, - .memo = operand.memo, - .salt = oracle.generate_salt(), - // .nonce = // this will be injected by the exec_ctx upon `finalise()` - .is_real = plonk::stdlib::types::to_ct(composer, true), - }; - - auto minuend_note_1 = PrivateStateNote(*this, minuend_preimage_1, true); - auto minuend_note_2 = PrivateStateNote(*this, minuend_preimage_2, true); - - fr msg_sender_private_key = oracle.get_msg_sender_private_key(); - auto [minuend_nullifier_1, minuend_nullifier_preimage_1] = minuend_note_1.compute_nullifier(msg_sender_private_key); - auto [minuend_nullifier_2, minuend_nullifier_preimage_2] = minuend_note_2.compute_nullifier(msg_sender_private_key); - - /// TODO: merkle membership proofs for the two minuend notes. - - auto difference_note = PrivateStateNote(*this, difference_preimage); - - exec_ctx->push_new_note(difference_note); - exec_ctx->push_new_nullifier_data(minuend_nullifier_1, minuend_nullifier_preimage_1); - exec_ctx->push_new_nullifier_data(minuend_nullifier_2, minuend_nullifier_preimage_2); -} - -// template class PrivateStateVar; - -}; // namespace aztec3::circuits::apps diff --git a/circuits/src/aztec3/circuits/apps/state_vars/field_state_var.hpp b/circuits/src/aztec3/circuits/apps/state_vars/field_state_var.hpp index cbb59881c53..91fa9536e3a 100644 --- a/circuits/src/aztec3/circuits/apps/state_vars/field_state_var.hpp +++ b/circuits/src/aztec3/circuits/apps/state_vars/field_state_var.hpp @@ -11,6 +11,7 @@ namespace aztec3::circuits::apps::state_vars { using plonk::stdlib::types::CircuitTypes; using plonk::stdlib::types::NativeTypes; +// TODO: we can probably generalise this to be PrimitiveStateVar for any stdlib primitive. template class FieldStateVar : public StateVar { public: typedef CircuitTypes CT; @@ -28,11 +29,11 @@ template class FieldStateVar : public StateVar { FieldStateVar(){}; - // Instantiate a top-level mapping: + // Instantiate a top-level var: FieldStateVar(FunctionExecutionContext* exec_ctx, std::string const& state_var_name, fr const& start_slot) : StateVar(exec_ctx, state_var_name, start_slot){}; - // Instantiate a nested mapping: + // Instantiate a var nested within a container: FieldStateVar(FunctionExecutionContext* exec_ctx, std::string const& state_var_name, grumpkin_point const& storage_slot_point, diff --git a/circuits/src/aztec3/circuits/apps/state_vars/state_var_base.hpp b/circuits/src/aztec3/circuits/apps/state_vars/state_var_base.hpp index c4589d36617..3d83be5b1e6 100644 --- a/circuits/src/aztec3/circuits/apps/state_vars/state_var_base.hpp +++ b/circuits/src/aztec3/circuits/apps/state_vars/state_var_base.hpp @@ -51,23 +51,12 @@ template class StateVar { return *this; } - // StateVar(StateVar const& other) - // { - // this->exec_ctx = other.exec_ctx; - // this->state_var_name = other.state_var_name; - // this->start_slot = other.start_slot; - // this->storage_slot_point = other.storage_slot_point; - // this->level_of_container_nesting = other.level_of_container_nesting; - // this->is_partial_slot = other.is_partial_slot; - // // return *this; - // } - StateVar(){}; // Instantiate a top-level state: StateVar(FunctionExecutionContext* exec_ctx, std::string const& state_var_name); - // Instantiate a nested state: + // Instantiate a state nested within a container: StateVar( FunctionExecutionContext* exec_ctx, std::string const& state_var_name, diff --git a/circuits/src/aztec3/circuits/apps/state_vars/utxo_set_state_var.hpp b/circuits/src/aztec3/circuits/apps/state_vars/utxo_set_state_var.hpp new file mode 100644 index 00000000000..a70adbd47d1 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/state_vars/utxo_set_state_var.hpp @@ -0,0 +1,62 @@ +#pragma once + +#include "state_var_base.hpp" + +// #include "../function_execution_context.hpp" + +#include +#include + +// Forward-declare from this namespace in particular: +namespace aztec3::circuits::apps { +template class FunctionExecutionContext; +} + +namespace aztec3::circuits::apps::state_vars { + +using aztec3::circuits::apps::FunctionExecutionContext; // Don't #include it! + +// template class FunctionExecutionContext; + +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; + +template class UTXOSetStateVar : public StateVar { + public: + typedef CircuitTypes CT; + typedef NativeTypes NT; + typedef typename CT::fr fr; + typedef typename CT::grumpkin_point grumpkin_point; + + typedef typename Note::NotePreimage NotePreimage; + + UTXOSetStateVar(){}; + + // Instantiate a top-level var: + UTXOSetStateVar(FunctionExecutionContext* exec_ctx, std::string const& state_var_name) + : StateVar(exec_ctx, state_var_name){}; + + // Instantiate a var nested within a container: + UTXOSetStateVar(FunctionExecutionContext* exec_ctx, + std::string const& state_var_name, + grumpkin_point const& storage_slot_point, + size_t level_of_container_nesting, + bool is_partial_slot) + : StateVar( + exec_ctx, state_var_name, storage_slot_point, level_of_container_nesting, is_partial_slot){}; + + // bool operator==(UTXOSetStateVar const&) const = default; + + /** + * @param advice - For NotePreimages, we allow 'advice' to be given, so that the correct DB entry is + * chosen. + * E.g. so that the `owner` can be specified. + */ + std::vector get(size_t const& num_notes, NotePreimage const& advice); + + void insert(NotePreimage new_note_preimage); +}; + +} // namespace aztec3::circuits::apps::state_vars + +#include "utxo_set_state_var.tpp" \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/state_vars/utxo_set_state_var.tpp b/circuits/src/aztec3/circuits/apps/state_vars/utxo_set_state_var.tpp new file mode 100644 index 00000000000..850f888d8de --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/state_vars/utxo_set_state_var.tpp @@ -0,0 +1,27 @@ +#pragma once + +#include "../opcodes/opcodes.hpp" + +#include +#include + +namespace { +using aztec3::circuits::apps::opcodes::Opcodes; +} // namespace + +namespace aztec3::circuits::apps::state_vars { + +template +std::vector UTXOSetStateVar::get(size_t const& num_notes, + typename Note::NotePreimage const& advice) +{ + return Opcodes::template UTXO_SLOAD(this, num_notes, advice); +}; + +template +void UTXOSetStateVar::insert(typename Note::NotePreimage new_note_preimage) +{ + return Opcodes::template UTXO_SSTORE(this, new_note_preimage); +}; + +} // namespace aztec3::circuits::apps::state_vars \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp b/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp index 27e05c4954b..393110707ee 100644 --- a/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp +++ b/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp @@ -32,10 +32,11 @@ template class UTXOStateVar : public StateVar UTXOStateVar(){}; + // Instantiate a top-level var: UTXOStateVar(FunctionExecutionContext* exec_ctx, std::string const& state_var_name) : StateVar(exec_ctx, state_var_name){}; - // Instantiate a nested mapping: + // Instantiate a var nested within a container: UTXOStateVar(FunctionExecutionContext* exec_ctx, std::string const& state_var_name, grumpkin_point const& storage_slot_point, diff --git a/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.tpp b/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.tpp index 0638009f4b0..51a99982ba7 100644 --- a/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.tpp +++ b/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.tpp @@ -20,7 +20,7 @@ Note UTXOStateVar::get(typename Note::NotePreimage const& advice template void UTXOStateVar::insert(typename Note::NotePreimage new_note_preimage) { - return Opcodes::UTXO_SSTORE(this, new_note_preimage); + return Opcodes::template UTXO_SSTORE(this, new_note_preimage); }; } // namespace aztec3::circuits::apps::state_vars \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp index 1da867d9257..502e2c032f8 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp @@ -1,92 +1,90 @@ -// #include -// #include -// // #include -// // #include -// // #include -// #include "index.hpp" -// #include "contract.hpp" - -// namespace aztec3::circuits::apps::test_apps::escrow { - -// class escrow_tests : public ::testing::Test {}; - -// TEST(escrow_tests, test_deposit) -// { - -// Composer composer; -// DB db; - -// const NT::address contract_address = 12345; -// const NT::fr msg_sender_private_key = 123456789; -// const NT::address msg_sender = -// NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, -// 0x2ef9f7f09867fd6eULL)); -// const NT::address tx_origin = msg_sender; - -// NativeOracle oracle = NativeOracle(db, contract_address, msg_sender, tx_origin, msg_sender_private_key); -// OracleWrapper oracle_wrapper = OracleWrapper(composer, oracle); - -// FunctionExecutionContext exec_ctx(composer, oracle_wrapper); - -// auto amount = NT::fr(5); -// auto asset_id = NT::fr(1); -// auto memo = NT::fr(999); - -// auto result = deposit(exec_ctx, amount, asset_id, memo); -// info("result: ", result); - -// info("computed witness: ", composer.computed_witness); -// info("witness: ", composer.witness); -// // info("constant variables: ", composer.constant_variables); -// // info("variables: ", composer.variables); -// info("failed?: ", composer.failed); -// info("err: ", composer.err); -// info("n: ", composer.n); -// } - -// TEST(escrow_tests, test_transfer) -// { - -// Composer composer; -// DB db; - -// const NT::address contract_address = 12345; -// const NT::fr msg_sender_private_key = 123456789; -// const NT::address msg_sender = -// NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, -// 0x2ef9f7f09867fd6eULL)); -// const NT::address tx_origin = msg_sender; - -// CallContext call_context = { -// .msg_sender = msg_sender, -// .storage_contract_address = contract_address, -// .tx_origin = msg_sender, -// .is_delegate_call = false, -// .is_static_call = false, -// }; - -// NativeOracle oracle = NativeOracle(db, call_context, msg_sender_private_key); -// OracleWrapper oracle_wrapper = OracleWrapper(composer, oracle); - -// FunctionExecutionContext exec_ctx(composer, oracle_wrapper); - -// auto amount = NT::fr(5); -// auto to = NT::address(657756); -// auto asset_id = NT::fr(1); -// auto memo = NT::fr(999); -// auto reveal_msg_sender_to_recipient = true; -// auto fee = NT::fr(2); - -// transfer(exec_ctx, amount, to, asset_id, memo, reveal_msg_sender_to_recipient, fee); - -// info("computed witness: ", composer.computed_witness); -// info("witness: ", composer.witness); -// // info("constant variables: ", composer.constant_variables); -// // info("variables: ", composer.variables); -// info("failed?: ", composer.failed); -// info("err: ", composer.err); -// info("n: ", composer.n); -// } +#include +#include +// #include +// #include +// #include +#include "index.hpp" +#include "contract.hpp" + +namespace aztec3::circuits::apps::test_apps::escrow { + +class escrow_tests : public ::testing::Test {}; + +TEST(escrow_tests, test_deposit) +{ + + C composer; + DB db; + + const NT::address contract_address = 12345; + const NT::fr msg_sender_private_key = 123456789; + const NT::address msg_sender = + NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); + const NT::address tx_origin = msg_sender; + + NativeOracle oracle = NativeOracle(db, contract_address, msg_sender, tx_origin, msg_sender_private_key); + OracleWrapper oracle_wrapper = OracleWrapper(composer, oracle); + + FunctionExecutionContext exec_ctx(composer, oracle_wrapper); + + auto amount = NT::fr(5); + auto asset_id = NT::fr(1); + auto memo = NT::fr(999); + + auto result = deposit(exec_ctx, amount, asset_id, memo); + info("result: ", result); + + info("computed witness: ", composer.computed_witness); + info("witness: ", composer.witness); + // info("constant variables: ", composer.constant_variables); + // info("variables: ", composer.variables); + info("failed?: ", composer.failed); + info("err: ", composer.err); + info("n: ", composer.n); +} + +TEST(escrow_tests, test_transfer) +{ + + C composer; + DB db; + + const NT::address contract_address = 12345; + const NT::fr msg_sender_private_key = 123456789; + const NT::address msg_sender = + NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); + const NT::address tx_origin = msg_sender; + + CallContext call_context = { + .msg_sender = msg_sender, + .storage_contract_address = contract_address, + .tx_origin = msg_sender, + .is_delegate_call = false, + .is_static_call = false, + }; + + NativeOracle oracle = NativeOracle(db, call_context, msg_sender_private_key); + OracleWrapper oracle_wrapper = OracleWrapper(composer, oracle); + + FunctionExecutionContext exec_ctx(composer, oracle_wrapper); + + auto amount = NT::fr(5); + auto to = NT::address(657756); + auto asset_id = NT::fr(1); + auto memo = NT::fr(999); + auto reveal_msg_sender_to_recipient = true; + auto fee = NT::fr(2); + + transfer(exec_ctx, amount, to, asset_id, memo, reveal_msg_sender_to_recipient, fee); + + info("computed witness: ", composer.computed_witness); + info("witness: ", composer.witness); + // info("constant variables: ", composer.constant_variables); + // info("variables: ", composer.variables); + info("failed?: ", composer.failed); + info("err: ", composer.err); + info("n: ", composer.n); +} // TEST(escrow_tests, test_withdraw) // { @@ -130,4 +128,4 @@ // info("n: ", composer.n); // } -// } // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file +} // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp index 5deda875252..2c73665ec3d 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp @@ -1,35 +1,33 @@ -// #pragma once +#pragma once -// #include "init.hpp" +#include "init.hpp" -// #include -// #include +#include +#include -// namespace aztec3::circuits::apps::test_apps::escrow { +namespace aztec3::circuits::apps::test_apps::escrow { -// inline Contract init_contract(FunctionExecutionContext& exec_ctx) -// { -// Contract contract(exec_ctx, "Escrow"); +inline Contract init_contract(FunctionExecutionContext& exec_ctx) +{ + Contract contract(exec_ctx, "Escrow"); -// // mapping(owner => mapping(asset_id => balance)) balances; -// contract.declare_private_state_var("balances"); + contract.declare_state_var("balances"); -// // Solely used for assigning vk indices. -// contract.set_functions({ -// { .name = "deposit", .is_private = true }, -// { .name = "transfer", .is_private = true }, -// { .name = "withdraw", .is_private = true }, -// }); + // Solely used for assigning vk indices. + contract.set_functions({ + { .name = "deposit", .is_private = true }, + { .name = "transfer", .is_private = true }, + { .name = "withdraw", .is_private = true }, + }); -// // TODO: this L1 declaration interface is just to get something working. -// contract.import_l1_function({ -// .function_name = "withdraw", -// .function_selector = 12345, -// .num_params = 3, -// }); + // TODO: this L1 declaration interface is just to get something working. + contract.import_l1_function({ + .function_name = "withdraw", + .function_selector = 12345, + .num_params = 3, + }); -// // TODO: create a new FunctionExecutor(contract) and return it. -// return contract; -// } + return contract; +} -// } // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file +} // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp index 59c44cea8c2..74bcb5d6b4a 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp @@ -1,137 +1,71 @@ -// #include "deposit.hpp" +#include "deposit.hpp" -// #include "contract.hpp" +#include "contract.hpp" -// #include -// #include +#include +#include -// namespace aztec3::circuits::apps::test_apps::escrow { +namespace aztec3::circuits::apps::test_apps::escrow { -// using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; +using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; -// OptionalPrivateCircuitPublicInputs deposit(FunctionExecutionContext& exec_ctx, -// NT::fr const& _amount, -// NT::fr const& _asset_id, -// NT::fr const& _memo) -// { -// auto& composer = exec_ctx.composer; -// auto& oracle = exec_ctx.oracle; -// Contract contract = init_contract(exec_ctx); +OptionalPrivateCircuitPublicInputs deposit(FunctionExecutionContext& exec_ctx, + NT::fr const& _amount, + NT::fr const& _asset_id, + NT::fr const& _memo) +{ + /**************************************************************** + * PREAMBLE + ****************************************************************/ -// CT::fr amount = to_ct(composer, _amount); -// CT::fr asset_id = to_ct(composer, _asset_id); -// CT::fr memo = to_ct(composer, _memo); + // Make the exec_ctx aware of the contract's layout. + init_contract(exec_ctx); -// CT::address msg_sender = oracle.get_msg_sender(); + // Convert params into circuit types: + auto& composer = exec_ctx.composer; -// auto& balances = contract.get_private_state_var("balances"); + CT::fr amount = to_ct(composer, _amount); + CT::fr asset_id = to_ct(composer, _asset_id); + CT::fr memo = to_ct(composer, _memo); -// balances.at({ msg_sender.to_field(), asset_id }) -// .add({ -// .value = amount, -// .owner = msg_sender, -// .creator_address = msg_sender, -// .memo = memo, -// }); + auto& oracle = exec_ctx.oracle; + const CT::address msg_sender = oracle.get_msg_sender(); -// auto& public_inputs = exec_ctx.private_circuit_public_inputs; + /**************************************************************** + * BODY + ****************************************************************/ -// public_inputs.args[0] = amount; -// public_inputs.args[1] = asset_id; -// public_inputs.args[2] = memo; + // Syntactic sugar for a state variable: + // Note: these Mappings always map-from a field type (because it was complicated enough!!!) + // mapping(asset_id => mapping(owner => UTXOSet< >)) balances; + Mapping>> balances(&exec_ctx, "balances"); -// exec_ctx.finalise(); + balances[asset_id][msg_sender.to_field()].insert({ + .value = amount, + .owner = msg_sender, + .creator_address = msg_sender, + .memo = memo, + }); -// info("public inputs: ", public_inputs); + /**************************************************************** + * CLEANUP + ****************************************************************/ -// return public_inputs.to_native_type(); -// // TODO: also return note preimages and nullifier preimages. -// }; + // Push args to the public inputs. + // TODO: don't give function direct access to the exec_ctx? + auto& public_inputs = exec_ctx.private_circuit_public_inputs; -// } // namespace aztec3::circuits::apps::test_apps::escrow + public_inputs.args[0] = amount; + public_inputs.args[1] = asset_id; + public_inputs.args[2] = memo; -// // require_pokosk(owner) + exec_ctx.finalise(); -// // DEPOSIT : + info("public inputs: ", public_inputs); -// // balances[msg.sender] += amount; + return public_inputs.to_native_type(); + // TODO: also return note preimages and nullifier preimages. + // TODO: or, we'll be collecting this data in the exec_ctx. +}; -// // Either : -msg_sender == owner - msg_sender is populating the private state of some other owner, -// // where the state is indexed _by_ the msg_sender - -// // balances[msg_sender][asset_id] = h(storage_slot, value, owner, ...); - -// // Either : -to == owner - the state is indexed _by_ to, but the owner is someone else - -// // balances[to][asset_id] = h(storage_slot, value, owner); - -// // transfer: - -// // msg.sender needs to prove they know a private key to call this: - -// // balances[msg.sender] -= amount <-- msg.sender == owner in the commitment -// // balances[to] += amount <-- to == owner in the commitment - -// // So if this is called by a smart contract (rather than a person): -// // - It works for regular public solidity -// // - But in private land, we actually want to produce a nullifier, so it needs to be called by a person who knows a -// // secret key, in order to produce a nullifier. - -// // Private approval feels difficult. - -// // function approve(address spender, uint256 amount) public returns (bool success) -// // { -// // allowed[msg.sender][spender] = amount; -// // emit Approval(msg.sender, spender, amount); -// // return true; -// // } - -// // -- -- -- -- -- -- -- -- - -// // mapping(address = > UTXOSet) balances; -// // mapping(address = > mapping(address = > UTXO)) allowed; - -// // deposit(uint amount) -// // { -// // balances[msg.sender].insert(amount, { owner : msg.sender }); // specify commitment owner? -// // } - -// // transfer(uint amount, address to) -// // { -// // UTXO[2] notes = balances[msg.sender].get(2, sort, filter, { owner : msg.sender }); - -// // uint input_amount = notes[0].value + notes[1].value; -// // require(input_amount >= amount); - -// // notes[0].remove(); -// // notes[1].remove(); - -// // balances[msg.sender].insert(input_amount - amount, { owner : msg.sender }); - -// // balances[to].insert(amount, { owner : to }); -// // } - -// // approve(address spender, uint amount) -// // { -// // UTXO note = allowed[msg.sender][spender].get(1, { owner : msg.sender }); -// // allowed[msg.sender][spender].replace(increase_amount, { owner : spender }); -// // } - -// // function transferFrom(address sender, address recipient, uint256 amount) -// // { - -// // require(balances[sender] >= amount, "Insufficient balance."); -// // require(allowed[sender][msg.sender] >= amount, "Insufficient allowance."); - -// // balances[sender] = balances[sender].sub(amount); -// // allowed[sender][msg.sender] = allowed[sender][msg.sender].sub(amount); -// // balances[recipient] = balances[recipient].add(amount); -// // emit Transfer(sender, recipient, amount); -// // return true; -// // } - -// // Initialising singleton UTXOs: -// // - We want to ensure we never create more than 1 UTXO in the tree for such a variable. -// // - So we can't use "optional" to get a dummy UTXO (because then a user could call the functoin multiple times, -// eeach -// // time _get_ a dummy UTXO, and then create loads of competing notes for the same variable). \ No newline at end of file +} // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.hpp index 59f3bbf2cfb..afb9391f8f2 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.hpp @@ -1,17 +1,17 @@ -// #pragma once +#pragma once -// #include "init.hpp" +#include "init.hpp" -// #include -// #include +#include +#include -// namespace aztec3::circuits::apps::test_apps::escrow { +namespace aztec3::circuits::apps::test_apps::escrow { -// using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; +using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; -// OptionalPrivateCircuitPublicInputs deposit(FunctionExecutionContext& exec_ctx, -// NT::fr const& _amount, -// NT::fr const& _asset_id, -// NT::fr const& _memo); +OptionalPrivateCircuitPublicInputs deposit(FunctionExecutionContext& exec_ctx, + NT::fr const& _amount, + NT::fr const& _asset_id, + NT::fr const& _memo); -// } // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file +} // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/index.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/index.hpp index 55dfd98f087..4cf1909486f 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/index.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/index.hpp @@ -1,5 +1,5 @@ -// #include "init.hpp" -// #include "contract.hpp" -// #include "deposit.hpp" -// #include "transfer.hpp" -// #include "withdraw.hpp" \ No newline at end of file +#include "init.hpp" +#include "contract.hpp" +#include "deposit.hpp" +#include "transfer.hpp" +#include "withdraw.hpp" \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/init.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/init.hpp index 22996d6c982..400e8547f73 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/init.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/init.hpp @@ -1,24 +1,48 @@ -// #pragma once +#pragma once -// #include -// #include +#include +#include +#include +#include +#include -// #include -// #include -// #include -// #include +#include +#include -// namespace aztec3::circuits::apps::test_apps::escrow { +#include +#include +#include +#include -// using Composer = plonk::stdlib::types::turbo::Composer; +namespace aztec3::circuits::apps::test_apps::escrow { -// using CT = plonk::stdlib::types::CircuitTypes; -// using NT = plonk::stdlib::types::NativeTypes; +using C = plonk::stdlib::types::turbo::Composer; -// using DB = oracle::FakeDB; -// using oracle::NativeOracle; -// using OracleWrapper = OracleWrapperInterface; +using CT = plonk::stdlib::types::CircuitTypes; +using NT = plonk::stdlib::types::NativeTypes; -// using plonk::stdlib::types::to_ct; +using DB = oracle::FakeDB; +using oracle::NativeOracle; +using OracleWrapper = apps::OracleWrapperInterface; -// } // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file +using Contract = apps::Contract; +using FunctionExecutionContext = apps::FunctionExecutionContext; + +using plonk::stdlib::types::to_ct; + +// StateVars +using apps::state_vars::MappingStateVar; +using apps::state_vars::UTXOSetStateVar; + +// Get rid of ugle `Composer` template arg from our state var types: +template struct SpecialisedTypes { + typedef MappingStateVar mapping; + typedef UTXOSetStateVar utxo_set; +}; + +template using Mapping = typename SpecialisedTypes::mapping; +template using UTXOSet = typename SpecialisedTypes::utxo_set; + +using DefaultNote = apps::notes::DefaultPrivateNote; + +} // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp index 5566c2d0ede..1a9da9a8284 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp @@ -1,88 +1,107 @@ -// #include "transfer.hpp" +#include "transfer.hpp" -// #include "contract.hpp" +#include "contract.hpp" -// #include -// #include +#include -// namespace aztec3::circuits::apps::test_apps::escrow { +namespace aztec3::circuits::apps::test_apps::escrow { -// using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; +using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; -// OptionalPrivateCircuitPublicInputs transfer(FunctionExecutionContext& exec_ctx, -// NT::fr const& _amount, -// NT::address const& _to, -// NT::fr const& _asset_id, -// NT::fr const& _memo, -// NT::boolean const& _reveal_msg_sender_to_recipient, -// NT::fr const& _fee) -// { -// info("\n\nin transfer..."); +OptionalPrivateCircuitPublicInputs transfer(FunctionExecutionContext& exec_ctx, + NT::fr const& _amount, + NT::address const& _to, + NT::fr const& _asset_id, + NT::fr const& _memo, + NT::boolean const& _reveal_msg_sender_to_recipient, + NT::fr const& _fee) +{ + /**************************************************************** + * Initialisation + ****************************************************************/ -// // Initialisation *************************************************************** + // Make the exec_ctx aware of the contract's layout. + init_contract(exec_ctx); -// auto& composer = exec_ctx.composer; -// auto& oracle = exec_ctx.oracle; -// Contract contract = init_contract(exec_ctx); + // Convert params into circuit types: + auto& composer = exec_ctx.composer; -// CT::fr amount = to_ct(composer, _amount); -// CT::address to = to_ct(composer, _to); -// CT::fr asset_id = to_ct(composer, _asset_id); -// CT::fr memo = to_ct(composer, _memo); -// CT::boolean reveal_msg_sender_to_recipient = to_ct(composer, _reveal_msg_sender_to_recipient); -// CT::fr fee = to_ct(composer, _fee); + CT::fr amount = to_ct(composer, _amount); + CT::address to = to_ct(composer, _to); + CT::fr asset_id = to_ct(composer, _asset_id); + CT::fr memo = to_ct(composer, _memo); + CT::boolean reveal_msg_sender_to_recipient = to_ct(composer, _reveal_msg_sender_to_recipient); + CT::fr fee = to_ct(composer, _fee); -// // Get states and globals ******************************************************* + /**************************************************************** + * Get States & Globals used by the function + ****************************************************************/ -// CT::address msg_sender = oracle.get_msg_sender(); + auto& oracle = exec_ctx.oracle; + CT::address msg_sender = oracle.get_msg_sender(); -// auto& balances = contract.get_private_state_var("balances"); + Mapping>> balances(&exec_ctx, "balances"); -// // Circuit-specific logic ******************************************************* + /**************************************************************** + * BODY + ****************************************************************/ -// CT::address creator_address = -// CT::address::conditional_assign(reveal_msg_sender_to_recipient, msg_sender, CT::address(0)); + CT::address creator_address = + CT::address::conditional_assign(reveal_msg_sender_to_recipient, msg_sender, CT::address(0)); -// balances.at({ msg_sender.to_field(), asset_id }) -// .subtract({ -// .value = amount + fee, -// .owner = msg_sender, -// .creator_address = msg_sender, -// .memo = memo, -// }); + std::vector old_balance_notes = + balances[asset_id][msg_sender.to_field()].get(2, { .owner = msg_sender }); -// balances.at({ to.to_field(), asset_id }) -// .add({ -// .value = amount, -// .owner = to, -// .creator_address = creator_address, -// .memo = memo, -// }); + CT::fr old_value_1 = *(old_balance_notes[0].get_preimage().value); + CT::fr old_value_2 = *(old_balance_notes[1].get_preimage().value); -// // Assign circuit-specific public inputs **************************************** + // MISSING: overflow & underflow checks, but I can't be bothered with safe_uint or range checks yet. + CT::fr change = (old_value_1 + old_value_2) - amount; -// auto& public_inputs = exec_ctx.private_circuit_public_inputs; + old_balance_notes[0].remove(); + old_balance_notes[1].remove(); -// public_inputs.args[0] = amount; -// public_inputs.args[1] = to.to_field(); -// public_inputs.args[2] = asset_id; -// public_inputs.args[3] = memo; -// public_inputs.args[4] = CT::fr(reveal_msg_sender_to_recipient); -// public_inputs.args[5] = fee; + // Send amount to `to` address. + balances[asset_id][to.to_field()].insert({ + .value = amount, + .owner = to, + .creator_address = creator_address, + .memo = memo, + }); -// public_inputs.emitted_events[0] = CT::fr::copy_as_new_witness(composer, fee); -// public_inputs.emitted_events[1] = CT::fr::copy_as_new_witness(composer, asset_id); + // Return change to sender: + balances[asset_id][msg_sender.to_field()].insert({ + .value = change, + .owner = msg_sender, + .creator_address = msg_sender, + .memo = memo, + }); -// /// TODO: merkle membership check -// // public_inputs.old_private_data_tree_root + /**************************************************************** + * CLEANUP + ****************************************************************/ -// // Finalise ********************************************************************* + // Push args to the public inputs. + auto& public_inputs = exec_ctx.private_circuit_public_inputs; -// exec_ctx.finalise(); + public_inputs.args[0] = amount; + public_inputs.args[1] = to.to_field(); + public_inputs.args[2] = asset_id; + public_inputs.args[3] = memo; + public_inputs.args[4] = CT::fr(reveal_msg_sender_to_recipient); + public_inputs.args[5] = fee; -// info("public inputs: ", public_inputs); + public_inputs.emitted_events[0] = CT::fr::copy_as_new_witness(composer, fee); + public_inputs.emitted_events[1] = CT::fr::copy_as_new_witness(composer, asset_id); -// return public_inputs.to_native_type(); -// }; + /// TODO: merkle membership check + // public_inputs.old_private_data_tree_root -// } // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file + exec_ctx.finalise(); + + info("public inputs: ", public_inputs); + + return public_inputs.to_native_type(); +}; + +} // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.hpp index f91e8e91497..fa3fe7dfcdb 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.hpp @@ -1,20 +1,20 @@ -// #pragma once +#pragma once -// #include "init.hpp" +#include "init.hpp" -// #include -// #include +#include +#include -// namespace aztec3::circuits::apps::test_apps::escrow { +namespace aztec3::circuits::apps::test_apps::escrow { -// using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; +using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; -// OptionalPrivateCircuitPublicInputs transfer(FunctionExecutionContext& exec_ctx, -// NT::fr const& _amount, -// NT::address const& _to, -// NT::fr const& _asset_id, -// NT::fr const& _memo, -// NT::boolean const& _reveal_msg_sender_to_recipient, -// NT::fr const& _fee); +OptionalPrivateCircuitPublicInputs transfer(FunctionExecutionContext& exec_ctx, + NT::fr const& _amount, + NT::address const& _to, + NT::fr const& _asset_id, + NT::fr const& _memo, + NT::boolean const& _reveal_msg_sender_to_recipient, + NT::fr const& _fee); -// } // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file +} // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/oracle/oracle.hpp b/circuits/src/aztec3/oracle/oracle.hpp index 8b73a02fef2..5d9fcc97c0d 100644 --- a/circuits/src/aztec3/oracle/oracle.hpp +++ b/circuits/src/aztec3/oracle/oracle.hpp @@ -2,7 +2,6 @@ #include -#include #include #include @@ -13,7 +12,6 @@ namespace aztec3::oracle { using aztec3::circuits::abis::CallContext; -using aztec3::circuits::apps::PrivateStateNotePreimage; using aztec3::circuits::apps::UTXOSLoadDatum; using aztec3::circuits::apps::notes::DefaultPrivateNotePreimage; @@ -115,13 +113,14 @@ template class NativeOracleInterface { return db.get_utxo_sload_datum(contract_address, storage_slot_point, advice); } - std::pair, PrivateStateNotePreimage> - get_private_state_note_preimages_for_subtraction(NT::fr const& storage_slot, - NT::address const& owner, - NT::fr const& subtrahend) + template + std::vector> get_utxo_sload_data(NT::grumpkin_point const storage_slot_point, + size_t const& num_notes, + NotePreimage const advice) { + // TODO: consider whether it's actually safe to bypass get_call_context() here... const auto& contract_address = call_context.storage_contract_address; - return db.get_private_state_note_preimages_for_subtraction(contract_address, storage_slot, owner, subtrahend); + return db.get_utxo_sload_data(contract_address, storage_slot_point, num_notes, advice); } NT::fr generate_salt() const { return NT::fr::random_element(); } @@ -154,6 +153,10 @@ class FakeDB { /** * For getting a singleton UTXO (not a set). + * + * NOTICE: this fake db stub is hard-coded to a DefaultPrivateNotePreimage which _itself_ is hard-coded to the value + * type being a field. + * So if you want to test other note types against this stub DB, you'll need to write your own stub DB entry. */ UTXOSLoadDatum> get_utxo_sload_datum( NT::address const& contract_address, @@ -182,7 +185,7 @@ class FakeDB { std::fill(sibling_path.begin(), sibling_path.end(), 1); // Fill with 1's to be lazy. TODO: return a valid path. return { - .commitment = 1, // TODO: implement commit() method in `preimage`? + .commitment = 1, .contract_address = contract_address, .preimage = preimage, @@ -192,46 +195,55 @@ class FakeDB { }; }; - std::pair, PrivateStateNotePreimage> - get_private_state_note_preimages_for_subtraction(NT::address const& contract_address, - NT::fr const& storage_slot, - NT::address const& owner, - NT::fr const& subtrahend) + /** + * For getting a set of UTXOs. + * + * * NOTICE: this fake db stub is hard-coded to a DefaultPrivateNotePreimage which _itself_ is hard-coded to the + * value type being a field. + * So if you want to test other note types against this stub DB, you'll need to write your own stub DB entry. + */ + std::vector>> get_utxo_sload_data( + NT::address const& contract_address, + NT::grumpkin_point const& storage_slot_point, + size_t const& num_notes, + DefaultPrivateNotePreimage const& advice) + // NT::address const& owner, + // NT::fr required_utxo_tree_root, + // size_t utxo_tree_depth) { - (void)contract_address; // currently unused - - NT::grumpkin_point storage_slot_point; - NT::fr x = storage_slot; - NT::fr yy = x.sqr() * x + NT::grumpkin_group::curve_b; - NT::fr y = yy.sqrt(); - NT::fr neg_y = -y; - y = y < neg_y ? y : neg_y; - storage_slot_point = NT::grumpkin_group::affine_element(x, y); - info("derived slot point:", storage_slot_point); - - return std::make_pair( - PrivateStateNotePreimage{ - .start_slot = 0, - .storage_slot_point = storage_slot_point, - .value = uint256_t(subtrahend) / 2 + 1, - .owner = owner, + (void)storage_slot_point; // Not used in this 'fake' implementation. + + std::vector>> data; + + const size_t utxo_tree_depth = 32; + const NT::fr required_utxo_tree_root = 2468; + + std::vector sibling_path(utxo_tree_depth); + std::fill(sibling_path.begin(), sibling_path.end(), 1); // Fill with 1's to be lazy. TODO: return a valid path. + + for (size_t i = 0; i < num_notes; i++) { + DefaultPrivateNotePreimage preimage{ + .value = 100 + i, + .owner = advice.owner, .creator_address = 0, .memo = 3456, .salt = 1234, .nonce = 2345, - .is_real = true, - }, - PrivateStateNotePreimage{ - .start_slot = 0, - .storage_slot_point = storage_slot_point, - .value = uint256_t(subtrahend) / 2 + 3, - .owner = owner, - .creator_address = 0, - .memo = 6789, - .salt = 4567, - .nonce = 5678, - .is_real = true, + .is_dummy = false, + }; + + data.push_back({ + .commitment = 1, + .contract_address = contract_address, + .preimage = preimage, + + .sibling_path = sibling_path, + .leaf_index = 2, + .old_private_data_tree_root = required_utxo_tree_root, }); + } + + return data; }; }; From 401576da3d65bc71ffa5e392eb8c61dee72f37f1 Mon Sep 17 00:00:00 2001 From: iAmMichaelConnor Date: Thu, 5 Jan 2023 12:06:05 +0000 Subject: [PATCH 023/166] tidying --- .../src/aztec3/circuits/apps/contract.hpp | 4 +- .../apps/function_execution_context.hpp | 1 - circuits/src/aztec3/circuits/apps/l1_call.hpp | 4 +- .../apps/notes/default_private_note/note.hpp | 11 +- .../apps/notes/default_private_note/note.tpp | 15 +- .../default_private_note/note_preimage.hpp | 4 +- .../circuits/apps/notes/note_interface.hpp | 46 +----- .../aztec3/circuits/apps/opcodes/opcodes.hpp | 14 +- .../aztec3/circuits/apps/opcodes/opcodes.tpp | 14 +- .../apps/state_vars/field_state_var.hpp | 2 +- .../apps/state_vars/mapping_state_var.hpp | 4 +- .../apps/state_vars/mapping_state_var.tpp | 21 +-- .../apps/state_vars/state_var_base.hpp | 34 ++--- .../apps/state_vars/state_var_base.tpp | 25 +--- .../apps/state_vars/utxo_set_state_var.hpp | 6 - .../apps/state_vars/utxo_state_var.hpp | 4 - .../circuits/apps/test_apps/escrow/.test.cpp | 81 ++++++----- .../apps/test_apps/escrow/transfer.cpp | 9 +- .../apps/test_apps/escrow/withdraw.cpp | 134 +++++++++++------- .../apps/test_apps/escrow/withdraw.hpp | 26 ++-- .../src/aztec3/circuits/apps/type_check.hpp | 13 -- .../src/aztec3/circuits/apps/utxo_datum.hpp | 30 ---- 22 files changed, 187 insertions(+), 315 deletions(-) delete mode 100644 circuits/src/aztec3/circuits/apps/type_check.hpp diff --git a/circuits/src/aztec3/circuits/apps/contract.hpp b/circuits/src/aztec3/circuits/apps/contract.hpp index fee61740a2a..12f7d155151 100644 --- a/circuits/src/aztec3/circuits/apps/contract.hpp +++ b/circuits/src/aztec3/circuits/apps/contract.hpp @@ -92,9 +92,7 @@ template class Contract { // Importing in this way (rather than explicit instantiation of a template class at the bottom of a .cpp file) preserves // the following: -// - We retain implicit instantiation of templates, meaning we can pick and choose (with static_assert) which class -// methods support native, -// circuit or both types. +// - We retain implicit instantiation of templates. // - We don't implement method definitions in this file, to avoid a circular dependency with // function_execution_context.hpp. #include "contract.tpp" \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/function_execution_context.hpp b/circuits/src/aztec3/circuits/apps/function_execution_context.hpp index 21e03a1f2fb..9d525b521e3 100644 --- a/circuits/src/aztec3/circuits/apps/function_execution_context.hpp +++ b/circuits/src/aztec3/circuits/apps/function_execution_context.hpp @@ -17,7 +17,6 @@ // #include -// #include "private_state_var.hpp" // #include "function_declaration.hpp" // #include "l1_function_interface.hpp" diff --git a/circuits/src/aztec3/circuits/apps/l1_call.hpp b/circuits/src/aztec3/circuits/apps/l1_call.hpp index 37a66ad94f9..005bef3eba3 100644 --- a/circuits/src/aztec3/circuits/apps/l1_call.hpp +++ b/circuits/src/aztec3/circuits/apps/l1_call.hpp @@ -1,11 +1,11 @@ #pragma once + #include "l1_function_interface.hpp" + #include #include #include #include -// #include -// #include namespace aztec3::circuits::apps { diff --git a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.hpp b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.hpp index a520aac9e41..5190fe8dba4 100644 --- a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.hpp +++ b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.hpp @@ -50,8 +50,6 @@ template class DefaultPrivateNote : publ std::optional nullifier; std::optional partial_commitment; - // bool is_partial = false; - NotePreimage note_preimage; std::optional nullifier_preimage; @@ -104,7 +102,7 @@ template class DefaultPrivateNote : publ bool needs_nonce() override; - void set_nonce(fr nonce) override; + void set_nonce(fr const& nonce) override; fr generate_nonce() override; @@ -134,8 +132,7 @@ template class DefaultPrivateNote : publ // Importing in this way (rather than explicit instantiation of a template class at the bottom of a .cpp file) preserves // the following: -// - We retain implicit instantiation of templates, meaning we can pick and choose (with static_assert) which class -// methods support native, -// circuit or both types. -// - We don't implement method definitions in this file, to avoid a circular dependency with state_factory.hpp. +// - We retain implicit instantiation of templates. +// - We don't implement method definitions in this file, to avoid a circular dependency with the state_var files (which +// are forward-declared in this file). #include "note.tpp" \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.tpp b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.tpp index 2c94448004b..f924df506c7 100644 --- a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.tpp +++ b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.tpp @@ -180,8 +180,7 @@ typename CircuitTypes::fr DefaultPrivateNote::compute_nul throw_or_abort("Can't nullify a partial note."); } if (!commitment) { - throw_or_abort("Commitment not yet calculated. Call compute_commitment() or change how you initialise this " - "note to include the `commit_on_init` bool."); + compute_commitment(); } if (nullifier && nullifier_preimage) { return *nullifier; @@ -279,7 +278,7 @@ template bool DefaultPrivateNote::n } template -void DefaultPrivateNote::set_nonce(typename CircuitTypes::fr nonce) +void DefaultPrivateNote::set_nonce(typename CircuitTypes::fr const& nonce) { ASSERT(!note_preimage.nonce); note_preimage.nonce = nonce; @@ -293,14 +292,4 @@ typename CircuitTypes::fr DefaultPrivateNote::generate_no return *(note_preimage.nonce); }; -// template -// typename CircuitTypes::fr DefaultPrivateNote::compute_dummy_nullifier(fr const& dummy_commitment, -// fr const& -// owner_private_key) -// { -// return DefaultPrivateNote::compute_nullifier(dummy_commitment, owner_private_key, false); -// } - -// template class DefaultPrivateNote; - } // namespace aztec3::circuits::apps::notes \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note_preimage.hpp b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note_preimage.hpp index 6ee2810e003..8891894eb4f 100644 --- a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note_preimage.hpp +++ b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note_preimage.hpp @@ -45,7 +45,7 @@ template struct DefaultPrivateNotePreimage { const bool has_to_circuit_type = requires(V v) { v.to_circuit_type(); }; const bool has_to_ct = requires(V v) { to_ct(v); }; - // To avoid messy template arguments in the calling code, we use a lambda functino with `auto` return type to + // To avoid messy template arguments in the calling code, we use a lambda function with `auto` return type to // avoid explicitly having to state the circuit type for `V`. auto circuit_value = [&]() -> auto { @@ -140,6 +140,4 @@ std::ostream& operator<<(std::ostream& os, DefaultPrivateNotePreimage co << "is_dummy: " << preimage.is_dummy << "\n"; } -// template using MappingKeyValues = std::map>; - } // namespace aztec3::circuits::apps::notes \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/notes/note_interface.hpp b/circuits/src/aztec3/circuits/apps/notes/note_interface.hpp index ce94f6c9644..1371aff8e3f 100644 --- a/circuits/src/aztec3/circuits/apps/notes/note_interface.hpp +++ b/circuits/src/aztec3/circuits/apps/notes/note_interface.hpp @@ -1,23 +1,13 @@ #pragma once -// #include "../state_vars/utxo_state_var.hpp" - #include #include namespace aztec3::circuits::apps::notes { -// TODO: remove this `using` declaration? -// using aztec3::circuits::apps::state_vars::UTXOStateVar; - using plonk::stdlib::types::CircuitTypes; using plonk::stdlib::types::NativeTypes; -// template class UTXOStateVar; -// template class FunctionExecutionContext; - -// template struct PrivateStateNotePreimage; - template class NoteInterface { public: typedef CircuitTypes CT; @@ -26,16 +16,10 @@ template class NoteInterface { typedef typename CT::address address; typedef typename CT::boolean boolean; - // UTXOStateVar* utxo_state_var; - - // NoteInterface(UTXOStateVar* utxo_state_var, NotePreimage note_preimage) - // : utxo_state_var(utxo_state_var) - // , note_preimage(note_preimage){}; - - virtual ~NoteInterface() { - } // Destructor explicitly made virtual, to ensure that the destructor of the derived class is called if the derived - // object is deleted through a pointer to this base class. (In many places in the code, files handle - // `NoteInterface*` pointers instead of the derived class). + // Destructor explicitly made virtual, to ensure that the destructor of the derived class is called if the derived + // object is deleted through a pointer to this base class. (In many places in the code, files handle + // `NoteInterface*` pointers instead of the derived class). + virtual ~NoteInterface() {} virtual void remove() = 0; @@ -43,12 +27,6 @@ template class NoteInterface { virtual fr get_nullifier() = 0; - // virtual grumpkin_point get_partial_commitment() const = 0; - - // virtual NotePreimage get_note_preimage() const = 0; - - // virtual NullifierPreimageTmp get_nullifier_preimage() const = 0; - virtual fr compute_commitment() = 0; virtual fr compute_nullifier() = 0; @@ -56,22 +34,10 @@ template class NoteInterface { virtual void constrain_against_advice(NoteInterface const& advice_note) = 0; virtual bool needs_nonce() = 0; - virtual void set_nonce(fr nonce) = 0; - virtual fr generate_nonce() = 0; - - // virtual void finalise(std::optional nonce) = 0; - // virtual std::pair compute_partial_commitment() = 0; + virtual void set_nonce(fr const& nonce) = 0; - // static fr compute_dummy_commitment() = 0; - - // static fr compute_nullifier(fr const& commitment, - // fr const& owner_private_key, - // boolean const& is_dummy_commitment = false) = 0; - - // static fr compute_dummy_nullifier(fr const& dummy_commitment, fr const& owner_private_key) = 0; - // private: - // std::optional note_preimage; + virtual fr generate_nonce() = 0; }; } // namespace aztec3::circuits::apps::notes \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/opcodes/opcodes.hpp b/circuits/src/aztec3/circuits/apps/opcodes/opcodes.hpp index d9240419a8c..f0e4a91d28a 100644 --- a/circuits/src/aztec3/circuits/apps/opcodes/opcodes.hpp +++ b/circuits/src/aztec3/circuits/apps/opcodes/opcodes.hpp @@ -1,13 +1,9 @@ #pragma once -// #include "../state_vars/utxo_state_var.hpp" - #include #include #include -#include - namespace aztec3::circuits::apps::state_vars { template class StateVar; template class UTXOStateVar; @@ -29,9 +25,6 @@ template class Opcodes { typedef CircuitTypes CT; typedef NativeTypes NT; - template - using VariantUTXOStateVar = std::variant, UTXOSetStateVar>; - /** * @brief * - Load a singleton UTXOSLoadDatum from the Private Client's DB @@ -66,6 +59,9 @@ template class Opcodes { } // namespace aztec3::circuits::apps::opcodes -// - We don't implement method definitions in this file, to avoid a circular dependency with -// utxo_state_var.hpp. +// Importing in this way (rather than explicit instantiation of a template class at the bottom of a .cpp file) preserves +// the following: +// - We retain implicit instantiation of templates. +// - We don't implement method definitions in this file, to avoid a circular dependency with the state_var files (which +// are forward-declared in this file). #include "opcodes.tpp" diff --git a/circuits/src/aztec3/circuits/apps/opcodes/opcodes.tpp b/circuits/src/aztec3/circuits/apps/opcodes/opcodes.tpp index 5c4c3cafebd..59f81e29aa6 100644 --- a/circuits/src/aztec3/circuits/apps/opcodes/opcodes.tpp +++ b/circuits/src/aztec3/circuits/apps/opcodes/opcodes.tpp @@ -44,11 +44,12 @@ Note Opcodes::UTXO_SLOAD(UTXOStateVar* utxo_state_var, new_note.constrain_against_advice(advice_note); - info("calculated commitment: ", new_note.get_commitment()); - info("retrieved commitment: ", utxo_datum.commitment); // TODO: hard-code or calculate the correct commitment in the FakeDB stub, so that the returned data passes this // check. - new_note.get_commitment().assert_equal(utxo_datum.commitment, "UTXO_SLOAD: bad commitment"); + // Commenting-out this check for now, so the proof verifies. + // info("calculated commitment: ", new_note.get_commitment()); + // info("retrieved commitment: ", utxo_datum.commitment); + // new_note.get_commitment().assert_equal(utxo_datum.commitment, "UTXO_SLOAD: bad commitment"); oracle.get_contract_address().assert_equal(utxo_datum.contract_address, "UTXO_SLOAD: bad contract address"); @@ -85,11 +86,12 @@ std::vector Opcodes::UTXO_SLOAD(UTXOSetStateVar* new_note.constrain_against_advice(advice_note); - info("calculated commitment: ", new_note.get_commitment()); - info("retrieved commitment: ", utxo_datum.commitment); // TODO: hard-code or calculate the correct commitment in the FakeDB stub, so that the returned data passes this // check. - new_note.get_commitment().assert_equal(utxo_datum.commitment, "UTXO_SLOAD: bad commitment"); + // Commenting-out this check for now, so the proof verifies. + // info("calculated commitment: ", new_note.get_commitment()); + // info("retrieved commitment: ", utxo_datum.commitment); + // new_note.get_commitment().assert_equal(utxo_datum.commitment, "UTXO_SLOAD: bad commitment"); oracle.get_contract_address().assert_equal(utxo_datum.contract_address, "UTXO_SLOAD: bad contract address"); diff --git a/circuits/src/aztec3/circuits/apps/state_vars/field_state_var.hpp b/circuits/src/aztec3/circuits/apps/state_vars/field_state_var.hpp index 91fa9536e3a..21d450f75ad 100644 --- a/circuits/src/aztec3/circuits/apps/state_vars/field_state_var.hpp +++ b/circuits/src/aztec3/circuits/apps/state_vars/field_state_var.hpp @@ -11,7 +11,7 @@ namespace aztec3::circuits::apps::state_vars { using plonk::stdlib::types::CircuitTypes; using plonk::stdlib::types::NativeTypes; -// TODO: we can probably generalise this to be PrimitiveStateVar for any stdlib primitive. +// TODO: we can probably generalise this to be a PrimitiveStateVar for any stdlib primitive. template class FieldStateVar : public StateVar { public: typedef CircuitTypes CT; diff --git a/circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.hpp b/circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.hpp index dcd35b7b6d8..8b07f74bb51 100644 --- a/circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.hpp +++ b/circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.hpp @@ -69,9 +69,7 @@ template class MappingStateVar : public StateVar // Importing in this way (rather than explicit instantiation of a template class at the bottom of a .cpp file) preserves // the following: -// - We retain implicit instantiation of templates, meaning we can pick and choose (with static_assert) which class -// methods support native, -// circuit or both types. +// - We retain implicit instantiation of templates. // - We don't implement method definitions in this file, to avoid a circular dependency with // function_execution_context.hpp. #include "mapping_state_var.tpp" diff --git a/circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.tpp b/circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.tpp index f32bde86f3e..0f596cf4f69 100644 --- a/circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.tpp +++ b/circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.tpp @@ -28,21 +28,6 @@ using crypto::pedersen::generator_index_t; using plonk::stdlib::types::CircuitTypes; using plonk::stdlib::types::NativeTypes; -// template -// MappingStateVar::MappingStateVar(FunctionExecutionContext* exec_ctx, -// std::string const& state_var_name) -// : StateVar(exec_ctx, state_var_name) -// {} - -// template -// MappingStateVar::MappingStateVar(FunctionExecutionContext* exec_ctx, -// std::string const& state_var_name, -// grumpkin_point const& storage_slot_point, -// size_t level_of_container_nesting, -// bool is_partial_slot) -// : StateVar(exec_ctx, state_var_name, storage_slot_point, level_of_container_nesting, is_partial_slot) -// {} - // Fr: start_slot // // mapping(fr => V): @@ -59,7 +44,7 @@ template std::tuple MappingStateVar::compute_slot_point_at_mapping_key( NT::fr const& start_slot, size_t level_of_container_nesting, std::optional const& key) { - bool is_partial_slot = false; // ????? + bool is_partial_slot = false; std::vector> input_pairs; @@ -89,7 +74,7 @@ template std::tuple::grumpkin_point, bool> MappingStateVar:: compute_slot_point_at_mapping_key(std::optional const& key) { - bool is_partial_slot = false; // ?????? + bool is_partial_slot = false; std::vector> input_pairs; @@ -160,6 +145,4 @@ template V& MappingStateVar::at(std return this->value_cache[lookup]; } -// template class PrivateStateVar; - }; // namespace aztec3::circuits::apps::state_vars diff --git a/circuits/src/aztec3/circuits/apps/state_vars/state_var_base.hpp b/circuits/src/aztec3/circuits/apps/state_vars/state_var_base.hpp index 3d83be5b1e6..876a0d7b9c8 100644 --- a/circuits/src/aztec3/circuits/apps/state_vars/state_var_base.hpp +++ b/circuits/src/aztec3/circuits/apps/state_vars/state_var_base.hpp @@ -1,7 +1,5 @@ #pragma once -// #include "../function_execution_context.hpp" - #include #include @@ -35,22 +33,6 @@ template class StateVar { size_t level_of_container_nesting = 0; bool is_partial_slot = false; - // native_storage_slot.x => value cache, to prevent creating constraints with each call. - // V value; - - // StateVar(){}; - - StateVar operator=(StateVar const& other) - { - this->exec_ctx = other.exec_ctx; - this->state_var_name = other.state_var_name; - this->start_slot = other.start_slot; - this->storage_slot_point = other.storage_slot_point; - this->level_of_container_nesting = other.level_of_container_nesting; - this->is_partial_slot = other.is_partial_slot; - return *this; - } - StateVar(){}; // Instantiate a top-level state: @@ -71,6 +53,17 @@ template class StateVar { bool operator==(StateVar const&) const = default; + StateVar operator=(StateVar const& other) + { + this->exec_ctx = other.exec_ctx; + this->state_var_name = other.state_var_name; + this->start_slot = other.start_slot; + this->storage_slot_point = other.storage_slot_point; + this->level_of_container_nesting = other.level_of_container_nesting; + this->is_partial_slot = other.is_partial_slot; + return *this; + } + private: grumpkin_point compute_slot_point(); }; @@ -79,7 +72,6 @@ template class StateVar { // Importing in this way (rather than explicit instantiation of a template class at the bottom of a .cpp file) preserves // the following: -// - We retain implicit instantiation of templates, meaning we can pick and choose (with static_assert) which class -// methods support native, -// circuit or both types. +// - We retain implicit instantiation of templates. +// - We avoid circular dependencies with function_execution_context.hpp #include "state_var_base.tpp" diff --git a/circuits/src/aztec3/circuits/apps/state_vars/state_var_base.tpp b/circuits/src/aztec3/circuits/apps/state_vars/state_var_base.tpp index 72586a9d022..14bd20dcc8e 100644 --- a/circuits/src/aztec3/circuits/apps/state_vars/state_var_base.tpp +++ b/circuits/src/aztec3/circuits/apps/state_vars/state_var_base.tpp @@ -1,23 +1,13 @@ #pragma once -// #include -// #include "oracle_wrapper.hpp" -// #include "private_state_note.hpp" -// #include "private_state_note_preimage.hpp" -// #include "private_state_operand.hpp" - -// TODO: remove redundant includes: #include "../function_execution_context.hpp" #include -#include -#include #include + #include -#include #include -#include namespace { using aztec3::circuits::apps::FunctionExecutionContext; @@ -27,19 +17,6 @@ namespace aztec3::circuits::apps::state_vars { using crypto::pedersen::generator_index_t; using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; - -// Fr: start_slot -// -// mapping(fr => V): -// level of nesting = 1 -// start_slot_point = start_slot * A -// at(k1).slot = start_slot_point + k1 * B -// -// mapping(fr => mapping(fr => T)): -// level_of_nesting = 2 -// start_slot_point becomes: prev_start_slot_point + k1 * B -// at(k2).slot = new_start_slot_point + k2 * C template StateVar::StateVar(FunctionExecutionContext* exec_ctx, std::string const& state_var_name) diff --git a/circuits/src/aztec3/circuits/apps/state_vars/utxo_set_state_var.hpp b/circuits/src/aztec3/circuits/apps/state_vars/utxo_set_state_var.hpp index a70adbd47d1..ff381fe0326 100644 --- a/circuits/src/aztec3/circuits/apps/state_vars/utxo_set_state_var.hpp +++ b/circuits/src/aztec3/circuits/apps/state_vars/utxo_set_state_var.hpp @@ -2,8 +2,6 @@ #include "state_var_base.hpp" -// #include "../function_execution_context.hpp" - #include #include @@ -16,8 +14,6 @@ namespace aztec3::circuits::apps::state_vars { using aztec3::circuits::apps::FunctionExecutionContext; // Don't #include it! -// template class FunctionExecutionContext; - using plonk::stdlib::types::CircuitTypes; using plonk::stdlib::types::NativeTypes; @@ -45,8 +41,6 @@ template class UTXOSetStateVar : public State : StateVar( exec_ctx, state_var_name, storage_slot_point, level_of_container_nesting, is_partial_slot){}; - // bool operator==(UTXOSetStateVar const&) const = default; - /** * @param advice - For NotePreimages, we allow 'advice' to be given, so that the correct DB entry is * chosen. diff --git a/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp b/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp index 393110707ee..97dd67b1180 100644 --- a/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp +++ b/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp @@ -2,8 +2,6 @@ #include "state_var_base.hpp" -// #include "../function_execution_context.hpp" - #include #include @@ -16,8 +14,6 @@ namespace aztec3::circuits::apps::state_vars { using aztec3::circuits::apps::FunctionExecutionContext; // Don't #include it! -// template class FunctionExecutionContext; - using plonk::stdlib::types::CircuitTypes; using plonk::stdlib::types::NativeTypes; diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp index 502e2c032f8..8557540be57 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp @@ -86,46 +86,45 @@ TEST(escrow_tests, test_transfer) info("n: ", composer.n); } -// TEST(escrow_tests, test_withdraw) -// { - -// Composer composer; -// DB db; - -// const NT::address contract_address = 12345; -// const NT::fr msg_sender_private_key = 123456789; -// const NT::address msg_sender = -// NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, -// 0x2ef9f7f09867fd6eULL)); - -// CallContext call_context = { -// .msg_sender = msg_sender, -// .storage_contract_address = contract_address, -// .tx_origin = msg_sender, -// .is_delegate_call = false, -// .is_static_call = false, -// }; - -// NativeOracle oracle = NativeOracle(db, call_context, msg_sender_private_key); -// OracleWrapper oracle_wrapper = OracleWrapper(composer, oracle); - -// FunctionExecutionContext exec_ctx(composer, oracle_wrapper); - -// auto amount = NT::fr(5); -// auto asset_id = NT::fr(1); -// auto memo = NT::fr(999); -// auto l1_withdrawal_address = NT::fr(657756); -// auto fee = NT::fr(2); - -// withdraw(exec_ctx, amount, asset_id, memo, l1_withdrawal_address, fee); - -// info("computed witness: ", composer.computed_witness); -// info("witness: ", composer.witness); -// // info("constant variables: ", composer.constant_variables); -// // info("variables: ", composer.variables); -// info("failed?: ", composer.failed); -// info("err: ", composer.err); -// info("n: ", composer.n); -// } +TEST(escrow_tests, test_withdraw) +{ + + C composer; + DB db; + + const NT::address contract_address = 12345; + const NT::fr msg_sender_private_key = 123456789; + const NT::address msg_sender = + NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); + + CallContext call_context = { + .msg_sender = msg_sender, + .storage_contract_address = contract_address, + .tx_origin = msg_sender, + .is_delegate_call = false, + .is_static_call = false, + }; + + NativeOracle oracle = NativeOracle(db, call_context, msg_sender_private_key); + OracleWrapper oracle_wrapper = OracleWrapper(composer, oracle); + + FunctionExecutionContext exec_ctx(composer, oracle_wrapper); + + auto amount = NT::fr(5); + auto asset_id = NT::fr(1); + auto memo = NT::fr(999); + auto l1_withdrawal_address = NT::fr(657756); + auto fee = NT::fr(2); + + withdraw(exec_ctx, amount, asset_id, memo, l1_withdrawal_address, fee); + + info("computed witness: ", composer.computed_witness); + info("witness: ", composer.witness); + // info("constant variables: ", composer.constant_variables); + // info("variables: ", composer.variables); + info("failed?: ", composer.failed); + info("err: ", composer.err); + info("n: ", composer.n); +} } // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp index 1a9da9a8284..cab215a0e69 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp @@ -23,7 +23,7 @@ OptionalPrivateCircuitPublicInputs transfer(FunctionExecutionContext& exec_c // Make the exec_ctx aware of the contract's layout. init_contract(exec_ctx); - // Convert params into circuit types: + // Convert arguments into circuit types: auto& composer = exec_ctx.composer; CT::fr amount = to_ct(composer, _amount); @@ -40,6 +40,9 @@ OptionalPrivateCircuitPublicInputs transfer(FunctionExecutionContext& exec_c auto& oracle = exec_ctx.oracle; CT::address msg_sender = oracle.get_msg_sender(); + // Syntactic sugar for a state variable: + // Note: these Mappings always map-from a field type (because it was complicated enough!!!) + // mapping(asset_id => mapping(owner => UTXOSet< >)) balances; Mapping>> balances(&exec_ctx, "balances"); /**************************************************************** @@ -49,6 +52,7 @@ OptionalPrivateCircuitPublicInputs transfer(FunctionExecutionContext& exec_c CT::address creator_address = CT::address::conditional_assign(reveal_msg_sender_to_recipient, msg_sender, CT::address(0)); + // TODO: sort & filter functions! std::vector old_balance_notes = balances[asset_id][msg_sender.to_field()].get(2, { .owner = msg_sender }); @@ -56,7 +60,7 @@ OptionalPrivateCircuitPublicInputs transfer(FunctionExecutionContext& exec_c CT::fr old_value_2 = *(old_balance_notes[1].get_preimage().value); // MISSING: overflow & underflow checks, but I can't be bothered with safe_uint or range checks yet. - CT::fr change = (old_value_1 + old_value_2) - amount; + CT::fr change = (old_value_1 + old_value_2) - (amount + fee); old_balance_notes[0].remove(); old_balance_notes[1].remove(); @@ -91,6 +95,7 @@ OptionalPrivateCircuitPublicInputs transfer(FunctionExecutionContext& exec_c public_inputs.args[4] = CT::fr(reveal_msg_sender_to_recipient); public_inputs.args[5] = fee; + // Emit events public_inputs.emitted_events[0] = CT::fr::copy_as_new_witness(composer, fee); public_inputs.emitted_events[1] = CT::fr::copy_as_new_witness(composer, asset_id); diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp index 8055b7001a7..aa8491bc6cb 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp @@ -1,78 +1,104 @@ -// #include "withdraw.hpp" +#include "withdraw.hpp" -// #include "contract.hpp" +#include "contract.hpp" -// #include -// #include +#include -// namespace aztec3::circuits::apps::test_apps::escrow { +namespace aztec3::circuits::apps::test_apps::escrow { -// using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; +using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; -// OptionalPrivateCircuitPublicInputs withdraw(FunctionExecutionContext& exec_ctx, -// NT::fr const& _amount, -// NT::fr const& _asset_id, -// NT::fr const& _memo, -// NT::fr const& _l1_withdrawal_address, -// NT::fr const& _fee) -// { -// info("\n\nin withdraw..."); +OptionalPrivateCircuitPublicInputs withdraw(FunctionExecutionContext& exec_ctx, + NT::fr const& _amount, + NT::fr const& _asset_id, + NT::fr const& _memo, + NT::fr const& _l1_withdrawal_address, + NT::fr const& _fee) +{ + /**************************************************************** + * Initialisation + ****************************************************************/ -// // Initialisation *************************************************************** + // Make the exec_ctx aware of the contract's layout. + Contract contract = init_contract(exec_ctx); -// auto& composer = exec_ctx.composer; -// auto& oracle = exec_ctx.oracle; -// Contract contract = init_contract(exec_ctx); + // Convert arguments into circuit types: + auto& composer = exec_ctx.composer; -// CT::fr amount = to_ct(composer, _amount); -// CT::fr asset_id = to_ct(composer, _asset_id); -// CT::fr memo = to_ct(composer, _memo); -// CT::fr l1_withdrawal_address = to_ct(composer, _l1_withdrawal_address); -// CT::fr fee = to_ct(composer, _fee); + CT::fr amount = to_ct(composer, _amount); + CT::fr asset_id = to_ct(composer, _asset_id); + CT::fr memo = to_ct(composer, _memo); + CT::fr l1_withdrawal_address = to_ct(composer, _l1_withdrawal_address); + CT::fr fee = to_ct(composer, _fee); -// // Get states and globals ******************************************************* + /**************************************************************** + * Get States & Globals used by the function + ****************************************************************/ -// CT::address msg_sender = oracle.get_msg_sender(); + auto& oracle = exec_ctx.oracle; + CT::address msg_sender = oracle.get_msg_sender(); -// auto& balances = contract.get_private_state_var("balances"); + // Syntactic sugar for a state variable: + // Note: these Mappings always map-from a field type (because it was complicated enough!!!) + // mapping(asset_id => mapping(owner => UTXOSet< >)) balances; + Mapping>> balances(&exec_ctx, "balances"); -// // Circuit-specific logic ******************************************************* + /**************************************************************** + * BODY + ****************************************************************/ -// balances.at({ msg_sender.to_field(), asset_id }) -// .subtract({ -// .value = amount + fee, -// .owner = msg_sender, -// .creator_address = msg_sender, -// .memo = memo, -// }); + // TODO: sort & filter functions! + std::vector old_balance_notes = + balances[asset_id][msg_sender.to_field()].get(2, { .owner = msg_sender }); -// auto& l1_withdraw_function = contract.get_l1_function("withdraw"); + CT::fr old_value_1 = *(old_balance_notes[0].get_preimage().value); + CT::fr old_value_2 = *(old_balance_notes[1].get_preimage().value); -// // TODO: this doesn't do anything at the moment: -// l1_withdraw_function.call({ asset_id, amount, msg_sender.to_field() }); + // MISSING: overflow & underflow checks, but I can't be bothered with safe_uint or range checks yet. + CT::fr change = (old_value_1 + old_value_2) - (amount + fee); -// // Assign circuit-specific public inputs **************************************** + old_balance_notes[0].remove(); + old_balance_notes[1].remove(); -// auto& public_inputs = exec_ctx.private_circuit_public_inputs; + // Return change to self: + balances[asset_id][msg_sender.to_field()].insert({ + .value = change, + .owner = msg_sender, + .creator_address = msg_sender, + .memo = memo, + }); -// public_inputs.args[0] = amount; -// public_inputs.args[1] = asset_id; -// public_inputs.args[2] = memo; -// public_inputs.args[3] = l1_withdrawal_address; -// public_inputs.args[4] = fee; + auto& l1_withdraw_function = contract.get_l1_function("withdraw"); -// public_inputs.emitted_events[0] = CT::fr::copy_as_new_witness(composer, l1_withdrawal_address); -// public_inputs.emitted_events[1] = CT::fr::copy_as_new_witness(composer, asset_id); -// public_inputs.emitted_events[2] = CT::fr::copy_as_new_witness(composer, fee); + // TODO: this doesn't do anything at the moment: + l1_withdraw_function.call({ asset_id, amount, msg_sender.to_field() }); -// exec_ctx.finalise(); + /**************************************************************** + * CLEANUP + ****************************************************************/ -// /// TODO: merkle membership check -// // public_inputs.old_private_data_tree_root + // Push args to the public inputs. + auto& public_inputs = exec_ctx.private_circuit_public_inputs; -// info("public inputs: ", public_inputs); + public_inputs.args[0] = amount; + public_inputs.args[1] = asset_id; + public_inputs.args[2] = memo; + public_inputs.args[3] = l1_withdrawal_address; + public_inputs.args[4] = fee; -// return public_inputs.to_native_type(); -// }; + // Emit events + public_inputs.emitted_events[0] = CT::fr::copy_as_new_witness(composer, l1_withdrawal_address); + public_inputs.emitted_events[1] = CT::fr::copy_as_new_witness(composer, asset_id); + public_inputs.emitted_events[2] = CT::fr::copy_as_new_witness(composer, fee); -// } // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file + exec_ctx.finalise(); + + /// TODO: merkle membership check + // public_inputs.old_private_data_tree_root + + info("public inputs: ", public_inputs); + + return public_inputs.to_native_type(); +}; + +} // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.hpp index 1163bc7a011..41a3c35d870 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.hpp @@ -1,19 +1,19 @@ -// #pragma once +#pragma once -// #include "init.hpp" +#include "init.hpp" -// #include -// #include +#include +#include -// namespace aztec3::circuits::apps::test_apps::escrow { +namespace aztec3::circuits::apps::test_apps::escrow { -// using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; +using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; -// OptionalPrivateCircuitPublicInputs withdraw(FunctionExecutionContext& exec_ctx, -// NT::fr const& _amount, -// NT::fr const& _asset_id, -// NT::fr const& _memo, -// NT::fr const& _l1_withdrawal_address, -// NT::fr const& _fee); +OptionalPrivateCircuitPublicInputs withdraw(FunctionExecutionContext& exec_ctx, + NT::fr const& _amount, + NT::fr const& _asset_id, + NT::fr const& _memo, + NT::fr const& _l1_withdrawal_address, + NT::fr const& _fee); -// } // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file +} // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/type_check.hpp b/circuits/src/aztec3/circuits/apps/type_check.hpp deleted file mode 100644 index 237ea6b0863..00000000000 --- a/circuits/src/aztec3/circuits/apps/type_check.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -namespace aztec3::circuits::apps { - -template struct isMap { - static constexpr bool value = false; -}; - -template struct isMap> { - static constexpr bool value = true; -}; - -} // namespace aztec3::circuits::apps \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/utxo_datum.hpp b/circuits/src/aztec3/circuits/apps/utxo_datum.hpp index 90d34a3c73b..26c66506bfd 100644 --- a/circuits/src/aztec3/circuits/apps/utxo_datum.hpp +++ b/circuits/src/aztec3/circuits/apps/utxo_datum.hpp @@ -1,9 +1,5 @@ #pragma once -// #include "function_execution_context.hpp" - -// #include "../private_state_note_preimage.hpp" - #include #include #include @@ -33,9 +29,6 @@ template struct UTXOSLoadDatum { template auto to_circuit_type(Composer& composer) const { - // typedef CircuitTypes CT; - // typedef NativeTypes NT; - static_assert(std::is_same::value); // Capture the composer: @@ -50,29 +43,6 @@ template struct UTXOSLoadDatum { return datum; }; - - // template using NotePreimageCT = NotePreimage>; - - // template - // UTXOSLoadDatum, NotePreimageCT> to_circuit_type(Composer& composer) const - // { - // typedef CircuitTypes CT; - // typedef NativeTypes NT; - - // static_assert((std::is_same::value)); - - // // Capture the composer: - // auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; - - // NotePreimageCT preimage_ct = preimage.to_circuit_type(composer); - - // UTXOSLoadDatum, NotePreimageCT> datum = { - // preimage_ct, to_ct(commitment), to_ct(sibling_path), to_ct(leaf_index), - // to_ct(old_private_data_tree_root), - // }; - - // return datum; - // }; }; } // namespace aztec3::circuits::apps From a49fe51e4c81fbd95fb40b5096e6257d9c8715cf Mon Sep 17 00:00:00 2001 From: iAmMichaelConnor Date: Thu, 5 Jan 2023 13:34:18 +0000 Subject: [PATCH 024/166] commenting & tidying --- circuits/src/aztec3/circuits/apps/README.md | 73 +-- .../apps/notes/default_private_note/note.hpp | 10 +- .../apps/notes/default_private_note/note.tpp | 10 +- .../default_private_note/note_preimage.hpp | 2 + .../nullifier_preimage.hpp | 2 + .../aztec3/circuits/apps/opcodes/opcodes.hpp | 6 + .../apps/state_vars/mapping_state_var.hpp | 12 +- .../apps/state_vars/state_var_base.hpp | 25 +- .../apps/state_vars/utxo_set_state_var.hpp | 8 + .../apps/state_vars/utxo_state_var.hpp | 11 +- .../aztec3/circuits/kernel/private/.test.cpp | 497 ++++++++------- .../aztec3/circuits/kernel/private/index.hpp | 4 +- .../aztec3/circuits/kernel/private/init.hpp | 48 +- .../kernel/private/private_kernel_circuit.cpp | 575 +++++++++--------- .../kernel/private/private_kernel_circuit.hpp | 20 +- 15 files changed, 632 insertions(+), 671 deletions(-) diff --git a/circuits/src/aztec3/circuits/apps/README.md b/circuits/src/aztec3/circuits/apps/README.md index 6688506f6ff..90693176092 100644 --- a/circuits/src/aztec3/circuits/apps/README.md +++ b/circuits/src/aztec3/circuits/apps/README.md @@ -3,76 +3,7 @@ All code in this dir is for: - Demonstrating how our users' (developers) apps will need to be written, in terms of: - Public inputs - - Commitment/nullifier creation (recommendations) + - Syntax for State Variables & UTXOs - Function calls - - Everything from the 'Noir Examples' section of the Aztec3 book. - To help illustrate ideas to the Noir team -- To allow test app circuits to be mocked-up as quickly and easily as possible - -## Private State Code - -This is some complex code, which attempts to abstract-away stuff to do with creating commitments, nullifiers, and Aztec3 public input ABIs. All that, so that test app circuits can be mocked-up without too much faff. Some explanation is needed: - -``` -contract_factory - |___private_state_factory - |___private_state_vars - | |___private_state_var (fr state) - | |___private_state_var (mapping state) - | |___private_state_var (fr state) - | |... - | |___private_state_var (fr state) - | ___________________| - | | fr states can creates notes - | v - |___private_state_notes - | |___private_state_note - | |___private_state_note_preimage - | | - | |___ preimage members are std::optional - | so that partial commitments can be - | created in one tx, and completed in - | a later tx. - | - |___commitments - |___nullifiers once all notes have been created by the circuit, we can - `finalise()` the state_factory. This will figure out whether - we need more: - - dummy nullifiers (to use as input_nullifiers to - commitments). - Only at this stage are the commitments (and partial commitments) - and nullifiers computed. -``` - -ContractFactory -- Composer& composer; -- OracleWrapperInterface& oracle; -- const std::string contract_name; -- PrivateStateFactory private_state_factory; -- std::map> function_signatures; -- std::map> l1_functions; - -PrivateStateFactory -- Composer& composer; -- OracleWrapperInterface& oracle; -- const std::string contract_name; -- fr private_state_counter = 0; -- std::map> private_state_vars; -- std::vector> private_state_notes; -- std::vector commitments; -- std::vector nullifiers; - -PrivateStateVar -- PrivateStateFactory* state_factory; -- PrivateStateType private_state_type; -- std::string name; -- fr start_slot; -- grumpkin_point storage_slot_point; -- std::map> private_states; -- bool is_mapping = false; -- std::optional> mapping_key_names = std::nullopt; -- bool is_partial_slot = false; - -PrivateStateNote -- PrivateStateVar& private_state_var; -- PrivateStateNotePreimage preimage; \ No newline at end of file +- To allow test app circuits to be mocked-up as quickly and easily as possible, for use in the Kernel & Rollup circuits. \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.hpp b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.hpp index 5190fe8dba4..0d9630dd3b4 100644 --- a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.hpp +++ b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.hpp @@ -13,15 +13,11 @@ // Forward-declare from this namespace in particular: namespace aztec3::circuits::apps::state_vars { template class StateVar; -template class UTXOStateVar; -template class UTXOSetStateVar; } // namespace aztec3::circuits::apps::state_vars namespace aztec3::circuits::apps::notes { -using aztec3::circuits::apps::state_vars::StateVar; // Don't #include it! -using aztec3::circuits::apps::state_vars::UTXOSetStateVar; // Don't #include it! -using aztec3::circuits::apps::state_vars::UTXOStateVar; // Don't #include it! +using aztec3::circuits::apps::state_vars::StateVar; // Don't #include it! using plonk::stdlib::types::CircuitTypes; using plonk::stdlib::types::NativeTypes; @@ -37,8 +33,6 @@ template class DefaultPrivateNote : publ typedef typename CT::address address; typedef typename CT::boolean boolean; - // using VariantUTXOStateVar = - // std::variant, UTXOSetStateVar>; using NotePreimage = DefaultPrivateNotePreimage, ValueType>; using NullifierPreimage = DefaultPrivateNoteNullifierPreimage>; @@ -124,8 +118,6 @@ template class DefaultPrivateNote : publ bool is_partial_preimage() const; bool is_partial_storage_slot() const; bool is_partial() const; - - // bool check_if_partial() const = 0; }; } // namespace aztec3::circuits::apps::notes diff --git a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.tpp b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.tpp index f924df506c7..61c1acf1839 100644 --- a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.tpp +++ b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.tpp @@ -7,8 +7,6 @@ #include "../../opcodes/opcodes.hpp" #include "../../state_vars/state_var_base.hpp" -#include "../../state_vars/utxo_state_var.hpp" -#include "../../state_vars/utxo_set_state_var.hpp" #include @@ -26,8 +24,6 @@ namespace { using aztec3::circuits::apps::opcodes::Opcodes; using aztec3::circuits::apps::state_vars::StateVar; -using aztec3::circuits::apps::state_vars::UTXOSetStateVar; -using aztec3::circuits::apps::state_vars::UTXOStateVar; } // namespace namespace aztec3::circuits::apps::notes { @@ -179,12 +175,12 @@ typename CircuitTypes::fr DefaultPrivateNote::compute_nul if (is_partial()) { throw_or_abort("Can't nullify a partial note."); } - if (!commitment) { - compute_commitment(); - } if (nullifier && nullifier_preimage) { return *nullifier; } + if (!commitment) { + compute_commitment(); + } fr& owner_private_key = get_oracle().get_msg_sender_private_key(); diff --git a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note_preimage.hpp b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note_preimage.hpp index 8891894eb4f..80ba1e87951 100644 --- a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note_preimage.hpp +++ b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note_preimage.hpp @@ -2,7 +2,9 @@ #include #include + #include + #include #include #include diff --git a/circuits/src/aztec3/circuits/apps/notes/default_private_note/nullifier_preimage.hpp b/circuits/src/aztec3/circuits/apps/notes/default_private_note/nullifier_preimage.hpp index f123eb472f5..fac86d2e520 100644 --- a/circuits/src/aztec3/circuits/apps/notes/default_private_note/nullifier_preimage.hpp +++ b/circuits/src/aztec3/circuits/apps/notes/default_private_note/nullifier_preimage.hpp @@ -1,7 +1,9 @@ #pragma once #include #include + #include + #include #include #include diff --git a/circuits/src/aztec3/circuits/apps/opcodes/opcodes.hpp b/circuits/src/aztec3/circuits/apps/opcodes/opcodes.hpp index f0e4a91d28a..058a7cfdd08 100644 --- a/circuits/src/aztec3/circuits/apps/opcodes/opcodes.hpp +++ b/circuits/src/aztec3/circuits/apps/opcodes/opcodes.hpp @@ -20,6 +20,12 @@ using plonk::stdlib::witness_t; using plonk::stdlib::types::CircuitTypes; using plonk::stdlib::types::NativeTypes; +/** + * @brief - These static methods are a suggestion for what ACIR++ 'Opcodes' might do. They combine directives to get + * data from an oracle, and then apply constraints to that data. Separating out this functionality into a separate + * `Opcodes` class, like this, was trickier than just writing this stuff directly in the `Note` or + * `FunctionExecutionContext` classes, but hopefully the separation is tidier. + */ template class Opcodes { public: typedef CircuitTypes CT; diff --git a/circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.hpp b/circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.hpp index 8b07f74bb51..551538a6671 100644 --- a/circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.hpp +++ b/circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.hpp @@ -19,8 +19,11 @@ using plonk::stdlib::types::CircuitTypes; using plonk::stdlib::types::NativeTypes; /** - * Note: we restrict mapping keys to always be something which is convertible into a `field` type. This is to allow - * storage_slot_points to be computed more easily. You'll notice, therefore, that there's no Key template type. + * @tparam V - the value type being mapped-to by this mapping. + * + * Note: we restrict mapping _keys_ to always be a `field` type. This is to allow storage_slot_points to be computed + * more easily (it was difficult enough to get working). You'll notice, therefore, that there's no Key template type; + * only a value template type (`V`). Adding a Key template type could be a future enhancement. */ template class MappingStateVar : public StateVar { public: @@ -38,7 +41,10 @@ template class MappingStateVar : public StateVar MappingStateVar(FunctionExecutionContext* exec_ctx, std::string const& state_var_name) : StateVar(exec_ctx, state_var_name){}; - // Instantiate a nested mapping: + // Instantiate a nested mapping (within some other container). + // Note: we assume this is called by some other StateVar, and the params have been computed correctly. + // TODO: we could specify a set of `friend` classes which may access this method, to make this assumption more + // explicit. MappingStateVar(FunctionExecutionContext* exec_ctx, std::string const& state_var_name, grumpkin_point const& storage_slot_point, diff --git a/circuits/src/aztec3/circuits/apps/state_vars/state_var_base.hpp b/circuits/src/aztec3/circuits/apps/state_vars/state_var_base.hpp index 876a0d7b9c8..3f311d6c446 100644 --- a/circuits/src/aztec3/circuits/apps/state_vars/state_var_base.hpp +++ b/circuits/src/aztec3/circuits/apps/state_vars/state_var_base.hpp @@ -15,6 +15,11 @@ using aztec3::circuits::apps::FunctionExecutionContext; // Don't #include it! using plonk::stdlib::types::CircuitTypes; using plonk::stdlib::types::NativeTypes; +/** + * @brief StateVar is a base class from which contract state variables are derived. Its main purpose is deriving storage + * slots, and generating constraints for those slot derivations, in a protocol-consistent way, regardless of the app + * being written. + */ template class StateVar { public: typedef CircuitTypes CT; @@ -22,15 +27,31 @@ template class StateVar { typedef typename CT::fr fr; typedef typename CT::grumpkin_point grumpkin_point; + // The execution context of the function currently being executed. FunctionExecutionContext* exec_ctx; + // Must match the name of a state which has been declared to the `Contract`. std::string state_var_name; + // The `start slot` of the state variable is the slot which is assigned to this particular state by the `Contract`, + // based on the ordering of declarations of the _names_ of states. For container types (mappings/arrays/structs), + // the state variable might be able to access multiple storage slots. The start slot is the 'starting point' for + // deriving such slots. fr start_slot; + + // The 'storage slot point' of the state variable. Having a _point_ for every storage slot allows for + // partial-commitment functionality. + // I.e. we can generate placeholder storage slots, which can be partially-committed to in one function, and then + // completed in some future function, once the mapping keys or array indices at which we'd like to store the data + // are known in future. Aztec Connect does something similar (the `asset_id` of the output value note isn't known + // until later, so is partially committed-to). grumpkin_point storage_slot_point; - // In order to calculate the correct storage_slot_point, we need to know how many containers we're nested inside, so - // that we can find the correct Pedersen generator. + + // In order to calculate the correct storage_slot_point, we need to know how many containers + // we're nested inside, so that we can find the correct Pedersen generator. size_t level_of_container_nesting = 0; + + // Optionally informs custom notes whether they should commit or partially-commit to this state. bool is_partial_slot = false; StateVar(){}; diff --git a/circuits/src/aztec3/circuits/apps/state_vars/utxo_set_state_var.hpp b/circuits/src/aztec3/circuits/apps/state_vars/utxo_set_state_var.hpp index ff381fe0326..56dc448035d 100644 --- a/circuits/src/aztec3/circuits/apps/state_vars/utxo_set_state_var.hpp +++ b/circuits/src/aztec3/circuits/apps/state_vars/utxo_set_state_var.hpp @@ -17,6 +17,14 @@ using aztec3::circuits::apps::FunctionExecutionContext; // Don't #include it! using plonk::stdlib::types::CircuitTypes; using plonk::stdlib::types::NativeTypes; +/** + * @brief - A derived StateVar which represents an unordered set of UTXOs which live in the UTXO tree. + * Notice the `get` and `insert` methods for this StateVar, which interact with the UTXO tree opcodes. + * + * @tparam Note - A UTXO state variable always acts on notes and note preimages. We allow for custom Note types to be + * designed. The Note type must implement the NoteInterface. TODO: maybe explicitly have this class act on the + * NoteInterface type, rather than a template type. + */ template class UTXOSetStateVar : public StateVar { public: typedef CircuitTypes CT; diff --git a/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp b/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp index 97dd67b1180..ed3ae808731 100644 --- a/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp +++ b/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp @@ -17,6 +17,15 @@ using aztec3::circuits::apps::FunctionExecutionContext; // Don't #include it! using plonk::stdlib::types::CircuitTypes; using plonk::stdlib::types::NativeTypes; +/** + * @brief - A derived StateVar which represents a singleton UTXO type. I.e. a state which can only ever have at-most ONE + * non-nullified UTXO in the tree at any time. Notice the `get` and `insert` methods for this StateVar, which interact + * with the UTXO tree opcodes. + * + * @tparam Note - A UTXO state variable always acts on notes and note preimages. We allow for custom Note types to be + * designed. The Note type must implement the NoteInterface. TODO: maybe explicitly have this class act on the + * NoteInterface type, rather than a template type. + */ template class UTXOStateVar : public StateVar { public: typedef CircuitTypes CT; @@ -41,8 +50,6 @@ template class UTXOStateVar : public StateVar : StateVar( exec_ctx, state_var_name, storage_slot_point, level_of_container_nesting, is_partial_slot){}; - // bool operator==(UTXOStateVar const&) const = default; - /** * @param advice - For NotePreimages, we allow 'advice' to be given, so that the correct DB entry is * chosen. diff --git a/circuits/src/aztec3/circuits/kernel/private/.test.cpp b/circuits/src/aztec3/circuits/kernel/private/.test.cpp index 8d5e49b81b1..c4af8b8da35 100644 --- a/circuits/src/aztec3/circuits/kernel/private/.test.cpp +++ b/circuits/src/aztec3/circuits/kernel/private/.test.cpp @@ -1,251 +1,248 @@ -// // #include -// // #include -// // #include -// // #include -// // #include -// #include "index.hpp" - -// #include - -// #include -// #include -// #include -// #include -// #include -// #include -// #include +// #include +// #include +// #include +// #include +// #include +#include "index.hpp" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // #include -// #include -// #include -// #include -// #include -// #include -// // #include -// // #include - -// // #include -// #include - -// #include -// #include -// #include - -// // #include -// // #include -// // #include - -// namespace { - -// using aztec3::circuits::abis::CallContext; -// using aztec3::circuits::abis::CallStackItem; -// using aztec3::circuits::abis::CallType; -// using aztec3::circuits::abis::FunctionSignature; -// using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; -// using aztec3::circuits::abis::PrivateCircuitPublicInputs; -// using aztec3::circuits::abis::SignedTxObject; -// using aztec3::circuits::abis::TxContext; -// using aztec3::circuits::abis::TxObject; - -// using aztec3::circuits::abis::private_kernel::AccumulatedData; -// using aztec3::circuits::abis::private_kernel::ConstantData; -// using aztec3::circuits::abis::private_kernel::Globals; -// using aztec3::circuits::abis::private_kernel::OldTreeRoots; -// using aztec3::circuits::abis::private_kernel::PreviousKernelData; -// using aztec3::circuits::abis::private_kernel::PrivateCallData; -// using aztec3::circuits::abis::private_kernel::PrivateInputs; -// using aztec3::circuits::abis::private_kernel::PublicInputs; - -// using aztec3::circuits::apps::test_apps::escrow::deposit; - -// // using aztec3::circuits::mock::mock_circuit; -// using aztec3::circuits::mock::mock_kernel_circuit; - -// } // namespace - -// namespace aztec3::circuits::kernel::private_kernel { - -// class private_kernel_tests : public ::testing::Test {}; - -// TEST(private_kernel_tests, test_deposit) -// { -// //*************************************************************************** -// // Some private circuit proof (`deposit`, in this case) -// //*************************************************************************** - -// const NT::address escrow_contract_address = 12345; -// const NT::fr escrow_contract_leaf_index = 1; -// const NT::fr escrow_portal_contract_address = 23456; - -// const NT::fr msg_sender_private_key = 123456789; -// const NT::address msg_sender = -// NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, -// 0x2ef9f7f09867fd6eULL)); -// const NT::address tx_origin = msg_sender; - -// Composer deposit_composer; -// DB db; - -// NativeOracle deposit_oracle = -// NativeOracle(db, escrow_contract_address, msg_sender, tx_origin, msg_sender_private_key); -// OracleWrapper deposit_oracle_wrapper = OracleWrapper(deposit_composer, deposit_oracle); - -// FunctionExecutionContext deposit_ctx(deposit_composer, deposit_oracle_wrapper); - -// auto amount = NT::fr(5); -// auto asset_id = NT::fr(1); -// auto memo = NT::fr(999); - -// OptionalPrivateCircuitPublicInputs opt_deposit_public_inputs = deposit(deposit_ctx, amount, asset_id, memo); -// PrivateCircuitPublicInputs deposit_public_inputs = opt_deposit_public_inputs.remove_optionality(); - -// UnrolledProver deposit_prover = deposit_composer.create_unrolled_prover(); -// NT::Proof deposit_proof = deposit_prover.construct_proof(); -// // info("\ndeposit_proof: ", deposit_proof.proof_data); - -// std::shared_ptr deposit_vk = deposit_composer.compute_verification_key(); - -// //*************************************************************************** -// // We can create a TxObject from some of the above data. Users must sign a TxObject in order to give permission -// for -// // a tx to take place - creating a SignedTxObject. -// //*************************************************************************** - -// TxObject deposit_tx_object = TxObject{ -// .from = tx_origin, -// .to = escrow_contract_address, -// .function_signature = -// FunctionSignature{ -// .vk_index = 0, // TODO: deduce this from the contract, somehow. -// .is_private = true, -// .is_constructor = false, -// }, -// .args = deposit_public_inputs.args, -// .nonce = 0, -// .tx_context = -// TxContext{ -// .called_from_l1 = false, -// .called_from_public_l2 = false, -// .is_fee_payment_tx = false, -// .reference_block_num = 0, -// }, -// .chain_id = 1, -// }; - -// SignedTxObject signed_deposit_tx_object = SignedTxObject{ -// .tx_object = deposit_tx_object, - -// // .signature = TODO: need a method for signing a TxObject. -// }; - -// //*************************************************************************** -// // We mock a kernel circuit proof for the base case of kernel recursion (because even the first iteration of the -// // kernel circuit expects to verify some previous kernel circuit). -// //*************************************************************************** - -// Composer mock_kernel_composer; - -// // TODO: we have a choice to make: -// // Either the `end` state of the mock kernel's public inputs can be set equal to the public call we _want_ to -// // verify in the first round of recursion, OR, we have some fiddly conditional logic in the circuit to ignore -// // certain checks if we're handling the 'base case' of the recursion. -// // I've chosen the former, for now. -// const CallStackItem deposit_call_stack_item{ -// .contract_address = deposit_tx_object.to, - -// .function_signature = deposit_tx_object.function_signature, - -// .public_inputs = deposit_public_inputs, -// }; - -// std::array initial_kernel_private_call_stack{}; -// initial_kernel_private_call_stack[0] = deposit_call_stack_item.hash(); - -// // Some test data: -// auto mock_kernel_public_inputs = PublicInputs{ -// .end = -// AccumulatedData{ -// .private_call_stack = initial_kernel_private_call_stack, -// }, - -// // These will be constant throughout all recursions, so can be set to those of the first function call - the -// // deposit tx. -// .constants = -// ConstantData{ -// .old_tree_roots = -// OldTreeRoots{ -// .private_data_tree_root = deposit_public_inputs.old_private_data_tree_root, -// // .nullifier_tree_root = -// // .contract_tree_root = -// // .private_kernel_vk_tree_root = -// }, -// .tx_context = deposit_tx_object.tx_context, -// }, - -// .is_private = true, -// // .is_public = false, -// // .is_contract_deployment = false, -// }; - -// mock_kernel_circuit(mock_kernel_composer, mock_kernel_public_inputs); - -// UnrolledProver mock_kernel_prover = mock_kernel_composer.create_unrolled_prover(); -// NT::Proof mock_kernel_proof = mock_kernel_prover.construct_proof(); -// // info("\nmock_kernel_proof: ", mock_kernel_proof.proof_data); - -// std::shared_ptr mock_kernel_vk = mock_kernel_composer.compute_verification_key(); - -// //*************************************************************************** -// // Now we can execute and prove the first kernel iteration, with all the data generated above: -// // - app proof, public inputs, etc. -// // - mock kernel proof, public inputs, etc. -// //*************************************************************************** - -// Composer private_kernel_composer; - -// // TODO: I think we need a different kind of oracle for the kernel circuits... -// NativeOracle private_kernel_oracle = NativeOracle(db, escrow_contract_address, msg_sender, -// msg_sender_private_key); OracleWrapper private_kernel_oracle_wrapper = OracleWrapper(private_kernel_composer, -// private_kernel_oracle); - -// PrivateInputs private_inputs = PrivateInputs{ -// .signed_tx_object = signed_deposit_tx_object, - -// .previous_kernel = -// PreviousKernelData{ -// .public_inputs = mock_kernel_public_inputs, -// .proof = mock_kernel_proof, -// .vk = mock_kernel_vk, -// }, - -// .private_call = -// PrivateCallData{ -// .call_stack_item = deposit_call_stack_item, -// // .call_context_reconciliation_data = TODO - -// .proof = deposit_proof, -// .vk = deposit_vk, -// // .vk_path TODO - -// // .contract_tree_root TODO -// .contract_leaf_index = escrow_contract_leaf_index, -// // .contract_path TODO - -// .portal_contract_address = escrow_portal_contract_address, -// }, -// }; - -// private_kernel_circuit(private_kernel_composer, private_kernel_oracle_wrapper, private_inputs); - -// info("computed witness: ", private_kernel_composer.computed_witness); -// info("witness: ", private_kernel_composer.witness); -// // info("constant variables: ", private_kernel_composer.constant_variables); -// // info("variables: ", private_kernel_composer.variables); - -// // TODO: this fails intermittently, with: -// // bigfield multiply range check failed -// info("failed?: ", private_kernel_composer.failed); -// info("err: ", private_kernel_composer.err); -// info("n: ", private_kernel_composer.n); -// } - -// } // namespace aztec3::circuits::kernel::private_kernel \ No newline at end of file +// #include + +// #include +#include + +#include +#include +#include + +// #include +// #include +// #include + +namespace { + +using aztec3::circuits::abis::CallContext; +using aztec3::circuits::abis::CallStackItem; +using aztec3::circuits::abis::CallType; +using aztec3::circuits::abis::FunctionSignature; +using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; +using aztec3::circuits::abis::PrivateCircuitPublicInputs; +using aztec3::circuits::abis::SignedTxObject; +using aztec3::circuits::abis::TxContext; +using aztec3::circuits::abis::TxObject; + +using aztec3::circuits::abis::private_kernel::AccumulatedData; +using aztec3::circuits::abis::private_kernel::ConstantData; +using aztec3::circuits::abis::private_kernel::Globals; +using aztec3::circuits::abis::private_kernel::OldTreeRoots; +using aztec3::circuits::abis::private_kernel::PreviousKernelData; +using aztec3::circuits::abis::private_kernel::PrivateCallData; +using aztec3::circuits::abis::private_kernel::PrivateInputs; +using aztec3::circuits::abis::private_kernel::PublicInputs; + +using aztec3::circuits::apps::test_apps::escrow::deposit; + +// using aztec3::circuits::mock::mock_circuit; +using aztec3::circuits::mock::mock_kernel_circuit; + +} // namespace + +namespace aztec3::circuits::kernel::private_kernel { + +class private_kernel_tests : public ::testing::Test {}; + +TEST(private_kernel_tests, test_deposit) +{ + //*************************************************************************** + // Some private circuit proof (`deposit`, in this case) + //*************************************************************************** + + const NT::address escrow_contract_address = 12345; + const NT::fr escrow_contract_leaf_index = 1; + const NT::fr escrow_portal_contract_address = 23456; + + const NT::fr msg_sender_private_key = 123456789; + const NT::address msg_sender = + NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); + const NT::address tx_origin = msg_sender; + + Composer deposit_composer; + DB db; + + NativeOracle deposit_oracle = + NativeOracle(db, escrow_contract_address, msg_sender, tx_origin, msg_sender_private_key); + OracleWrapper deposit_oracle_wrapper = OracleWrapper(deposit_composer, deposit_oracle); + + FunctionExecutionContext deposit_ctx(deposit_composer, deposit_oracle_wrapper); + + auto amount = NT::fr(5); + auto asset_id = NT::fr(1); + auto memo = NT::fr(999); + + OptionalPrivateCircuitPublicInputs opt_deposit_public_inputs = deposit(deposit_ctx, amount, asset_id, memo); + PrivateCircuitPublicInputs deposit_public_inputs = opt_deposit_public_inputs.remove_optionality(); + + UnrolledProver deposit_prover = deposit_composer.create_unrolled_prover(); + NT::Proof deposit_proof = deposit_prover.construct_proof(); + // info("\ndeposit_proof: ", deposit_proof.proof_data); + + std::shared_ptr deposit_vk = deposit_composer.compute_verification_key(); + + //*************************************************************************** + // We can create a TxObject from some of the above data. Users must sign a TxObject in order to give permission for + // a tx to take place - creating a SignedTxObject. + //*************************************************************************** + + TxObject deposit_tx_object = TxObject{ + .from = tx_origin, + .to = escrow_contract_address, + .function_signature = + FunctionSignature{ + .vk_index = 0, // TODO: deduce this from the contract, somehow. + .is_private = true, + .is_constructor = false, + }, + .args = deposit_public_inputs.args, + .nonce = 0, + .tx_context = + TxContext{ + .called_from_l1 = false, + .called_from_public_l2 = false, + .is_fee_payment_tx = false, + .reference_block_num = 0, + }, + .chain_id = 1, + }; + + SignedTxObject signed_deposit_tx_object = SignedTxObject{ + .tx_object = deposit_tx_object, + + // .signature = TODO: need a method for signing a TxObject. + }; + + //*************************************************************************** + // We mock a kernel circuit proof for the base case of kernel recursion (because even the first iteration of the + // kernel circuit expects to verify some previous kernel circuit). + //*************************************************************************** + + Composer mock_kernel_composer; + + // TODO: we have a choice to make: + // Either the `end` state of the mock kernel's public inputs can be set equal to the public call we _want_ to + // verify in the first round of recursion, OR, we have some fiddly conditional logic in the circuit to ignore + // certain checks if we're handling the 'base case' of the recursion. + // I've chosen the former, for now. + const CallStackItem deposit_call_stack_item{ + .contract_address = deposit_tx_object.to, + + .function_signature = deposit_tx_object.function_signature, + + .public_inputs = deposit_public_inputs, + }; + + std::array initial_kernel_private_call_stack{}; + initial_kernel_private_call_stack[0] = deposit_call_stack_item.hash(); + + // Some test data: + auto mock_kernel_public_inputs = PublicInputs{ + .end = + AccumulatedData{ + .private_call_stack = initial_kernel_private_call_stack, + }, + + // These will be constant throughout all recursions, so can be set to those of the first function call - the + // deposit tx. + .constants = + ConstantData{ + .old_tree_roots = + OldTreeRoots{ + .private_data_tree_root = deposit_public_inputs.old_private_data_tree_root, + // .nullifier_tree_root = + // .contract_tree_root = + // .private_kernel_vk_tree_root = + }, + .tx_context = deposit_tx_object.tx_context, + }, + + .is_private = true, + // .is_public = false, + // .is_contract_deployment = false, + }; + + mock_kernel_circuit(mock_kernel_composer, mock_kernel_public_inputs); + + UnrolledProver mock_kernel_prover = mock_kernel_composer.create_unrolled_prover(); + NT::Proof mock_kernel_proof = mock_kernel_prover.construct_proof(); + // info("\nmock_kernel_proof: ", mock_kernel_proof.proof_data); + + std::shared_ptr mock_kernel_vk = mock_kernel_composer.compute_verification_key(); + + //*************************************************************************** + // Now we can execute and prove the first kernel iteration, with all the data generated above: + // - app proof, public inputs, etc. + // - mock kernel proof, public inputs, etc. + //*************************************************************************** + + Composer private_kernel_composer; + + // TODO: I think we need a different kind of oracle for the kernel circuits... + NativeOracle private_kernel_oracle = NativeOracle(db, escrow_contract_address, msg_sender, msg_sender_private_key); + OracleWrapper private_kernel_oracle_wrapper = OracleWrapper(private_kernel_composer, private_kernel_oracle); + + PrivateInputs private_inputs = PrivateInputs{ + .signed_tx_object = signed_deposit_tx_object, + + .previous_kernel = + PreviousKernelData{ + .public_inputs = mock_kernel_public_inputs, + .proof = mock_kernel_proof, + .vk = mock_kernel_vk, + }, + + .private_call = + PrivateCallData{ + .call_stack_item = deposit_call_stack_item, + // .call_context_reconciliation_data = TODO + + .proof = deposit_proof, + .vk = deposit_vk, + // .vk_path TODO + + // .contract_tree_root TODO + .contract_leaf_index = escrow_contract_leaf_index, + // .contract_path TODO + + .portal_contract_address = escrow_portal_contract_address, + }, + }; + + private_kernel_circuit(private_kernel_composer, private_kernel_oracle_wrapper, private_inputs); + + info("computed witness: ", private_kernel_composer.computed_witness); + info("witness: ", private_kernel_composer.witness); + // info("constant variables: ", private_kernel_composer.constant_variables); + // info("variables: ", private_kernel_composer.variables); + + // TODO: this fails intermittently, with: + // bigfield multiply range check failed + info("failed?: ", private_kernel_composer.failed); + info("err: ", private_kernel_composer.err); + info("n: ", private_kernel_composer.n); +} + +} // namespace aztec3::circuits::kernel::private_kernel \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/kernel/private/index.hpp b/circuits/src/aztec3/circuits/kernel/private/index.hpp index 753db228377..f257de72825 100644 --- a/circuits/src/aztec3/circuits/kernel/private/index.hpp +++ b/circuits/src/aztec3/circuits/kernel/private/index.hpp @@ -1,2 +1,2 @@ -// #include "init.hpp" -// #include "private_kernel_circuit.hpp" \ No newline at end of file +#include "init.hpp" +#include "private_kernel_circuit.hpp" \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/kernel/private/init.hpp b/circuits/src/aztec3/circuits/kernel/private/init.hpp index f3452ceaac7..0de9fc6ecfd 100644 --- a/circuits/src/aztec3/circuits/kernel/private/init.hpp +++ b/circuits/src/aztec3/circuits/kernel/private/init.hpp @@ -1,34 +1,34 @@ -// #pragma once -// #include -// #include -// #include +#pragma once +#include +#include +#include -// #include +#include -// #include +#include -// #include -// #include -// #include -// #include +#include +#include +#include +#include -// namespace aztec3::circuits::kernel::private_kernel { +namespace aztec3::circuits::kernel::private_kernel { -// // Turbo specific, at the moment: -// using Composer = plonk::stdlib::types::turbo::Composer; -// using plonk::stdlib::types::turbo::UnrolledProver; +// Turbo specific, at the moment: +using Composer = plonk::stdlib::types::turbo::Composer; +using plonk::stdlib::types::turbo::UnrolledProver; -// using Aggregator = aztec3::circuits::recursion::TurboAggregator; +using Aggregator = aztec3::circuits::recursion::TurboAggregator; -// // Generic: -// using CT = plonk::stdlib::types::CircuitTypes; -// using NT = plonk::stdlib::types::NativeTypes; -// using plonk::stdlib::types::to_ct; +// Generic: +using CT = plonk::stdlib::types::CircuitTypes; +using NT = plonk::stdlib::types::NativeTypes; +using plonk::stdlib::types::to_ct; -// using DB = oracle::FakeDB; -// using oracle::NativeOracle; -// using OracleWrapper = aztec3::circuits::apps::OracleWrapperInterface; +using DB = oracle::FakeDB; +using oracle::NativeOracle; +using OracleWrapper = aztec3::circuits::apps::OracleWrapperInterface; -// using FunctionExecutionContext = aztec3::circuits::apps::FunctionExecutionContext; +using FunctionExecutionContext = aztec3::circuits::apps::FunctionExecutionContext; -// } // namespace aztec3::circuits::kernel::private_kernel \ No newline at end of file +} // namespace aztec3::circuits::kernel::private_kernel \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp b/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp index 2487c6fe396..1d4f8abc732 100644 --- a/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp +++ b/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp @@ -1,303 +1,296 @@ -// #include "init.hpp" - -// #include -// #include - -// namespace aztec3::circuits::kernel::private_kernel { - -// using aztec3::circuits::abis::private_kernel::PrivateInputs; -// using aztec3::circuits::abis::private_kernel::PublicInputs; - -// /****************************************************************************************************************** -// * Calcs on circuit arrays. -// * TODO: move these array calcs to a common/circuit_array.hpp file. -// *****************************************************************************************************************/ - -// /** -// * Gets the number of contiguous nonzero values of an array. -// * Note: this assumes `0` always means 'not used', so be careful. If you actually want `0` to be counted, you'll need -// * something else. -// */ -// // TODO: move to own file of helper functions. -// template CT::fr array_length(std::array const& arr) -// { -// CT::fr length = 0; -// CT::boolean hit_zero = false; -// for (const auto& e : arr) { -// hit_zero |= e == 0; -// const CT::fr increment = !hit_zero; -// length += increment; -// } -// return length; -// }; - -// /** -// * Note: doesn't remove the last element from the array; only returns it! -// * Note: this assumes `0` always means 'not used', so be careful. If you actually want `0` to be counted, you'll need -// * something else. -// * If it returns `0`, the array is considered 'empty'. -// */ -// template CT::fr array_pop(std::array const& arr) -// { -// CT::fr popped_value; -// CT::boolean already_popped = false; -// for (size_t i = arr.size() - 1; i != (size_t)-1; i--) { -// CT::boolean is_non_zero = arr[i] != 0; -// popped_value = CT::fr::conditional_assign(!already_popped && is_non_zero, arr[i], popped_value); - -// already_popped |= is_non_zero; -// } -// return popped_value; -// }; - -// /** -// * Note: this assumes `0` always means 'not used', so be careful. If you actually want `0` to be counted, you'll need -// * something else. -// */ -// template CT::boolean is_array_empty(std::array const& arr) -// { -// CT::boolean nonzero_found = false; -// for (size_t i = arr.size() - 1; i != (size_t)-1; i--) { -// CT::boolean is_non_zero = arr[i] != 0; -// nonzero_found |= is_non_zero; -// } -// return !nonzero_found; -// }; - -// /** -// * Inserts the `source` array at the first zero-valued index of the `target` array. -// * Fails if the `source` array is too large vs the remaining capacity of the `target` array. -// */ -// template -// void push_array_to_array(std::array const& source, std::array& target) -// { -// CT::fr target_length = array_length(target); -// CT::fr source_length = array_length(source); - -// CT::fr target_capacity = CT::fr(target.size()); -// // TODO: using safe_fr for an underflow check, do: -// // remaining_target_capacity = target_capacity.subtract(target_length + source_length); - -// CT::fr t_i = 0; -// CT::fr next_index = target_length; -// for (const auto& s : source) { -// for (auto& t : target) { -// next_index.assert_not_equal(target_capacity, "Target array capacity exceeded"); -// CT::boolean at_index = t_i == next_index; -// t = CT::fr::conditional_assign(at_index, s, t); -// next_index = CT::fr::conditional_assign(at_index, next_index + 1, next_index); -// ++t_i; -// } -// } -// } - -// /*************************************************************************************************************** -// * End of array calcs. -// **************************************************************************************************************/ - -// // TODO: NEED TO RECONCILE THE `proof`'s public inputs (which are uint8's) with the -// // private_call.call_stack_item.public_inputs! -// CT::AggregationObject verify_proofs(Composer& composer, -// PrivateInputs const& private_inputs, -// size_t const& num_private_call_public_inputs, -// size_t const& num_private_kernel_public_inputs) -// { -// CT::AggregationObject aggregation_object = Aggregator::aggregate( -// &composer, private_inputs.private_call.vk, private_inputs.private_call.proof, -// num_private_call_public_inputs); - -// Aggregator::aggregate(&composer, -// private_inputs.previous_kernel.vk, -// private_inputs.previous_kernel.proof, -// num_private_kernel_public_inputs, -// aggregation_object); - -// return aggregation_object; -// } - -// void initialise_end_values(PrivateInputs const& private_inputs, PublicInputs& public_inputs) -// { -// public_inputs.constants = private_inputs.previous_kernel.public_inputs.constants; - -// // Ensure the arrays are the same as previously, before we start pushing more data onto them: -// auto& end = public_inputs.end; -// const auto& start = private_inputs.previous_kernel.public_inputs.end; - -// end.output_commitments = start.output_commitments; -// end.input_nullifiers = start.input_nullifiers; - -// end.private_call_stack = start.private_call_stack; -// end.public_call_stack = start.public_call_stack; -// end.contract_deployment_call_stack = start.contract_deployment_call_stack; -// end.l1_call_stack = start.l1_call_stack; - -// end.optionally_revealed_data = start.optionally_revealed_data; -// } - -// void update_end_values(PrivateInputs const& private_inputs, PublicInputs& public_inputs) -// { -// const auto private_call_public_inputs = private_inputs.private_call.call_stack_item.public_inputs; - -// const auto& output_commitments = private_call_public_inputs.output_commitments; -// const auto& input_nullifiers = private_call_public_inputs.input_nullifiers; - -// const auto& is_static_call = -// private_inputs.private_call.call_stack_item.public_inputs.call_context.is_static_call; - -// // No state changes are allowed for static calls: -// is_static_call.must_imply(is_array_empty(output_commitments) == true); -// is_static_call.must_imply(is_array_empty(input_nullifiers) == true); - -// const auto& storage_contract_address = -// private_inputs.private_call.call_stack_item.public_inputs.call_context.storage_contract_address; - -// { // commitments & nullifiers -// std::array siloed_output_commitments; -// for (size_t i = 0; i < output_commitments.size(); ++i) { -// siloed_output_commitments[i] = -// CT::fr::conditional_assign(output_commitments[i] == 0, -// 0, -// CT::compress({ storage_contract_address.to_field(), output_commitments[i] -// }, -// GeneratorIndex::OUTER_COMMITMENT)); -// } -// std::array siloed_input_nullifiers; -// for (size_t i = 0; i < input_nullifiers.size(); ++i) { -// siloed_input_nullifiers[i] = -// CT::fr::conditional_assign(input_nullifiers[i] == 0, -// 0, -// CT::compress({ storage_contract_address.to_field(), input_nullifiers[i] }, -// GeneratorIndex::OUTER_NULLIFIER)); -// } - -// push_array_to_array(siloed_output_commitments, public_inputs.end.output_commitments); -// push_array_to_array(siloed_input_nullifiers, public_inputs.end.input_nullifiers); -// } - -// { -// // TODO: we need to pass in UNPACKED stack data. I.e. the preimages of the call_stack_item hashes, so that -// data -// // in the stack can be validated as being correct. (e.g. call_contexts of calls made by the private_call -// // currently being validated). - -// // So we'll need to ensure our test_apps return not only a PrivateCircuitPublicInputs object, but also an -// object -// // containing a TONNE of preimage data. Stuff like: -// // - Stack item preimages -// // - Commitment and nullifier preimages -// // - Hash paths and leaf indices -// // - Any and all preimage data derived by the circuit or through oracle calls. - -// // Update on this topic: I've created call_context_reconciliation_data, which allows the call_context to be -// // efficiently unpacked from a call_stack_item_hash. We'll need some "functions calling functions" tests -// cases -// // to see how best to move this data around neatly. -// } - -// const auto& portal_contract_address = private_inputs.private_call.portal_contract_address; - -// { -// const auto& partial_l1_call_stack = private_call_public_inputs.partial_l1_call_stack; -// std::array l1_call_stack; - -// for (size_t i = 0; i < partial_l1_call_stack.size(); ++i) { -// l1_call_stack[i] = -// CT::fr::conditional_assign(partial_l1_call_stack[i] == 0, -// 0, -// CT::compress({ portal_contract_address, partial_l1_call_stack[i] }, -// GeneratorIndex::L1_CALL_STACK_ITEM)); -// } -// } -// } - -// void validate_private_call_hash(PrivateInputs const& private_inputs) -// { -// const auto& start = private_inputs.previous_kernel.public_inputs.end; -// const auto private_call_hash = array_pop(start.private_call_stack); -// const auto calculated_private_call_hash = private_inputs.private_call.call_stack_item.hash(); - -// private_call_hash.assert_equal(calculated_private_call_hash, "private_call_hash does not reconcile"); -// }; - -// void validate_inputs(PrivateInputs const& private_inputs) -// { - -// const auto& next_call = private_inputs.private_call.call_stack_item; - -// next_call.function_signature.is_private.assert_equal( -// true, "Cannot execute a non-private function with the private kernel circuit"); - -// const auto& start = private_inputs.previous_kernel.public_inputs.end; - -// const CT::boolean is_base_case = start.private_call_count == 0; -// const CT::boolean is_recursive_case = !is_base_case; - -// CT::fr start_private_call_stack_length = array_length(start.private_call_stack); -// CT::fr start_public_call_stack_length = array_length(start.public_call_stack); -// CT::fr start_contract_deployment_call_stack_length = array_length(start.contract_deployment_call_stack); -// CT::fr start_l1_call_stack_length = array_length(start.l1_call_stack); - -// // Base Case -// { -// // Validate callstack lengths: -// is_base_case.must_imply(start_private_call_stack_length == -// 1 // TODO: might change to allow 2, so a fee can be paid. -// && start_public_call_stack_length == 0 && -// start_contract_deployment_call_stack_length == 0 && start_l1_call_stack_length == -// 0, -// "Invalid callstacks for base case."); - -// is_base_case.must_imply(next_call.public_inputs.call_context.is_delegate_call == false && -// next_call.public_inputs.call_context.is_static_call == false, -// "A user cannot make a delegatecall or staticcall"); - -// // The below also prevents delegatecall/staticcall -// is_base_case.must_imply(next_call.public_inputs.call_context.storage_contract_address == -// next_call.contract_address, -// "Storage contract address must be that of the called contract in the base case"); -// } - -// // Recursive Case -// { -// is_recursive_case.must_imply(private_inputs.previous_kernel.public_inputs.is_private == true, -// "Cannot verify a non-private kernel snark in the private kernel circuit"); - -// is_recursive_case.must_imply(next_call.function_signature.is_constructor == false, -// "A constructor must be executed as the first tx in the recursion"); - -// is_recursive_case.must_imply(start_private_call_stack_length != 0); -// } +#include "init.hpp" + +#include +#include + +namespace aztec3::circuits::kernel::private_kernel { + +using aztec3::circuits::abis::private_kernel::PrivateInputs; +using aztec3::circuits::abis::private_kernel::PublicInputs; + +/****************************************************************************************************************** + * Calcs on circuit arrays. + * TODO: move these array calcs to a common/circuit_array.hpp file. + *****************************************************************************************************************/ + +/** + * Gets the number of contiguous nonzero values of an array. + * Note: this assumes `0` always means 'not used', so be careful. If you actually want `0` to be counted, you'll need + * something else. + */ +// TODO: move to own file of helper functions. +template CT::fr array_length(std::array const& arr) +{ + CT::fr length = 0; + CT::boolean hit_zero = false; + for (const auto& e : arr) { + hit_zero |= e == 0; + const CT::fr increment = !hit_zero; + length += increment; + } + return length; +}; + +/** + * Note: doesn't remove the last element from the array; only returns it! + * Note: this assumes `0` always means 'not used', so be careful. If you actually want `0` to be counted, you'll need + * something else. + * If it returns `0`, the array is considered 'empty'. + */ +template CT::fr array_pop(std::array const& arr) +{ + CT::fr popped_value; + CT::boolean already_popped = false; + for (size_t i = arr.size() - 1; i != (size_t)-1; i--) { + CT::boolean is_non_zero = arr[i] != 0; + popped_value = CT::fr::conditional_assign(!already_popped && is_non_zero, arr[i], popped_value); + + already_popped |= is_non_zero; + } + return popped_value; +}; + +/** + * Note: this assumes `0` always means 'not used', so be careful. If you actually want `0` to be counted, you'll need + * something else. + */ +template CT::boolean is_array_empty(std::array const& arr) +{ + CT::boolean nonzero_found = false; + for (size_t i = arr.size() - 1; i != (size_t)-1; i--) { + CT::boolean is_non_zero = arr[i] != 0; + nonzero_found |= is_non_zero; + } + return !nonzero_found; +}; + +/** + * Inserts the `source` array at the first zero-valued index of the `target` array. + * Fails if the `source` array is too large vs the remaining capacity of the `target` array. + */ +template +void push_array_to_array(std::array const& source, std::array& target) +{ + CT::fr target_length = array_length(target); + CT::fr source_length = array_length(source); + + CT::fr target_capacity = CT::fr(target.size()); + // TODO: using safe_fr for an underflow check, do: + // remaining_target_capacity = target_capacity.subtract(target_length + source_length); + + CT::fr t_i = 0; + CT::fr next_index = target_length; + for (const auto& s : source) { + for (auto& t : target) { + next_index.assert_not_equal(target_capacity, "Target array capacity exceeded"); + CT::boolean at_index = t_i == next_index; + t = CT::fr::conditional_assign(at_index, s, t); + next_index = CT::fr::conditional_assign(at_index, next_index + 1, next_index); + ++t_i; + } + } +} + +/*************************************************************************************************************** + * End of array calcs. + **************************************************************************************************************/ + +// TODO: NEED TO RECONCILE THE `proof`'s public inputs (which are uint8's) with the +// private_call.call_stack_item.public_inputs! +CT::AggregationObject verify_proofs(Composer& composer, + PrivateInputs const& private_inputs, + size_t const& num_private_call_public_inputs, + size_t const& num_private_kernel_public_inputs) +{ + CT::AggregationObject aggregation_object = Aggregator::aggregate( + &composer, private_inputs.private_call.vk, private_inputs.private_call.proof, num_private_call_public_inputs); + + Aggregator::aggregate(&composer, + private_inputs.previous_kernel.vk, + private_inputs.previous_kernel.proof, + num_private_kernel_public_inputs, + aggregation_object); + + return aggregation_object; +} + +void initialise_end_values(PrivateInputs const& private_inputs, PublicInputs& public_inputs) +{ + public_inputs.constants = private_inputs.previous_kernel.public_inputs.constants; + + // Ensure the arrays are the same as previously, before we start pushing more data onto them: + auto& end = public_inputs.end; + const auto& start = private_inputs.previous_kernel.public_inputs.end; + + end.output_commitments = start.output_commitments; + end.input_nullifiers = start.input_nullifiers; + + end.private_call_stack = start.private_call_stack; + end.public_call_stack = start.public_call_stack; + end.contract_deployment_call_stack = start.contract_deployment_call_stack; + end.l1_call_stack = start.l1_call_stack; + + end.optionally_revealed_data = start.optionally_revealed_data; +} + +void update_end_values(PrivateInputs const& private_inputs, PublicInputs& public_inputs) +{ + const auto private_call_public_inputs = private_inputs.private_call.call_stack_item.public_inputs; + + const auto& output_commitments = private_call_public_inputs.output_commitments; + const auto& input_nullifiers = private_call_public_inputs.input_nullifiers; + + const auto& is_static_call = private_inputs.private_call.call_stack_item.public_inputs.call_context.is_static_call; + + // No state changes are allowed for static calls: + is_static_call.must_imply(is_array_empty(output_commitments) == true); + is_static_call.must_imply(is_array_empty(input_nullifiers) == true); + + const auto& storage_contract_address = + private_inputs.private_call.call_stack_item.public_inputs.call_context.storage_contract_address; + + { // commitments & nullifiers + std::array siloed_output_commitments; + for (size_t i = 0; i < output_commitments.size(); ++i) { + siloed_output_commitments[i] = + CT::fr::conditional_assign(output_commitments[i] == 0, + 0, + CT::compress({ storage_contract_address.to_field(), output_commitments[i] }, + GeneratorIndex::OUTER_COMMITMENT)); + } + std::array siloed_input_nullifiers; + for (size_t i = 0; i < input_nullifiers.size(); ++i) { + siloed_input_nullifiers[i] = + CT::fr::conditional_assign(input_nullifiers[i] == 0, + 0, + CT::compress({ storage_contract_address.to_field(), input_nullifiers[i] }, + GeneratorIndex::OUTER_NULLIFIER)); + } + + push_array_to_array(siloed_output_commitments, public_inputs.end.output_commitments); + push_array_to_array(siloed_input_nullifiers, public_inputs.end.input_nullifiers); + } + + { + // TODO: we need to pass in UNPACKED stack data. I.e. the preimages of the call_stack_item hashes, so that data + // in the stack can be validated as being correct. (e.g. call_contexts of calls made by the private_call + // currently being validated). + + // So we'll need to ensure our test_apps return not only a PrivateCircuitPublicInputs object, but also an object + // containing a TONNE of preimage data. Stuff like: + // - Stack item preimages + // - Commitment and nullifier preimages + // - Hash paths and leaf indices + // - Any and all preimage data derived by the circuit or through oracle calls. + + // Update on this topic: I've created call_context_reconciliation_data, which allows the call_context to + // be efficiently unpacked from a call_stack_item_hash. We'll need some "functions calling functions" + // tests cases to see how best to move this data around neatly. + } + + const auto& portal_contract_address = private_inputs.private_call.portal_contract_address; + + { + const auto& partial_l1_call_stack = private_call_public_inputs.partial_l1_call_stack; + std::array l1_call_stack; + + for (size_t i = 0; i < partial_l1_call_stack.size(); ++i) { + l1_call_stack[i] = + CT::fr::conditional_assign(partial_l1_call_stack[i] == 0, + 0, + CT::compress({ portal_contract_address, partial_l1_call_stack[i] }, + GeneratorIndex::L1_CALL_STACK_ITEM)); + } + } +} + +void validate_private_call_hash(PrivateInputs const& private_inputs) +{ + const auto& start = private_inputs.previous_kernel.public_inputs.end; + const auto private_call_hash = array_pop(start.private_call_stack); + const auto calculated_private_call_hash = private_inputs.private_call.call_stack_item.hash(); + + private_call_hash.assert_equal(calculated_private_call_hash, "private_call_hash does not reconcile"); +}; + +void validate_inputs(PrivateInputs const& private_inputs) +{ + + const auto& next_call = private_inputs.private_call.call_stack_item; + + next_call.function_signature.is_private.assert_equal( + true, "Cannot execute a non-private function with the private kernel circuit"); + + const auto& start = private_inputs.previous_kernel.public_inputs.end; + + const CT::boolean is_base_case = start.private_call_count == 0; + const CT::boolean is_recursive_case = !is_base_case; + + CT::fr start_private_call_stack_length = array_length(start.private_call_stack); + CT::fr start_public_call_stack_length = array_length(start.public_call_stack); + CT::fr start_contract_deployment_call_stack_length = array_length(start.contract_deployment_call_stack); + CT::fr start_l1_call_stack_length = array_length(start.l1_call_stack); + + // Base Case + { + // Validate callstack lengths: + is_base_case.must_imply(start_private_call_stack_length == + 1 // TODO: might change to allow 2, so a fee can be paid. + && start_public_call_stack_length == 0 && + start_contract_deployment_call_stack_length == 0 && start_l1_call_stack_length == 0, + "Invalid callstacks for base case."); + + is_base_case.must_imply(next_call.public_inputs.call_context.is_delegate_call == false && + next_call.public_inputs.call_context.is_static_call == false, + "A user cannot make a delegatecall or staticcall"); + + // The below also prevents delegatecall/staticcall + is_base_case.must_imply(next_call.public_inputs.call_context.storage_contract_address == + next_call.contract_address, + "Storage contract address must be that of the called contract in the base case"); + } + + // Recursive Case + { + is_recursive_case.must_imply(private_inputs.previous_kernel.public_inputs.is_private == true, + "Cannot verify a non-private kernel snark in the private kernel circuit"); + + is_recursive_case.must_imply(next_call.function_signature.is_constructor == false, + "A constructor must be executed as the first tx in the recursion"); + + is_recursive_case.must_imply(start_private_call_stack_length != 0); + } -// validate_private_call_hash(private_inputs); -// } + validate_private_call_hash(private_inputs); +} -// // TODO: decide what to return. -// void private_kernel_circuit(Composer& composer, OracleWrapper& oracle, PrivateInputs const& _private_inputs) -// { -// (void)oracle; // To avoid unused variable compiler errors whilst building. +// TODO: decide what to return. +void private_kernel_circuit(Composer& composer, OracleWrapper& oracle, PrivateInputs const& _private_inputs) +{ + (void)oracle; // To avoid unused variable compiler errors whilst building. -// const PrivateInputs private_inputs = _private_inputs.to_circuit_type(composer); -// PublicInputs public_inputs; + const PrivateInputs private_inputs = _private_inputs.to_circuit_type(composer); + PublicInputs public_inputs; -// // const auto& start = private_inputs.previous_kernel.public_inputs.end; + // const auto& start = private_inputs.previous_kernel.public_inputs.end; -// // const CT::boolean is_base_case = start.private_call_count == 0; -// // const CT::boolean is_recursive_case = !is_base_case; + // const CT::boolean is_base_case = start.private_call_count == 0; + // const CT::boolean is_recursive_case = !is_base_case; -// validate_inputs(private_inputs); + validate_inputs(private_inputs); -// initialise_end_values(private_inputs, public_inputs); + initialise_end_values(private_inputs, public_inputs); -// auto aggregation_object = verify_proofs(composer, -// private_inputs, -// _private_inputs.private_call.vk->num_public_inputs, -// _private_inputs.previous_kernel.vk->num_public_inputs); + auto aggregation_object = verify_proofs(composer, + private_inputs, + _private_inputs.private_call.vk->num_public_inputs, + _private_inputs.previous_kernel.vk->num_public_inputs); -// // TODO: kernel vk membership check! + // TODO: kernel vk membership check! -// public_inputs.end.aggregation_object = aggregation_object; + public_inputs.end.aggregation_object = aggregation_object; -// // public_inputs.set_public(); -// }; + // public_inputs.set_public(); +}; -// } // namespace aztec3::circuits::kernel::private_kernel \ No newline at end of file +} // namespace aztec3::circuits::kernel::private_kernel \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.hpp b/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.hpp index a0d12f2444a..4b6f6b4b3b3 100644 --- a/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.hpp +++ b/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.hpp @@ -1,16 +1,16 @@ -// #pragma once +#pragma once -// #include "init.hpp" +#include "init.hpp" -// #include -// // #include +#include +// #include -// namespace aztec3::circuits::kernel::private_kernel { +namespace aztec3::circuits::kernel::private_kernel { -// using aztec3::circuits::abis::private_kernel::PrivateInputs; -// // using abis::private_kernel::PublicInputs; +using aztec3::circuits::abis::private_kernel::PrivateInputs; +// using abis::private_kernel::PublicInputs; -// // TODO: decide what to return. -// void private_kernel_circuit(Composer& composer, OracleWrapper& oracle, PrivateInputs const& _private_inputs); +// TODO: decide what to return. +void private_kernel_circuit(Composer& composer, OracleWrapper& oracle, PrivateInputs const& _private_inputs); -// } // namespace aztec3::circuits::kernel::private_kernel \ No newline at end of file +} // namespace aztec3::circuits::kernel::private_kernel \ No newline at end of file From 9600f6730fc5b5916279afc34aada50bf11603b1 Mon Sep 17 00:00:00 2001 From: iAmMichaelConnor Date: Fri, 6 Jan 2023 13:24:08 +0000 Subject: [PATCH 025/166] utxo singleton initialisation --- circuits/src/aztec3/circuits/apps/.test.cpp | 91 ++++++- circuits/src/aztec3/circuits/apps/README.md | 52 +++- .../apps/function_execution_context.hpp | 2 +- .../apps/notes/default_private_note/note.hpp | 22 +- .../apps/notes/default_private_note/note.tpp | 2 - .../default_singleton_private_note/note.hpp | 111 ++++++++ .../default_singleton_private_note/note.tpp | 253 ++++++++++++++++++ .../note_preimage.hpp | 138 ++++++++++ .../nullifier_preimage.hpp | 72 +++++ .../circuits/apps/notes/note_interface.hpp | 17 +- .../aztec3/circuits/apps/opcodes/opcodes.hpp | 22 +- .../aztec3/circuits/apps/opcodes/opcodes.tpp | 30 ++- .../apps/state_vars/utxo_state_var.hpp | 7 + .../apps/state_vars/utxo_state_var.tpp | 9 +- .../.test.cpp | 10 +- .../contract.hpp | 30 ++- .../function1.cpp | 10 +- .../private_to_private_function_call/init.hpp | 18 +- circuits/src/aztec3/constants.hpp | 1 + circuits/src/aztec3/oracle/fake_db.hpp | 167 ++++++++++++ circuits/src/aztec3/oracle/oracle.hpp | 105 +------- 21 files changed, 1014 insertions(+), 155 deletions(-) create mode 100644 circuits/src/aztec3/circuits/apps/notes/default_singleton_private_note/note.hpp create mode 100644 circuits/src/aztec3/circuits/apps/notes/default_singleton_private_note/note.tpp create mode 100644 circuits/src/aztec3/circuits/apps/notes/default_singleton_private_note/note_preimage.hpp create mode 100644 circuits/src/aztec3/circuits/apps/notes/default_singleton_private_note/nullifier_preimage.hpp create mode 100644 circuits/src/aztec3/oracle/fake_db.hpp diff --git a/circuits/src/aztec3/circuits/apps/.test.cpp b/circuits/src/aztec3/circuits/apps/.test.cpp index fb905f48915..8f4a8485784 100644 --- a/circuits/src/aztec3/circuits/apps/.test.cpp +++ b/circuits/src/aztec3/circuits/apps/.test.cpp @@ -14,9 +14,13 @@ #include "utxo_datum.hpp" #include "notes/note_interface.hpp" + #include "notes/default_private_note/note.hpp" #include "notes/default_private_note/note_preimage.hpp" +#include "notes/default_singleton_private_note/note.hpp" +#include "notes/default_singleton_private_note/note_preimage.hpp" + #include "state_vars/field_state_var.hpp" #include "state_vars/mapping_state_var.hpp" #include "state_vars/utxo_state_var.hpp" @@ -55,9 +59,11 @@ using aztec3::circuits::apps::state_vars::MappingStateVar; using aztec3::circuits::apps::state_vars::UTXOSetStateVar; using aztec3::circuits::apps::state_vars::UTXOStateVar; -using aztec3::circuits::apps::notes::DefaultPrivateNote; using aztec3::circuits::apps::notes::NoteInterface; -// using aztec3::circuits::apps::notes::DefaultPrivateNotePreimage; + +using aztec3::circuits::apps::notes::DefaultPrivateNote; + +using aztec3::circuits::apps::notes::DefaultSingletonPrivateNote; //******** // Get rid of ugle `Composer` template arg from our state var types: @@ -262,4 +268,85 @@ TEST_F(state_var_tests, utxo_set_of_default_private_notes_fr) info("new_nullifiers: ", new_nullifiers); } +TEST_F(state_var_tests, initialise_utxo_of_default_singleton_private_note_fr) +{ + C composer; + NativeOracle native_oracle = get_test_native_oracle(); + OracleWrapper oracle = OracleWrapper(composer, native_oracle); + FunctionExecutionContext exec_ctx(composer, oracle); + + Contract contract(exec_ctx, "TestContract"); + contract.declare_state_var("my_utxo"); + + // FUNCTION: + + // This time we use a slightly different Note type, which is tailored towards singleton UTXO use-cases. In + // particular, it copes with the distinction between initialisation of the UTXO, vs future modification of the UTXO. + using Note = DefaultSingletonPrivateNote; + + UTXO my_utxo(&exec_ctx, "my_utxo"); + + const auto& msg_sender = oracle.get_msg_sender(); + + my_utxo.initialise({ .value = 100, .owner = msg_sender }); + + exec_ctx.finalise(); + + // Here, we test that the shared_ptr of a note, stored within the exec_ctx, works. TODO: put this in its own little + // test, instead of this ever-growing beast test. + auto new_note_pointers = exec_ctx.get_new_notes(); + std::shared_ptr debug_note = std::dynamic_pointer_cast(new_note_pointers[0]); + info("new_note_pointers: ", new_note_pointers); + info("*(new_note_pointers[0]): ", debug_note->get_preimage()); + + auto new_nullifiers = exec_ctx.get_new_nullifiers(); + info("new_nullifiers: ", new_nullifiers); +} + +TEST_F(state_var_tests, modify_utxo_of_default_singleton_private_note_fr) +{ + C composer; + NativeOracle native_oracle = get_test_native_oracle(); + OracleWrapper oracle = OracleWrapper(composer, native_oracle); + FunctionExecutionContext exec_ctx(composer, oracle); + + Contract contract(exec_ctx, "TestContract"); + contract.declare_state_var("my_utxo"); + + // FUNCTION: + + // This time we use a slightly different Note type, which is tailored towards singleton UTXO use-cases. In + // particular, it copes with the distinction between initialisation of the UTXO, vs future modification of the UTXO. + using Note = DefaultSingletonPrivateNote; + + UTXO my_utxo(&exec_ctx, "my_utxo"); + + const auto& msg_sender = oracle.get_msg_sender(); + + Note old_note = my_utxo.get({ .owner = msg_sender }); + + old_note.remove(); + + CT::fr old_value = *(old_note.get_preimage().value); + + CT::fr new_value = old_value + 5; + + my_utxo.insert({ + .value = new_value, // + .owner = msg_sender, + }); + + exec_ctx.finalise(); + + // Here, we test that the shared_ptr of a note, stored within the exec_ctx, works. TODO: put this in its own little + // test, instead of this ever-growing beast test. + auto new_note_pointers = exec_ctx.get_new_notes(); + std::shared_ptr debug_note = std::dynamic_pointer_cast(new_note_pointers[0]); + info("new_note_pointers: ", new_note_pointers); + info("*(new_note_pointers[0]): ", debug_note->get_preimage()); + + auto new_nullifiers = exec_ctx.get_new_nullifiers(); + info("new_nullifiers: ", new_nullifiers); +} + } // namespace aztec3::circuits::apps \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/README.md b/circuits/src/aztec3/circuits/apps/README.md index 90693176092..2a3e681914b 100644 --- a/circuits/src/aztec3/circuits/apps/README.md +++ b/circuits/src/aztec3/circuits/apps/README.md @@ -6,4 +6,54 @@ All code in this dir is for: - Syntax for State Variables & UTXOs - Function calls - To help illustrate ideas to the Noir team -- To allow test app circuits to be mocked-up as quickly and easily as possible, for use in the Kernel & Rollup circuits. \ No newline at end of file +- To allow test app circuits to be mocked-up as quickly and easily as possible, for use in the Kernel & Rollup circuits. + + + + +utxo_state_var.insert(note_preimage) + ↓ +Opcodes.UTXO_SSTORE (this=state_var*, note_preimage) + ↓ +exec_ctx got from state_var->exec_ctx +new_note = Note(state_var, new_note_preimage) <- could be done in state_var +exec_ctx->new_notes.push_back(new_note) +NO VISITOR CALLED + + + +utxo_state_var.get(NotePreimage advice) + ↓ +Opcodes.UTXO_LOAD (this=state_var*, advice) + ↓ +oracle got from state_var->exec_ctx->oracle +storage_slot_point got from state_var->storage_slot_point +Grab note_preimages and paths from DB +new_note = Note(state_var, note_preimage) +Compare against advice +- VISITOR CALLED: new_note.constrain_against_advice(advice) +Membership checks (and other checks) +- VISITOR CALLED: new_note.get_commitment() +return new_note + + + +note.remove() + ↓ +Opcodes.UTXO_NULL (state_var*, *this=note) + ↓ +exec_ctx got from state_var->exec_ctx +- VISITOR CALLED: + - nullifier = note.compute_nullifier() <- could be done in state_var +exec_ctx->new_nullifiers.push_back(nullifier) + + + +utxo_state_var.initialise(note_preimage) + ↓ +Opcodes.UTXO_SSTORE (this=state_var*, note_preimage) + ↓ +exec_ctx got from state_var->exec_ctx +new_note = Note(state_var, new_note_preimage) +exec_ctx->new_notes.push_back(new_note) +NO VISITOR CALLED \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/function_execution_context.hpp b/circuits/src/aztec3/circuits/apps/function_execution_context.hpp index 9d525b521e3..eb7b8a41be3 100644 --- a/circuits/src/aztec3/circuits/apps/function_execution_context.hpp +++ b/circuits/src/aztec3/circuits/apps/function_execution_context.hpp @@ -55,7 +55,7 @@ template class FunctionExecutionContext { std::vector new_commitments; // Nullifier preimages can be got from the corresponding Note that they nullify. - std::vector*> nullified_notes; + std::vector>> nullified_notes; std::vector new_nullifiers; public: diff --git a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.hpp b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.hpp index 0d9630dd3b4..10e571a5a94 100644 --- a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.hpp +++ b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.hpp @@ -8,8 +8,6 @@ #include #include -#include - // Forward-declare from this namespace in particular: namespace aztec3::circuits::apps::state_vars { template class StateVar; @@ -22,9 +20,6 @@ using aztec3::circuits::apps::state_vars::StateVar; // Don't #include it! using plonk::stdlib::types::CircuitTypes; using plonk::stdlib::types::NativeTypes; -// template struct DefaultPrivateNotePreimage; -// template struct DefaultPrivateNoteNullifierPreimage; - template class DefaultPrivateNote : public NoteInterface { public: typedef CircuitTypes CT; @@ -48,8 +43,6 @@ template class DefaultPrivateNote : publ std::optional nullifier_preimage; public: - // CUSTOM CONSTRUCTORS: - DefaultPrivateNote(StateVar* state_var, NotePreimage note_preimage) : state_var(state_var) , note_preimage(note_preimage){}; @@ -60,8 +53,6 @@ template class DefaultPrivateNote : publ void remove() override; - // HOOKS - fr get_commitment() override { if (commitment) { @@ -88,10 +79,6 @@ template class DefaultPrivateNote : publ // return *partial_commitment; // }; - fr compute_commitment() override; - - fr compute_nullifier() override; - void constrain_against_advice(NoteInterface const& advice_note) override; bool needs_nonce() override; @@ -100,6 +87,12 @@ template class DefaultPrivateNote : publ fr generate_nonce() override; + fr get_initialisation_nullifier() override + { + throw_or_abort( + "DefaultPrivateNote does not support initialisation. Maybe use DefaultSingletonPrivateNote instead?"); + }; + // CUSTOM METHODS auto& get_oracle(); @@ -115,6 +108,9 @@ template class DefaultPrivateNote : publ NotePreimage& get_preimage() { return note_preimage; }; private: + fr compute_commitment(); + fr compute_nullifier(); + bool is_partial_preimage() const; bool is_partial_storage_slot() const; bool is_partial() const; diff --git a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.tpp b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.tpp index 61c1acf1839..15910a85b58 100644 --- a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.tpp +++ b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.tpp @@ -19,8 +19,6 @@ #include #include -#include - namespace { using aztec3::circuits::apps::opcodes::Opcodes; using aztec3::circuits::apps::state_vars::StateVar; diff --git a/circuits/src/aztec3/circuits/apps/notes/default_singleton_private_note/note.hpp b/circuits/src/aztec3/circuits/apps/notes/default_singleton_private_note/note.hpp new file mode 100644 index 00000000000..1888b1f0c19 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/notes/default_singleton_private_note/note.hpp @@ -0,0 +1,111 @@ +#pragma once + +#include "../note_interface.hpp" + +#include "note_preimage.hpp" +#include "nullifier_preimage.hpp" + +#include +#include + +// Forward-declare from this namespace in particular: +namespace aztec3::circuits::apps::state_vars { +template class StateVar; +} // namespace aztec3::circuits::apps::state_vars + +namespace aztec3::circuits::apps::notes { + +using aztec3::circuits::apps::state_vars::StateVar; // Don't #include it! + +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; + +template class DefaultSingletonPrivateNote : public NoteInterface { + public: + typedef CircuitTypes CT; + typedef typename CT::fr fr; + typedef typename CT::grumpkin_point grumpkin_point; + typedef typename CT::address address; + typedef typename CT::boolean boolean; + + using NotePreimage = DefaultSingletonPrivateNotePreimage, ValueType>; + using NullifierPreimage = DefaultSingletonPrivateNoteNullifierPreimage>; + + public: + StateVar* state_var; + + private: + std::optional commitment; + std::optional nullifier; + + NotePreimage note_preimage; + std::optional nullifier_preimage; + + public: + DefaultSingletonPrivateNote(StateVar* state_var, NotePreimage note_preimage) + : state_var(state_var) + , note_preimage(note_preimage){}; + + ~DefaultSingletonPrivateNote() {} + + // OVERRIDE METHODS: + + void remove() override; + + fr get_commitment() override + { + if (commitment) { + return *commitment; + } + return compute_commitment(); + }; + + fr get_nullifier() override + { + if (nullifier) { + return *nullifier; + } + return compute_nullifier(); + }; + + void constrain_against_advice(NoteInterface const& advice_note) override; + + bool needs_nonce() override; + + void set_nonce(fr const& nonce) override; + + fr generate_nonce() override; + + fr get_initialisation_nullifier() override; + + // CUSTOM METHODS + + auto& get_oracle(); + + grumpkin_point compute_partial_commitment(); + + fr compute_dummy_nullifier(); + + static fr compute_nullifier(fr const& commitment, + fr const& owner_private_key, + boolean const& is_dummy_commitment = false); + + NotePreimage& get_preimage() { return note_preimage; }; + + private: + fr compute_commitment(); + fr compute_nullifier(); + + bool is_partial_preimage() const; + bool is_partial_storage_slot() const; + bool is_partial() const; +}; + +} // namespace aztec3::circuits::apps::notes + +// Importing in this way (rather than explicit instantiation of a template class at the bottom of a .cpp file) preserves +// the following: +// - We retain implicit instantiation of templates. +// - We don't implement method definitions in this file, to avoid a circular dependency with the state_var files (which +// are forward-declared in this file). +#include "note.tpp" \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/notes/default_singleton_private_note/note.tpp b/circuits/src/aztec3/circuits/apps/notes/default_singleton_private_note/note.tpp new file mode 100644 index 00000000000..e096b3d33db --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/notes/default_singleton_private_note/note.tpp @@ -0,0 +1,253 @@ +#include "note_preimage.hpp" +#include "nullifier_preimage.hpp" + +#include "../note_interface.hpp" + +#include "../../oracle_wrapper.hpp" +#include "../../opcodes/opcodes.hpp" + +#include "../../state_vars/state_var_base.hpp" + +#include + +#include + +#include +#include +#include +#include +#include +#include + +namespace { +using aztec3::circuits::apps::opcodes::Opcodes; +using aztec3::circuits::apps::state_vars::StateVar; +} // namespace + +namespace aztec3::circuits::apps::notes { + +using aztec3::GeneratorIndex; + +using crypto::pedersen::generator_index_t; + +using plonk::stdlib::witness_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; + +template void DefaultSingletonPrivateNote::remove() +{ + Opcodes::UTXO_NULL(state_var, *this); +} + +template auto& DefaultSingletonPrivateNote::get_oracle() +{ + return state_var->exec_ctx->oracle; +} + +template bool DefaultSingletonPrivateNote::is_partial_preimage() const +{ + const auto& [value, owner, salt, nonce] = note_preimage; + + return (!value || !owner || !salt || !nonce); +} + +template bool DefaultSingletonPrivateNote::is_partial_storage_slot() const +{ + return state_var->is_partial_slot; +} + +template bool DefaultSingletonPrivateNote::is_partial() const +{ + return is_partial_preimage() || is_partial_storage_slot(); +} + +template +typename CircuitTypes::fr DefaultSingletonPrivateNote::compute_commitment() +{ + if (commitment.has_value()) { + return *commitment; + } + + grumpkin_point storage_slot_point = state_var->storage_slot_point; + + std::vector inputs; + std::vector generators; + + auto gen_pair_address = [&](std::optional
const& input, size_t const hash_sub_index) { + if (!input) { + throw_or_abort("Cannot commit to a partial preimage."); + } + return std::make_pair((*input).to_field(), generator_index_t({ GeneratorIndex::COMMITMENT, hash_sub_index })); + }; + + auto gen_pair_fr = [&](std::optional const& input, size_t const hash_sub_index) { + if (!input) { + throw_or_abort("Cannot commit to a partial preimage."); + } + return std::make_pair(*input, generator_index_t({ GeneratorIndex::COMMITMENT, hash_sub_index })); + }; + + if (!note_preimage.salt) { + note_preimage.salt = get_oracle().generate_random_element(); + } + + const auto& [value, owner, salt, nonce] = note_preimage; + + const grumpkin_point commitment_point = + storage_slot_point + CT::commit({ + gen_pair_fr(value, PrivateStateNoteGeneratorIndex::VALUE), + gen_pair_address(owner, PrivateStateNoteGeneratorIndex::OWNER), + gen_pair_fr(salt, PrivateStateNoteGeneratorIndex::SALT), + gen_pair_fr(nonce, PrivateStateNoteGeneratorIndex::NONCE), + }); + + commitment = commitment_point.x; + + return *commitment; +} + +template +typename CircuitTypes::fr DefaultSingletonPrivateNote::compute_nullifier() +{ + if (is_partial()) { + throw_or_abort("Can't nullify a partial note."); + } + if (nullifier && nullifier_preimage) { + return *nullifier; + } + if (!commitment) { + compute_commitment(); + } + + fr& owner_private_key = get_oracle().get_msg_sender_private_key(); + + nullifier = DefaultSingletonPrivateNote::compute_nullifier(*commitment, owner_private_key); + nullifier_preimage = { + *commitment, + owner_private_key, + }; + return *nullifier; +}; + +template +typename CircuitTypes::fr DefaultSingletonPrivateNote::compute_dummy_nullifier() +{ + auto& oracle = get_oracle(); + fr dummy_commitment = oracle.generate_random_element(); + fr& owner_private_key = oracle.get_msg_sender_private_key(); + const boolean is_dummy_commitment = true; + + return DefaultSingletonPrivateNote::compute_nullifier( + dummy_commitment, owner_private_key, is_dummy_commitment); +}; + +template +typename CircuitTypes::fr DefaultSingletonPrivateNote::compute_nullifier( + fr const& commitment, fr const& owner_private_key, boolean const& is_dummy_commitment) +{ + /** + * Hashing the private key in this way enables the following use case: + * - A user can demonstrate to a 3rd party that they have spent a note, by providing the + hashed_private_key + * and the note_commitment. The 3rd party can then recalculate the nullifier. This does not reveal the + * underlying private_key to the 3rd party. */ + const grumpkin_point hashed_private_key = CT::grumpkin_group::template fixed_base_scalar_mul<254>( + owner_private_key, GeneratorIndex::NULLIFIER_HASHED_PRIVATE_KEY); + + const std::vector hash_inputs{ + commitment, + hashed_private_key.x, + hashed_private_key.y, + is_dummy_commitment, + }; + + // We compress the hash_inputs with Pedersen, because that's cheaper (constraint-wise) than compressing + // the data directly with Blake2s in the next step. + const fr compressed_inputs = CT::compress(hash_inputs, GeneratorIndex::NULLIFIER); + + // Blake2s hash the compressed result. Without this it's possible to leak info from the pedersen + // compression. + /** E.g. we can extract a representation of the hashed_pk: + * Paraphrasing, if: + * nullifier = note_comm * G1 + hashed_pk * G2 + is_dummy_note * G3 + * Then an observer can derive hashed_pk * G2 = nullifier - note_comm * G1 - is_dummy_note * G3 + * They can derive this for every tx, to link which txs are being sent by the same user. + * Notably, at the point someone withdraws, the observer would be able to connect `hashed_pk * G2` with a + * specific eth address. + */ + auto blake_input = typename CT::byte_array(compressed_inputs); + auto blake_result = CT::blake2s(blake_input); + return fr(blake_result); +}; + +template +void DefaultSingletonPrivateNote::constrain_against_advice(NoteInterface const& advice_note) +{ + // Cast from a ref to the base (interface) type to a ref to this derived type: + const DefaultSingletonPrivateNote& advice_note_ref = + dynamic_cast&>(advice_note); + + auto assert_equal = [](std::optional& this_member, std::optional const& advice_member) { + if (advice_member) { + (*this_member).assert_equal(*advice_member); + } + }; + + const auto& advice_preimage = advice_note_ref.note_preimage; + auto& this_preimage = note_preimage; + + assert_equal(this_preimage.value, advice_preimage.value); + assert_equal(this_preimage.owner, advice_preimage.owner); + assert_equal(this_preimage.salt, advice_preimage.salt); + assert_equal(this_preimage.nonce, advice_preimage.nonce); +} + +template bool DefaultSingletonPrivateNote::needs_nonce() +{ + return !note_preimage.nonce; +} + +template +void DefaultSingletonPrivateNote::set_nonce(typename CircuitTypes::fr const& nonce) +{ + ASSERT(!note_preimage.nonce); + note_preimage.nonce = nonce; +}; + +template +typename CircuitTypes::fr DefaultSingletonPrivateNote::generate_nonce() +{ + ASSERT(!note_preimage.nonce); + note_preimage.nonce = compute_dummy_nullifier(); + return *(note_preimage.nonce); +}; + +template +typename CircuitTypes::fr DefaultSingletonPrivateNote::get_initialisation_nullifier() +{ + auto& oracle = get_oracle(); + + // With this note, the person initialising the note must be the owner. + (*note_preimage.owner).assert_equal(oracle.get_msg_sender()); + + const fr& owner_private_key = oracle.get_msg_sender_private_key(); + + // We prevent this storage slot from even being initialised again: + auto& storage_slot_point = state_var->storage_slot_point; + + const std::vector hash_inputs{ + storage_slot_point.x, + storage_slot_point.y, + }; + + const bool is_dummy = false; + + // We compress the hash_inputs with Pedersen, because that's cheap. + const fr compressed_storage_slot_point = CT::compress(hash_inputs, GeneratorIndex::INITIALISATION_NULLIFIER); + + // For now, we piggy-back on the regular nullifier function. + return DefaultSingletonPrivateNote::compute_nullifier( + compressed_storage_slot_point, owner_private_key, is_dummy); +}; + +} // namespace aztec3::circuits::apps::notes \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/notes/default_singleton_private_note/note_preimage.hpp b/circuits/src/aztec3/circuits/apps/notes/default_singleton_private_note/note_preimage.hpp new file mode 100644 index 00000000000..5811654565c --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/notes/default_singleton_private_note/note_preimage.hpp @@ -0,0 +1,138 @@ +#pragma once + +#include +#include + +#include + +#include +#include +#include + +namespace aztec3::circuits::apps::notes { + +using crypto::pedersen::generator_index_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; + +template struct DefaultSingletonPrivateNotePreimage { + typedef typename NCT::fr fr; + typedef typename NCT::grumpkin_point grumpkin_point; + typedef typename NCT::address address; + typedef typename NCT::boolean boolean; + + // No custom constructors so that designated initializers can be used (for readability of test circuits). + + std::optional value; + std::optional
owner; + + std::optional salt; + std::optional nonce; + + bool operator==(DefaultSingletonPrivateNotePreimage const&) const = default; + + template auto to_circuit_type(Composer& composer) const + { + static_assert((std::is_same::value)); + + // Capture the composer: + auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + + // Depending on whether the _circuit_ type version of `V` is from the stdlib, or some custom type, the + // conversion method will be different. + const bool has_to_circuit_type = requires(V v) { v.to_circuit_type(); }; + const bool has_to_ct = requires(V v) { to_ct(v); }; + + // To avoid messy template arguments in the calling code, we use a lambda function with `auto` return type to + // avoid explicitly having to state the circuit type for `V`. + auto circuit_value = [&]() -> auto + { + if constexpr (has_to_circuit_type) { + return value.to_circuit_type(); + } else if (has_to_ct) { + return to_ct(value); + } else { + throw_or_abort("Can't convert Value to circuit type"); + } + } + (); + + // When this method is called, this class must be templated over native types. We can avoid templating over the + // circuit types (for the return values) (in order to make the calling syntax cleaner) with the below `decltype` + // deduction of the _circuit_ version of template type `V`. + DefaultSingletonPrivateNotePreimage, typename decltype(circuit_value)::value_type> + preimage = { + circuit_value, + to_ct(owner), + to_ct(salt), + to_ct(nonce), + }; + + return preimage; + }; + + template auto to_native_type() const + { + + static_assert(!std::is_same::value); + + auto to_nt = [&](auto& e) { return plonk::stdlib::types::to_nt(e); }; + + // See `to_circuit_type()` for explanation of this code. + const bool has_to_native_type = requires(V v) { v.to_native_type(); }; + const bool has_to_nt = requires(V v) { to_nt(v); }; + + auto native_value = [&]() -> auto + { + if constexpr (has_to_native_type) { + return value.to_native_type(); + } else if (has_to_nt) { + return to_nt(value); + } else { + throw_or_abort("Can't convert Value to native type"); + } + } + (); + + DefaultSingletonPrivateNotePreimage preimage = { + native_value, + to_nt(owner), + to_nt(salt), + to_nt(nonce), + }; + + return preimage; + }; +}; + +template void read(uint8_t const*& it, DefaultSingletonPrivateNotePreimage& preimage) +{ + using serialize::read; + + read(it, preimage.value); + read(it, preimage.owner); + read(it, preimage.salt); + read(it, preimage.nonce); +}; + +template +void write(std::vector& buf, DefaultSingletonPrivateNotePreimage const& preimage) +{ + using serialize::write; + + write(buf, preimage.value); + write(buf, preimage.owner); + write(buf, preimage.salt); + write(buf, preimage.nonce); +}; + +template +std::ostream& operator<<(std::ostream& os, DefaultSingletonPrivateNotePreimage const& preimage) +{ + return os << "value: " << preimage.value << "\n" + << "owner: " << preimage.owner << "\n" + << "salt: " << preimage.salt << "\n" + << "nonce: " << preimage.nonce << "\n"; +} + +} // namespace aztec3::circuits::apps::notes \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/notes/default_singleton_private_note/nullifier_preimage.hpp b/circuits/src/aztec3/circuits/apps/notes/default_singleton_private_note/nullifier_preimage.hpp new file mode 100644 index 00000000000..64c5be51c2d --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/notes/default_singleton_private_note/nullifier_preimage.hpp @@ -0,0 +1,72 @@ +#pragma once +#include +#include + +#include + +#include +#include +#include + +namespace aztec3::circuits::apps::notes { + +using crypto::pedersen::generator_index_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; + +template struct DefaultSingletonPrivateNoteNullifierPreimage { + typedef typename NCT::fr fr; + typedef typename NCT::boolean boolean; + + fr commitment; + fr owner_private_key; + boolean is_dummy = false; + + bool operator==(DefaultSingletonPrivateNoteNullifierPreimage const&) const = default; + + template + DefaultSingletonPrivateNoteNullifierPreimage> to_circuit_type(Composer& composer) const + { + static_assert((std::is_same::value)); + + // Capture the composer: + auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + + DefaultSingletonPrivateNoteNullifierPreimage> preimage = { + to_ct(commitment), + to_ct(owner_private_key), + to_ct(is_dummy), + }; + + return preimage; + }; +}; + +template void read(uint8_t const*& it, DefaultSingletonPrivateNoteNullifierPreimage& preimage) +{ + using serialize::read; + + read(it, preimage.commitment); + read(it, preimage.owner_private_key); + read(it, preimage.is_dummy); +}; + +template +void write(std::vector& buf, DefaultSingletonPrivateNoteNullifierPreimage const& preimage) +{ + using serialize::write; + + write(buf, preimage.commitment); + write(buf, preimage.owner_private_key); + write(buf, preimage.is_dummy); +}; + +template +std::ostream& operator<<(std::ostream& os, DefaultSingletonPrivateNoteNullifierPreimage const& preimage) +{ + return os << "commitment: " << preimage.commitment << "\n" + << "owner_private_key: " << preimage.owner_private_key << "\n" + << "is_dummy: " << preimage.is_dummy << "\n"; +} + +} // namespace aztec3::circuits::apps::notes \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/notes/note_interface.hpp b/circuits/src/aztec3/circuits/apps/notes/note_interface.hpp index 1371aff8e3f..c09510aff55 100644 --- a/circuits/src/aztec3/circuits/apps/notes/note_interface.hpp +++ b/circuits/src/aztec3/circuits/apps/notes/note_interface.hpp @@ -8,6 +8,13 @@ namespace aztec3::circuits::apps::notes { using plonk::stdlib::types::CircuitTypes; using plonk::stdlib::types::NativeTypes; +/** + * Note: The methods in this interface must be implemented by the derived Note types, even if such note types don't + * require such functions. + * + * It's essentially a visitor pattern. The Opcodes and UTXOStateVar types can call all of these + * methods on any Note, and the Note must choose whether to compute something, or whether to throw, for each method. + */ template class NoteInterface { public: typedef CircuitTypes CT; @@ -21,15 +28,19 @@ template class NoteInterface { // `NoteInterface*` pointers instead of the derived class). virtual ~NoteInterface() {} + // TODO: maybe rather than have this be a pure interface, we should have a constructor and the `state_var*` and + // `note_preimage` members here (although that would require a NotePreimage template param). + // This is all because the Opcodes actually _assume_ a particular constructor layout for each Note, as well as + // _assume_ those two data members are always present. Having said that, there's still no way to actually enforce a + // constructor function signature of a derived class. + virtual void remove() = 0; virtual fr get_commitment() = 0; virtual fr get_nullifier() = 0; - virtual fr compute_commitment() = 0; - - virtual fr compute_nullifier() = 0; + virtual fr get_initialisation_nullifier() = 0; virtual void constrain_against_advice(NoteInterface const& advice_note) = 0; diff --git a/circuits/src/aztec3/circuits/apps/opcodes/opcodes.hpp b/circuits/src/aztec3/circuits/apps/opcodes/opcodes.hpp index 058a7cfdd08..2d57acbb64a 100644 --- a/circuits/src/aztec3/circuits/apps/opcodes/opcodes.hpp +++ b/circuits/src/aztec3/circuits/apps/opcodes/opcodes.hpp @@ -21,10 +21,14 @@ using plonk::stdlib::types::CircuitTypes; using plonk::stdlib::types::NativeTypes; /** - * @brief - These static methods are a suggestion for what ACIR++ 'Opcodes' might do. They combine directives to get - * data from an oracle, and then apply constraints to that data. Separating out this functionality into a separate - * `Opcodes` class, like this, was trickier than just writing this stuff directly in the `Note` or - * `FunctionExecutionContext` classes, but hopefully the separation is tidier. + * @brief - These static methods are a suggestion for what ACIR++ 'Opcodes' might do. They can get + * data from an oracle. They can apply constraints to that data. And they are the only class allowed to push data to the + * execution context. + * Separating out this functionality into a separate `Opcodes` class, like this, was trickier than + * just writing this stuff directly in the `Note` or `FunctionExecutionContext` classes, but hopefully the separation is + * sensible. + * + * TODO: Any oracle access or exec_ctx access should go through this class? */ template class Opcodes { public: @@ -54,10 +58,16 @@ template class Opcodes { /** * @brief Compute and push a new nullifier to the public inputs of this exec_ctx. */ - template static void UTXO_NULL(StateVar* state_var, Note& note); + template static void UTXO_NULL(StateVar* state_var, Note& note_to_nullify); /** - * @brief Compute and push a new comitment to the public inputs of this exec_ctx. + * @brief Compute and push a new commitment to the public inputs of this exec_ctx, BUT ALSO compute and produce an + * initialisation nullifier, to prevent this note from being initialised again in the future. + */ + template static void UTXO_INIT(StateVar* state_var, Note& note_to_initialise); + + /** + * @brief Compute and push a new commitment to the public inputs of this exec_ctx. */ template static void UTXO_SSTORE(StateVar* state_var, typename Note::NotePreimage new_note_preimage); diff --git a/circuits/src/aztec3/circuits/apps/opcodes/opcodes.tpp b/circuits/src/aztec3/circuits/apps/opcodes/opcodes.tpp index 59f81e29aa6..958135f1b4b 100644 --- a/circuits/src/aztec3/circuits/apps/opcodes/opcodes.tpp +++ b/circuits/src/aztec3/circuits/apps/opcodes/opcodes.tpp @@ -107,13 +107,35 @@ std::vector Opcodes::UTXO_SLOAD(UTXOSetStateVar* template template -void Opcodes::UTXO_NULL(StateVar* state_var, Note& note) +void Opcodes::UTXO_NULL(StateVar* state_var, Note& note_to_nullify) { - typename CT::fr nullifier = note.compute_nullifier(); + typename CT::fr nullifier = note_to_nullify.get_nullifier(); auto& exec_ctx = state_var->exec_ctx; exec_ctx->new_nullifiers.push_back(nullifier); + + std::shared_ptr nullified_note_ptr = std::make_shared(note_to_nullify); + + exec_ctx->nullified_notes.push_back(nullified_note_ptr); +}; + +template +template +void Opcodes::UTXO_INIT(StateVar* state_var, Note& note_to_initialise) +{ + typename CT::fr init_nullifier = note_to_initialise.get_initialisation_nullifier(); + + auto& exec_ctx = state_var->exec_ctx; + + exec_ctx->new_nullifiers.push_back(init_nullifier); + + std::shared_ptr init_note_ptr = std::make_shared(note_to_initialise); + + // TODO: consider whether this should actually be pushed-to... + exec_ctx->nullified_notes.push_back(init_note_ptr); + + exec_ctx->new_notes.push_back(init_note_ptr); }; template @@ -124,9 +146,9 @@ void Opcodes::UTXO_SSTORE(StateVar* state_var, typename Note // Make a shared pointer, so we don't end up with a dangling pointer in the exec_ctx when this `new_note` // immediately goes out of scope. - std::shared_ptr new_note = std::make_shared(state_var, new_note_preimage); + std::shared_ptr new_note_ptr = std::make_shared(state_var, new_note_preimage); - exec_ctx->new_notes.push_back(new_note); + exec_ctx->new_notes.push_back(new_note_ptr); }; } // namespace aztec3::circuits::apps::opcodes diff --git a/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp b/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp index ed3ae808731..aae8507f559 100644 --- a/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp +++ b/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp @@ -57,6 +57,13 @@ template class UTXOStateVar : public StateVar */ Note get(NotePreimage const& advice); + /** + * @brief For singleton UTXOs, there's a distinction between initialising and modifying in future. See here: + * https://discourse.aztec.network/t/utxo-syntax-2-initialising-singleton-utxos/47. So we include this method for + * singleton UTXO types. + */ + void initialise(NotePreimage new_note_preimage); + void insert(NotePreimage new_note_preimage); }; diff --git a/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.tpp b/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.tpp index 51a99982ba7..1d5c757c0bc 100644 --- a/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.tpp +++ b/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.tpp @@ -17,10 +17,17 @@ Note UTXOStateVar::get(typename Note::NotePreimage const& advice return Opcodes::template UTXO_SLOAD(this, advice); }; +template +void UTXOStateVar::initialise(typename Note::NotePreimage new_note_preimage) +{ + Note new_note{ this, new_note_preimage }; + Opcodes::template UTXO_INIT(this, new_note); +}; + template void UTXOStateVar::insert(typename Note::NotePreimage new_note_preimage) { - return Opcodes::template UTXO_SSTORE(this, new_note_preimage); + Opcodes::template UTXO_SSTORE(this, new_note_preimage); }; } // namespace aztec3::circuits::apps::state_vars \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp index 46a37e99797..04dc49d1317 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp @@ -1,6 +1,7 @@ +// #include "index.hpp" + // #include // #include -// #include "index.hpp" // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { @@ -9,7 +10,7 @@ // TEST(private_to_private_function_call_tests, test_private_to_private_function_call) // { -// Composer fn1_composer; +// C fn1_composer; // DB db; // const NT::address contract_address = 12345; @@ -22,13 +23,14 @@ // NativeOracle fn1_oracle = NativeOracle(db, contract_address, msg_sender, tx_origin, msg_sender_private_key); // OracleWrapper fn1_oracle_wrapper = OracleWrapper(fn1_composer, fn1_oracle); -// FunctionExecutionContext fn1_exec_ctx(fn1_composer, fn1_oracle_wrapper); +// FunctionExecutionContext fn1_exec_ctx(fn1_composer, fn1_oracle_wrapper); // auto a = NT::fr(111); // auto b = NT::fr(222); // auto c = NT::fr(333); -// auto result = function1(fn1_exec_ctx, a, b, c); +// auto result = function_1_1(fn1_exec_ctx, a, b, c); + // info("result: ", result); // info("computed witness: ", fn1_composer.computed_witness); diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/contract.hpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/contract.hpp index 4363647ab6e..6d06163e104 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/contract.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/contract.hpp @@ -1,22 +1,38 @@ // #pragma once + +// #include "init.hpp" + // #include // #include // #include -// #include "init.hpp" // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { -// inline Contract init_contract(FunctionExecutionContext& exec_ctx) +// inline Contract init_contract_1(FunctionExecutionContext& exec_ctx) +// { +// Contract contract(exec_ctx, "contract_1"); + +// contract.declare_state_var("x"); +// contract.declare_state_var("y"); + +// // Solely used for assigning vk indices. +// contract.set_functions({ +// { .name = "function_1_1", .is_private = true }, +// }); + +// return contract; +// } + +// inline Contract init_contract_2(FunctionExecutionContext& exec_ctx) // { -// Contract contract(exec_ctx, "priv_to_priv_function_call"); +// Contract contract(exec_ctx, "contract_2"); -// contract.declare_private_state_var("x"); -// contract.declare_private_state_var("y"); +// contract.declare_state_var("x"); +// contract.declare_state_var("y"); // // Solely used for assigning vk indices. // contract.set_functions({ -// { .name = "function1", .is_private = true }, -// { .name = "function2", .is_private = true }, +// { .name = "function_2_1", .is_private = true }, // }); // return contract; diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.cpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.cpp index 256a9bd1634..f9edf86cb0f 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.cpp @@ -7,14 +7,14 @@ // using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; -// OptionalPrivateCircuitPublicInputs function1(FunctionExecutionContext& exec_ctx, +// OptionalPrivateCircuitPublicInputs function1(FunctionExecutionContext& exec_ctx, // NT::fr const& _a, // NT::fr const& _b, // NT::fr const& _c) // { // auto& composer = exec_ctx.composer; // auto& oracle = exec_ctx.oracle; -// Contract contract = init_contract(exec_ctx); +// Contract contract = init_contract(exec_ctx); // CT::fr a = to_ct(composer, _a); // CT::fr b = to_ct(composer, _b); @@ -34,7 +34,7 @@ // // auto function2 = contract.get_function("function2"); // const NT::address fn2_contract_address = 23456; -// Composer fn2_composer; +// C fn2_composer; // // Note: it's ok that we swap back into Native Types here - we don't need constraints. Creation of fn2_oracle is // // necessary for circuit construction only; it's not part of the circuit itself. We check that the call_contexts @@ -50,7 +50,7 @@ // oracle.get_tx_origin().to_field().get_value()); // OracleWrapper fn2_oracle_wrapper = OracleWrapper(fn2_composer, fn2_oracle); -// FunctionExecutionContext fn1_exec_ctx(fn2_composer, fn2_oracle_wrapper); +// FunctionExecutionContext fn1_exec_ctx(fn2_composer, fn2_oracle_wrapper); // // auto result = function2.call(a, b, c); @@ -66,7 +66,7 @@ // info("public inputs: ", public_inputs); -// return public_inputs.to_native_type(); +// return public_inputs.to_native_type(); // // TODO: also return note preimages and nullifier preimages. // }; diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/init.hpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/init.hpp index fbc4276329e..014419598ae 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/init.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/init.hpp @@ -1,20 +1,28 @@ // #pragma once + +// #include +// #include +// #include + +// #include + // #include // #include // #include // #include -// #include -// #include // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { -// using Composer = plonk::stdlib::types::turbo::Composer; -// using CT = plonk::stdlib::types::CircuitTypes; +// using C = plonk::stdlib::types::turbo::Composer; +// using CT = plonk::stdlib::types::CircuitTypes; // using NT = plonk::stdlib::types::NativeTypes; // using DB = oracle::FakeDB; // using oracle::NativeOracle; -// using OracleWrapper = OracleWrapperInterface; +// using OracleWrapper = OracleWrapperInterface; + +// using Contract = apps::Contract; +// using FunctionExecutionContext = apps::FunctionExecutionContext; // using plonk::stdlib::types::to_ct; diff --git a/circuits/src/aztec3/constants.hpp b/circuits/src/aztec3/constants.hpp index b23fb9b99b2..664e51ef5d5 100644 --- a/circuits/src/aztec3/constants.hpp +++ b/circuits/src/aztec3/constants.hpp @@ -39,6 +39,7 @@ enum GeneratorIndex { OUTER_COMMITMENT, NULLIFIER_HASHED_PRIVATE_KEY, NULLIFIER, + INITIALISATION_NULLIFIER, OUTER_NULLIFIER, STATE_READ, STATE_TRANSITION, diff --git a/circuits/src/aztec3/oracle/fake_db.hpp b/circuits/src/aztec3/oracle/fake_db.hpp new file mode 100644 index 00000000000..a37ed8be0ed --- /dev/null +++ b/circuits/src/aztec3/oracle/fake_db.hpp @@ -0,0 +1,167 @@ +#pragma once + +#include + +#include + +#include +#include + +#include + +namespace aztec3::oracle { + +using aztec3::circuits::abis::CallContext; + +using aztec3::circuits::apps::UTXOSLoadDatum; + +using aztec3::circuits::apps::notes::DefaultPrivateNotePreimage; + +using aztec3::circuits::apps::notes::DefaultSingletonPrivateNotePreimage; + +using plonk::stdlib::types::CircuitTypes; +using NT = plonk::stdlib::types::NativeTypes; + +// A temporary stub, whilst building other things first. +class FakeDB { + public: + FakeDB(){}; + + /** + * For getting a singleton UTXO (not a set). + * + * NOTICE: this fake db stub is hard-coded to a DefaultPrivateNotePreimage which _itself_ is hard-coded to the value + * type being a field. + * So if you want to test other note types against this stub DB, you'll need to write your own stub DB entry. + */ + UTXOSLoadDatum> get_utxo_sload_datum( + NT::address const& contract_address, + NT::grumpkin_point const& storage_slot_point, + DefaultPrivateNotePreimage const& advice) + // NT::address const& owner, + // NT::fr required_utxo_tree_root, + // size_t utxo_tree_depth) + { + (void)storage_slot_point; // Not used in this 'fake' implementation. + + DefaultPrivateNotePreimage preimage{ + .value = 100, + .owner = advice.owner, + .creator_address = 0, + .memo = 3456, + .salt = 1234, + .nonce = 2345, + .is_dummy = false, + }; + + const size_t utxo_tree_depth = 32; + const NT::fr required_utxo_tree_root = 2468; + + std::vector sibling_path(utxo_tree_depth); + std::fill(sibling_path.begin(), sibling_path.end(), 1); // Fill with 1's to be lazy. TODO: return a valid path. + + return { + .commitment = 1, + .contract_address = contract_address, + .preimage = preimage, + + .sibling_path = sibling_path, + .leaf_index = 2, + .old_private_data_tree_root = required_utxo_tree_root, + }; + }; + + /** + * For getting a set of UTXOs. + * + * * NOTICE: this fake db stub is hard-coded to a DefaultPrivateNotePreimage which _itself_ is hard-coded to the + * value type being a field. + * So if you want to test other note types against this stub DB, you'll need to write your own stub DB entry. + */ + std::vector>> get_utxo_sload_data( + NT::address const& contract_address, + NT::grumpkin_point const& storage_slot_point, + size_t const& num_notes, + DefaultPrivateNotePreimage const& advice) + // NT::address const& owner, + // NT::fr required_utxo_tree_root, + // size_t utxo_tree_depth) + { + (void)storage_slot_point; // Not used in this 'fake' implementation. + + std::vector>> data; + + const size_t utxo_tree_depth = 32; + const NT::fr required_utxo_tree_root = 2468; + + std::vector sibling_path(utxo_tree_depth); + std::fill(sibling_path.begin(), sibling_path.end(), 1); // Fill with 1's to be lazy. TODO: return a valid path. + + for (size_t i = 0; i < num_notes; i++) { + DefaultPrivateNotePreimage preimage{ + .value = 100 + i, + .owner = advice.owner, + .creator_address = 0, + .memo = 3456, + .salt = 1234, + .nonce = 2345, + .is_dummy = false, + }; + + data.push_back({ + .commitment = 1, + .contract_address = contract_address, + .preimage = preimage, + + .sibling_path = sibling_path, + .leaf_index = 2, + .old_private_data_tree_root = required_utxo_tree_root, + }); + } + + return data; + }; + + /** + * For getting a singleton UTXO (not a set). + * + * NOTICE: this fake db stub is hard-coded to a DefaultSingletonPrivateNotePreimage which _itself_ is hard-coded to + * the value type being a field. So if you want to test other note types against this stub DB, you'll need to write + * your own stub DB entry. + */ + UTXOSLoadDatum> get_utxo_sload_datum( + NT::address const& contract_address, + NT::grumpkin_point const& storage_slot_point, + DefaultSingletonPrivateNotePreimage const& advice) + // NT::address const& owner, + // NT::fr required_utxo_tree_root, + // size_t utxo_tree_depth) + { + (void)storage_slot_point; // Not used in this 'fake' implementation. + + DefaultSingletonPrivateNotePreimage preimage{ + .value = 100, + .owner = advice.owner, + .salt = 1234, + .nonce = 2345, + }; + + const size_t utxo_tree_depth = 32; + const NT::fr required_utxo_tree_root = 2468; + + std::vector sibling_path(utxo_tree_depth); + std::fill(sibling_path.begin(), sibling_path.end(), 1); // Fill with 1's to be lazy. TODO: return a valid path. + + return { + .commitment = 1, + .contract_address = contract_address, + .preimage = preimage, + + .sibling_path = sibling_path, + .leaf_index = 2, + .old_private_data_tree_root = required_utxo_tree_root, + }; + }; +}; + +} // namespace aztec3::oracle \ No newline at end of file diff --git a/circuits/src/aztec3/oracle/oracle.hpp b/circuits/src/aztec3/oracle/oracle.hpp index 5d9fcc97c0d..cbe82604ae4 100644 --- a/circuits/src/aztec3/oracle/oracle.hpp +++ b/circuits/src/aztec3/oracle/oracle.hpp @@ -1,10 +1,13 @@ #pragma once +#include "fake_db.hpp" + #include #include #include +#include #include @@ -15,6 +18,7 @@ using aztec3::circuits::abis::CallContext; using aztec3::circuits::apps::UTXOSLoadDatum; using aztec3::circuits::apps::notes::DefaultPrivateNotePreimage; +using aztec3::circuits::apps::notes::DefaultSingletonPrivateNotePreimage; using plonk::stdlib::types::CircuitTypes; using NT = plonk::stdlib::types::NativeTypes; @@ -146,107 +150,6 @@ template class NativeOracleInterface { "it shouldn't be trusted, and could lead to circuit bugs"; }; -// A temporary stub, whilst building other things first. -class FakeDB { - public: - FakeDB(){}; - - /** - * For getting a singleton UTXO (not a set). - * - * NOTICE: this fake db stub is hard-coded to a DefaultPrivateNotePreimage which _itself_ is hard-coded to the value - * type being a field. - * So if you want to test other note types against this stub DB, you'll need to write your own stub DB entry. - */ - UTXOSLoadDatum> get_utxo_sload_datum( - NT::address const& contract_address, - NT::grumpkin_point const& storage_slot_point, - DefaultPrivateNotePreimage const& advice) - // NT::address const& owner, - // NT::fr required_utxo_tree_root, - // size_t utxo_tree_depth) - { - (void)storage_slot_point; // Not used in this 'fake' implementation. - - DefaultPrivateNotePreimage preimage{ - .value = 100, - .owner = advice.owner, - .creator_address = 0, - .memo = 3456, - .salt = 1234, - .nonce = 2345, - .is_dummy = false, - }; - - const size_t utxo_tree_depth = 32; - const NT::fr required_utxo_tree_root = 2468; - - std::vector sibling_path(utxo_tree_depth); - std::fill(sibling_path.begin(), sibling_path.end(), 1); // Fill with 1's to be lazy. TODO: return a valid path. - - return { - .commitment = 1, - .contract_address = contract_address, - .preimage = preimage, - - .sibling_path = sibling_path, - .leaf_index = 2, - .old_private_data_tree_root = required_utxo_tree_root, - }; - }; - - /** - * For getting a set of UTXOs. - * - * * NOTICE: this fake db stub is hard-coded to a DefaultPrivateNotePreimage which _itself_ is hard-coded to the - * value type being a field. - * So if you want to test other note types against this stub DB, you'll need to write your own stub DB entry. - */ - std::vector>> get_utxo_sload_data( - NT::address const& contract_address, - NT::grumpkin_point const& storage_slot_point, - size_t const& num_notes, - DefaultPrivateNotePreimage const& advice) - // NT::address const& owner, - // NT::fr required_utxo_tree_root, - // size_t utxo_tree_depth) - { - (void)storage_slot_point; // Not used in this 'fake' implementation. - - std::vector>> data; - - const size_t utxo_tree_depth = 32; - const NT::fr required_utxo_tree_root = 2468; - - std::vector sibling_path(utxo_tree_depth); - std::fill(sibling_path.begin(), sibling_path.end(), 1); // Fill with 1's to be lazy. TODO: return a valid path. - - for (size_t i = 0; i < num_notes; i++) { - DefaultPrivateNotePreimage preimage{ - .value = 100 + i, - .owner = advice.owner, - .creator_address = 0, - .memo = 3456, - .salt = 1234, - .nonce = 2345, - .is_dummy = false, - }; - - data.push_back({ - .commitment = 1, - .contract_address = contract_address, - .preimage = preimage, - - .sibling_path = sibling_path, - .leaf_index = 2, - .old_private_data_tree_root = required_utxo_tree_root, - }); - } - - return data; - }; -}; - typedef NativeOracleInterface NativeOracle; } // namespace aztec3::oracle \ No newline at end of file From 793ef10a1b721047c6cc21c339f69be25407afc8 Mon Sep 17 00:00:00 2001 From: iAmMichaelConnor Date: Sun, 8 Jan 2023 11:14:31 +0000 Subject: [PATCH 026/166] small refactor --- circuits/src/aztec3/circuits/apps/.test.cpp | 58 +++++++--- .../src/aztec3/circuits/apps/contract.hpp | 53 ++++++---- .../src/aztec3/circuits/apps/contract.tpp | 35 ++++-- .../circuits/apps/function_declaration.hpp | 1 + .../apps/function_execution_context.hpp | 7 +- .../circuits/apps/l1_function_interface.hpp | 14 +-- .../default_singleton_private_note/note.tpp | 3 - .../aztec3/circuits/apps/opcodes/opcodes.hpp | 2 +- .../apps/state_vars/utxo_state_var.hpp | 1 + .../apps/test_apps/escrow/contract.hpp | 4 +- .../apps/test_apps/escrow/deposit.cpp | 3 +- .../circuits/apps/test_apps/escrow/init.hpp | 2 +- .../apps/test_apps/escrow/transfer.cpp | 3 +- .../apps/test_apps/escrow/withdraw.cpp | 7 +- .../.test.cpp | 63 ++++++----- .../README.md | 2 + .../contract.hpp | 60 ++++++----- .../function1.cpp | 73 ------------- .../function1.hpp | 15 --- .../function2.cpp | 50 --------- .../function2.hpp | 14 --- .../function_1_1.cpp | 100 ++++++++++++++++++ .../function_1_1.hpp | 17 +++ .../function_2_1.cpp | 81 ++++++++++++++ .../function_2_1.hpp | 16 +++ .../index.hpp | 8 +- .../private_to_private_function_call/init.hpp | 54 ++++++---- .../src/aztec3/circuits/types/address.hpp | 11 ++ 28 files changed, 454 insertions(+), 303 deletions(-) create mode 100644 circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/README.md delete mode 100644 circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.cpp delete mode 100644 circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.hpp delete mode 100644 circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function2.cpp delete mode 100644 circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function2.hpp create mode 100644 circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_1_1.cpp create mode 100644 circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_1_1.hpp create mode 100644 circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_2_1.cpp create mode 100644 circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_2_1.hpp diff --git a/circuits/src/aztec3/circuits/apps/.test.cpp b/circuits/src/aztec3/circuits/apps/.test.cpp index 8f4a8485784..a8ebc2571d8 100644 --- a/circuits/src/aztec3/circuits/apps/.test.cpp +++ b/circuits/src/aztec3/circuits/apps/.test.cpp @@ -45,14 +45,14 @@ using plonk::stdlib::types::to_ct; // exec_ctx // using aztec3::circuits::apps::FunctionExecutionContext; +// Contract +using Contract = aztec3::circuits::apps::Contract; + // Oracle using DB = aztec3::oracle::FakeDB; using aztec3::oracle::NativeOracle; using OracleWrapper = aztec3::circuits::apps::OracleWrapperInterface; -// Contract -using Contract = aztec3::circuits::apps::Contract; - // StateVars using aztec3::circuits::apps::state_vars::FieldStateVar; using aztec3::circuits::apps::state_vars::MappingStateVar; @@ -110,11 +110,17 @@ TEST_F(state_var_tests, mapping) FunctionExecutionContext exec_ctx(composer, oracle); // TODO: - // Interestingly, if I scope the below, the debugger works, but running the test via the command line fails. I - // reckon the contract (and crucially, all pointers to the contract which are stored in other classes) is being - // deleted... so the declaration of this contract and any pointers probably all need to be shared_ptr. + // Interestingly, if I scope the below, the debugger works, but running the test via the command line fails. This is + // because all pointers to the contract which are stored in other classes become dangling pointers, because contract + // would go out of scope immediately... so the declaration of this contract and any pointers probably all need to be + // shared_ptr eventually. // { - Contract contract(exec_ctx, "TestContract"); + + // I'm not entirely sure why we need to prepend `::` to `Contract`, to get to the unnamed namespace's declaration of + // `Contract` above... + ::Contract contract("TestContract"); + exec_ctx.register_contract(&contract); + contract.declare_state_var("my_mapping"); // } @@ -135,7 +141,9 @@ TEST_F(state_var_tests, mapping_within_mapping) FunctionExecutionContext exec_ctx(composer, oracle); // { - Contract contract(exec_ctx, "TestContract"); + ::Contract contract("TestContract"); + exec_ctx.register_contract(&contract); + contract.declare_state_var("my_mapping"); // } @@ -154,7 +162,9 @@ TEST_F(state_var_tests, partial_mapping) FunctionExecutionContext exec_ctx(composer, oracle); // { - Contract contract(exec_ctx, "TestContract"); + ::Contract contract("TestContract"); + exec_ctx.register_contract(&contract); + contract.declare_state_var("my_mapping"); // } @@ -172,7 +182,9 @@ TEST_F(state_var_tests, utxo_of_default_private_note_fr) OracleWrapper oracle = OracleWrapper(composer, native_oracle); FunctionExecutionContext exec_ctx(composer, oracle); - Contract contract(exec_ctx, "TestContract"); + ::Contract contract("TestContract"); + exec_ctx.register_contract(&contract); + contract.declare_state_var("my_utxo"); // FUNCTION: @@ -221,7 +233,9 @@ TEST_F(state_var_tests, utxo_set_of_default_private_notes_fr) // return (i < j); // }; - Contract contract(exec_ctx, "TestContract"); + ::Contract contract("TestContract"); + exec_ctx.register_contract(&contract); + contract.declare_state_var("balances"); // FUNCTION: @@ -275,7 +289,9 @@ TEST_F(state_var_tests, initialise_utxo_of_default_singleton_private_note_fr) OracleWrapper oracle = OracleWrapper(composer, native_oracle); FunctionExecutionContext exec_ctx(composer, oracle); - Contract contract(exec_ctx, "TestContract"); + ::Contract contract("TestContract"); + exec_ctx.register_contract(&contract); + contract.declare_state_var("my_utxo"); // FUNCTION: @@ -286,9 +302,19 @@ TEST_F(state_var_tests, initialise_utxo_of_default_singleton_private_note_fr) UTXO my_utxo(&exec_ctx, "my_utxo"); - const auto& msg_sender = oracle.get_msg_sender(); + // We hard-code the address of the person who may initialise the state in the 'contract's bytecode' (i.e. as a + // selector value). (Number chosen to match msg_sender of tests). + const CT::address unique_person_who_may_initialise = + NT::uint256(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL); - my_utxo.initialise({ .value = 100, .owner = msg_sender }); + unique_person_who_may_initialise.assert_equal(oracle.get_msg_sender()); + + // The person who may initialise the note might be different from the person who's actually given the note to own. + // (E.g. the caller of this function might be the deployer of the contract, who is initialising notes on behalf of + // other users) + CT::address owner_of_initialised_note = 888888; + + my_utxo.initialise({ .value = 100, .owner = owner_of_initialised_note }); exec_ctx.finalise(); @@ -310,7 +336,9 @@ TEST_F(state_var_tests, modify_utxo_of_default_singleton_private_note_fr) OracleWrapper oracle = OracleWrapper(composer, native_oracle); FunctionExecutionContext exec_ctx(composer, oracle); - Contract contract(exec_ctx, "TestContract"); + ::Contract contract("TestContract"); + exec_ctx.register_contract(&contract); + contract.declare_state_var("my_utxo"); // FUNCTION: diff --git a/circuits/src/aztec3/circuits/apps/contract.hpp b/circuits/src/aztec3/circuits/apps/contract.hpp index 12f7d155151..d6d17fce9b7 100644 --- a/circuits/src/aztec3/circuits/apps/contract.hpp +++ b/circuits/src/aztec3/circuits/apps/contract.hpp @@ -15,43 +15,53 @@ using plonk::stdlib::witness_t; using plonk::stdlib::types::CircuitTypes; using NT = plonk::stdlib::types::NativeTypes; -template class FunctionExecutionContext; +// template class FunctionExecutionContext; -template class Contract { - typedef CircuitTypes CT; - typedef typename CT::fr fr; - typedef typename CT::uint32 uint32; +template class Contract { + typedef typename NCT::fr fr; + typedef typename NCT::uint32 uint32; public: - FunctionExecutionContext& exec_ctx; - const std::string contract_name; fr state_var_counter = 0; + std::vector state_var_names; + std::map start_slots_by_state_var_name; - std::map> function_signatures; + std::map> function_signatures; - std::map> l1_functions; + std::map> l1_functions; - Contract(FunctionExecutionContext& exec_ctx, std::string const& contract_name) - : exec_ctx(exec_ctx) - , contract_name(contract_name) + std::map> imported_contracts; + + Contract(std::string const& contract_name) + : contract_name(contract_name) { - exec_ctx.register_contract(this); + // exec_ctx.register_contract(this); } - void set_functions(std::vector> const& functions); + void set_functions(std::vector> const& functions); + + void import_contracts(std::vector>> const import_declarations); + + Contract& get_imported_contract(std::string const& name) + { + if (!imported_contracts.contains(name)) { + throw_or_abort("No contract with that name imported"); + } + return imported_contracts[name]; + } // TODO: return some Function class which has a `call` method... // FunctionSignature get_function(std::string name) { return function_signature[name]; } - FunctionSignature get_function_signature_by_name(std::string const& name); + FunctionSignature get_function_signature_by_name(std::string const& name); - void import_l1_function(L1FunctionInterfaceStruct const& l1_function_struct); + void import_l1_function(L1FunctionInterfaceStruct const& l1_function_struct); - L1FunctionInterface& get_l1_function(std::string const& name); + L1FunctionInterface& get_l1_function(std::string const& name); // TODO: maybe also declare a type at this stage, so the correct type can be checked-for when the StateVar type is // created within the function. @@ -65,18 +75,21 @@ template class Contract { start_slots_by_state_var_name[state_var_name] = state_var_counter; // state_var_counter++; state_var_counter++; - ASSERT(state_var_counter.get_value() == state_var_names.size()); + ASSERT(state_var_counter == state_var_names.size()); }; fr& get_start_slot(std::string const& state_var_name) { if (!start_slots_by_state_var_name.contains(state_var_name)) { - throw_or_abort("Name '" + state_var_name + "' not found. Use `declare_private_state_var`."); + throw_or_abort("Name '" + state_var_name + "' not found. Use `declare_state_var`."); } return start_slots_by_state_var_name.at(state_var_name); }; private: + // Prevents an infinite loop if two contracts import each other. + bool already_imported; + void push_new_state_var_name(std::string const& state_var_name) { if (index_of(state_var_names, state_var_name) == -1) { @@ -95,4 +108,6 @@ template class Contract { // - We retain implicit instantiation of templates. // - We don't implement method definitions in this file, to avoid a circular dependency with // function_execution_context.hpp. +// TODO: things have changed since initially importing this .tpp file - maybe a conventional .cpp file is possible now +// instead... #include "contract.tpp" \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/contract.tpp b/circuits/src/aztec3/circuits/apps/contract.tpp index bc3f5101b59..c833af0df6a 100644 --- a/circuits/src/aztec3/circuits/apps/contract.tpp +++ b/circuits/src/aztec3/circuits/apps/contract.tpp @@ -19,16 +19,15 @@ using NT = plonk::stdlib::types::NativeTypes; using aztec3::circuits::abis::FunctionSignature; // using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; -template -void Contract::set_functions(std::vector>> const& functions) +template void Contract::set_functions(std::vector> const& functions) { for (uint32_t i = 0; i < functions.size(); ++i) { const auto& function = functions[i]; if (function_signatures.contains(function.name)) { throw_or_abort("Name already exists"); } - function_signatures[function.name] = FunctionSignature{ - // .contract_address = exec.oracle.get_this_contract_address(), + function_signatures[function.name] = FunctionSignature{ + // TODO: vk_index to actually be derived as 1st 4-bytes of hash of function signature. .vk_index = uint32(i), .is_private = function.is_private, .is_constructor = function.is_constructor, @@ -36,11 +35,28 @@ void Contract::set_functions(std::vector +void Contract::import_contracts(std::vector>> const import_declarations) +{ + // Prevents an infinite loop if two contracts import each-other. + if (already_imported) { + return; + } + + for (uint32_t i = 0; i < import_declarations.size(); ++i) { + const std::pair>& decl = import_declarations[i]; + if (imported_contracts.contains(decl.first)) { + throw_or_abort("Name already exists"); + } + imported_contracts.insert(decl); + } + already_imported = true; +} + // TODO: return some Function class which has a `call` method... // FunctionSignature get_function(std::string name) { return function_signature[name]; } -template -FunctionSignature> Contract::get_function_signature_by_name(std::string const& name) +template FunctionSignature Contract::get_function_signature_by_name(std::string const& name) { if (!function_signatures.contains(name)) { throw_or_abort("function signature not found"); @@ -48,14 +64,13 @@ FunctionSignature> Contract::get_function_signa return function_signatures[name]; } -template -void Contract::import_l1_function(L1FunctionInterfaceStruct const& l1_function_struct) +template void Contract::import_l1_function(L1FunctionInterfaceStruct const& l1_function_struct) { - L1FunctionInterface l1_function = L1FunctionInterface(this, l1_function_struct); + L1FunctionInterface l1_function = L1FunctionInterface(this, l1_function_struct); l1_functions.insert(std::make_pair(l1_function_struct.function_name, l1_function)); }; -template L1FunctionInterface& Contract::get_l1_function(std::string const& name) +template L1FunctionInterface& Contract::get_l1_function(std::string const& name) { if (!l1_functions.contains(name)) { throw_or_abort("L1 function not found. Make sure to import_l1_function()"); diff --git a/circuits/src/aztec3/circuits/apps/function_declaration.hpp b/circuits/src/aztec3/circuits/apps/function_declaration.hpp index 7c70d11e148..7289204d3e4 100644 --- a/circuits/src/aztec3/circuits/apps/function_declaration.hpp +++ b/circuits/src/aztec3/circuits/apps/function_declaration.hpp @@ -10,6 +10,7 @@ using plonk::stdlib::witness_t; using plonk::stdlib::types::CircuitTypes; using plonk::stdlib::types::NativeTypes; +// This exists just so that designated initialisers can be used when passing this info to a function, for readability. template struct FunctionDeclaration { typedef typename NCT::boolean boolean; diff --git a/circuits/src/aztec3/circuits/apps/function_execution_context.hpp b/circuits/src/aztec3/circuits/apps/function_execution_context.hpp index eb7b8a41be3..a0cbfca827b 100644 --- a/circuits/src/aztec3/circuits/apps/function_execution_context.hpp +++ b/circuits/src/aztec3/circuits/apps/function_execution_context.hpp @@ -34,6 +34,7 @@ using plonk::stdlib::types::CircuitTypes; using NT = plonk::stdlib::types::NativeTypes; template class FunctionExecutionContext { + typedef NativeTypes NT; typedef CircuitTypes CT; typedef typename CT::fr fr; @@ -45,7 +46,7 @@ template class FunctionExecutionContext { Composer& composer; OracleWrapperInterface& oracle; - Contract* contract = nullptr; + Contract* contract = nullptr; // TODO: make this private! OptionalPrivateCircuitPublicInputs private_circuit_public_inputs; @@ -67,10 +68,10 @@ template class FunctionExecutionContext { private_circuit_public_inputs.call_context = oracle.get_call_context(); } - void register_contract(Contract* contract) + void register_contract(Contract* contract) { if (this->contract != nullptr) { - throw_or_abort("contract already assigned to this FunctionExecutionContext"); + throw_or_abort("A contract is already assigned to this FunctionExecutionContext"); } this->contract = contract; } diff --git a/circuits/src/aztec3/circuits/apps/l1_function_interface.hpp b/circuits/src/aztec3/circuits/apps/l1_function_interface.hpp index 835ea3ecf0c..b388c85cdea 100644 --- a/circuits/src/aztec3/circuits/apps/l1_function_interface.hpp +++ b/circuits/src/aztec3/circuits/apps/l1_function_interface.hpp @@ -10,29 +10,29 @@ using plonk::stdlib::witness_t; using plonk::stdlib::types::CircuitTypes; using plonk::stdlib::types::NativeTypes; -template class Contract; +template class Contract; // We use the struct to retain designated initialisation, to make contract creation more readable. -template struct L1FunctionInterfaceStruct { - typedef typename CircuitTypes::fr fr; +template struct L1FunctionInterfaceStruct { + typedef typename NCT::fr fr; std::string function_name; fr function_selector; size_t num_params = 0; }; -template class L1FunctionInterface { - typedef typename CircuitTypes::fr fr; +template class L1FunctionInterface { + typedef typename NCT::fr fr; public: - Contract* contract; + Contract* contract; std::string function_name; fr function_selector; size_t num_params; L1FunctionInterface(){}; - L1FunctionInterface(Contract* contract, L1FunctionInterfaceStruct const& l1_fn_struct) + L1FunctionInterface(Contract* contract, L1FunctionInterfaceStruct const& l1_fn_struct) : contract(contract) , function_name(l1_fn_struct.function_name) , function_selector(l1_fn_struct.function_selector) diff --git a/circuits/src/aztec3/circuits/apps/notes/default_singleton_private_note/note.tpp b/circuits/src/aztec3/circuits/apps/notes/default_singleton_private_note/note.tpp index e096b3d33db..d7dc68447dc 100644 --- a/circuits/src/aztec3/circuits/apps/notes/default_singleton_private_note/note.tpp +++ b/circuits/src/aztec3/circuits/apps/notes/default_singleton_private_note/note.tpp @@ -227,9 +227,6 @@ typename CircuitTypes::fr DefaultSingletonPrivateNote::ge { auto& oracle = get_oracle(); - // With this note, the person initialising the note must be the owner. - (*note_preimage.owner).assert_equal(oracle.get_msg_sender()); - const fr& owner_private_key = oracle.get_msg_sender_private_key(); // We prevent this storage slot from even being initialised again: diff --git a/circuits/src/aztec3/circuits/apps/opcodes/opcodes.hpp b/circuits/src/aztec3/circuits/apps/opcodes/opcodes.hpp index 2d57acbb64a..8d2e0c3f634 100644 --- a/circuits/src/aztec3/circuits/apps/opcodes/opcodes.hpp +++ b/circuits/src/aztec3/circuits/apps/opcodes/opcodes.hpp @@ -33,7 +33,7 @@ using plonk::stdlib::types::NativeTypes; template class Opcodes { public: typedef CircuitTypes CT; - typedef NativeTypes NT; + typedef typename CT::address address; /** * @brief diff --git a/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp b/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp index aae8507f559..d3723691cd3 100644 --- a/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp +++ b/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp @@ -32,6 +32,7 @@ template class UTXOStateVar : public StateVar typedef NativeTypes NT; typedef typename CT::fr fr; typedef typename CT::grumpkin_point grumpkin_point; + typedef typename CT::address address; typedef typename Note::NotePreimage NotePreimage; diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp index 2c73665ec3d..45655fbec4d 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp @@ -7,9 +7,9 @@ namespace aztec3::circuits::apps::test_apps::escrow { -inline Contract init_contract(FunctionExecutionContext& exec_ctx) +inline Contract init_contract() { - Contract contract(exec_ctx, "Escrow"); + Contract contract("Escrow"); contract.declare_state_var("balances"); diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp index 74bcb5d6b4a..3506aeec2bc 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp @@ -19,7 +19,8 @@ OptionalPrivateCircuitPublicInputs deposit(FunctionExecutionContext& exec_ct ****************************************************************/ // Make the exec_ctx aware of the contract's layout. - init_contract(exec_ctx); + Contract contract = init_contract(); + exec_ctx.register_contract(&contract); // Convert params into circuit types: auto& composer = exec_ctx.composer; diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/init.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/init.hpp index 400e8547f73..be7748cee22 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/init.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/init.hpp @@ -25,7 +25,7 @@ using DB = oracle::FakeDB; using oracle::NativeOracle; using OracleWrapper = apps::OracleWrapperInterface; -using Contract = apps::Contract; +using Contract = apps::Contract; using FunctionExecutionContext = apps::FunctionExecutionContext; using plonk::stdlib::types::to_ct; diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp index cab215a0e69..559e98b9741 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp @@ -21,7 +21,8 @@ OptionalPrivateCircuitPublicInputs transfer(FunctionExecutionContext& exec_c ****************************************************************/ // Make the exec_ctx aware of the contract's layout. - init_contract(exec_ctx); + Contract contract = init_contract(); + exec_ctx.register_contract(&contract); // Convert arguments into circuit types: auto& composer = exec_ctx.composer; diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp index aa8491bc6cb..7aa48c54d9b 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp @@ -20,7 +20,8 @@ OptionalPrivateCircuitPublicInputs withdraw(FunctionExecutionContext& exec_c ****************************************************************/ // Make the exec_ctx aware of the contract's layout. - Contract contract = init_contract(exec_ctx); + Contract contract = init_contract(); + exec_ctx.register_contract(&contract); // Convert arguments into circuit types: auto& composer = exec_ctx.composer; @@ -68,10 +69,10 @@ OptionalPrivateCircuitPublicInputs withdraw(FunctionExecutionContext& exec_c .memo = memo, }); - auto& l1_withdraw_function = contract.get_l1_function("withdraw"); + // auto& l1_withdraw_function = contract.get_l1_function("withdraw"); // TODO: this doesn't do anything at the moment: - l1_withdraw_function.call({ asset_id, amount, msg_sender.to_field() }); + // l1_withdraw_function.call({ asset_id, amount, msg_sender.to_field() }); /**************************************************************** * CLEANUP diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp index 04dc49d1317..27e02abe96e 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp @@ -1,45 +1,44 @@ -// #include "index.hpp" +#include "index.hpp" -// #include -// #include +#include +#include -// namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { +namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { -// class private_to_private_function_call_tests : public ::testing::Test {}; +class private_to_private_function_call_tests : public ::testing::Test {}; -// TEST(private_to_private_function_call_tests, test_private_to_private_function_call) -// { +TEST(private_to_private_function_call_tests, test_private_to_private_function_call) +{ -// C fn1_composer; -// DB db; + C fn1_composer; + DB db; -// const NT::address contract_address = 12345; -// const NT::fr msg_sender_private_key = 123456789; -// const NT::address msg_sender = -// NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, -// 0x2ef9f7f09867fd6eULL)); -// const NT::address tx_origin = msg_sender; + const NT::address contract_address = 12345; + const NT::fr msg_sender_private_key = 123456789; + const NT::address msg_sender = + uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL); + const NT::address tx_origin = msg_sender; -// NativeOracle fn1_oracle = NativeOracle(db, contract_address, msg_sender, tx_origin, msg_sender_private_key); -// OracleWrapper fn1_oracle_wrapper = OracleWrapper(fn1_composer, fn1_oracle); + NativeOracle fn1_oracle = NativeOracle(db, contract_address, msg_sender, tx_origin, msg_sender_private_key); + OracleWrapper fn1_oracle_wrapper = OracleWrapper(fn1_composer, fn1_oracle); -// FunctionExecutionContext fn1_exec_ctx(fn1_composer, fn1_oracle_wrapper); + FunctionExecutionContext fn1_exec_ctx(fn1_composer, fn1_oracle_wrapper); -// auto a = NT::fr(111); -// auto b = NT::fr(222); -// auto c = NT::fr(333); + auto a = NT::fr(111); + auto b = NT::fr(222); + auto c = NT::fr(333); -// auto result = function_1_1(fn1_exec_ctx, a, b, c); + auto result = function_1_1(fn1_exec_ctx, a, b, c); -// info("result: ", result); + info("result: ", result); -// info("computed witness: ", fn1_composer.computed_witness); -// info("witness: ", fn1_composer.witness); -// // info("constant variables: ", fn1_composer.constant_variables); -// // info("variables: ", fn1_composer.variables); -// info("failed?: ", fn1_composer.failed); -// info("err: ", fn1_composer.err); -// info("n: ", fn1_composer.n); -// } + info("computed witness: ", fn1_composer.computed_witness); + info("witness: ", fn1_composer.witness); + // info("constant variables: ", fn1_composer.constant_variables); + // info("variables: ", fn1_composer.variables); + info("failed?: ", fn1_composer.failed); + info("err: ", fn1_composer.err); + info("n: ", fn1_composer.n); +} -// } // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file +} // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/README.md b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/README.md new file mode 100644 index 00000000000..34550188adf --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/README.md @@ -0,0 +1,2 @@ +Unfinished example directory. +Not worth reading yet. \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/contract.hpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/contract.hpp index 6d06163e104..a85fb0566cf 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/contract.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/contract.hpp @@ -1,41 +1,43 @@ -// #pragma once +#pragma once -// #include "init.hpp" +#include "init.hpp" -// #include -// #include -// #include +#include +#include +#include -// namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { +namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { -// inline Contract init_contract_1(FunctionExecutionContext& exec_ctx) -// { -// Contract contract(exec_ctx, "contract_1"); +Contract init_contract_2(); -// contract.declare_state_var("x"); -// contract.declare_state_var("y"); +inline Contract init_contract_1() +{ + Contract contract_1("contract_1"); -// // Solely used for assigning vk indices. -// contract.set_functions({ -// { .name = "function_1_1", .is_private = true }, -// }); + contract_1.declare_state_var("x"); -// return contract; -// } + // Solely used for assigning vk indices. + contract_1.set_functions({ + { .name = "function_1_1", .is_private = true }, + }); -// inline Contract init_contract_2(FunctionExecutionContext& exec_ctx) -// { -// Contract contract(exec_ctx, "contract_2"); + contract_1.import_contracts({ std::make_pair("contract_2", init_contract_2()) }); -// contract.declare_state_var("x"); -// contract.declare_state_var("y"); + return contract_1; +} -// // Solely used for assigning vk indices. -// contract.set_functions({ -// { .name = "function_2_1", .is_private = true }, -// }); +inline Contract init_contract_2() +{ + Contract contract_2("contract_2"); -// return contract; -// } + contract_2.declare_state_var("y"); -// } // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file + // Solely used for assigning vk indices. + contract_2.set_functions({ + { .name = "function_2_1", .is_private = true }, + }); + + return contract_2; +} + +} // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.cpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.cpp deleted file mode 100644 index f9edf86cb0f..00000000000 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.cpp +++ /dev/null @@ -1,73 +0,0 @@ -// #include "function1.hpp" -// #include -// #include -// #include "contract.hpp" - -// namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { - -// using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; - -// OptionalPrivateCircuitPublicInputs function1(FunctionExecutionContext& exec_ctx, -// NT::fr const& _a, -// NT::fr const& _b, -// NT::fr const& _c) -// { -// auto& composer = exec_ctx.composer; -// auto& oracle = exec_ctx.oracle; -// Contract contract = init_contract(exec_ctx); - -// CT::fr a = to_ct(composer, _a); -// CT::fr b = to_ct(composer, _b); -// CT::fr c = to_ct(composer, _c); - -// CT::address msg_sender = oracle.get_msg_sender(); - -// auto& x = contract.get_private_state_var("x"); - -// x.add({ -// .value = a, -// .owner = msg_sender, -// .creator_address = msg_sender, -// .memo = 0, -// }); - -// // auto function2 = contract.get_function("function2"); -// const NT::address fn2_contract_address = 23456; - -// C fn2_composer; - -// // Note: it's ok that we swap back into Native Types here - we don't need constraints. Creation of fn2_oracle is -// // necessary for circuit construction only; it's not part of the circuit itself. We check that the call_contexts -// // (msg_sender, contract_address, tx_origin) of functions 1 & 2 relate to one-another in the private kernel -// circuit, -// // by comparing the functions' public inputs. -// NativeOracle fn2_oracle = NativeOracle(oracle.oracle.db, -// fn2_contract_address, -// oracle.get_this_contract_address() -// .to_field() -// .get_value(), // TODO: add get_value() method to address type -// directly. -// oracle.get_tx_origin().to_field().get_value()); -// OracleWrapper fn2_oracle_wrapper = OracleWrapper(fn2_composer, fn2_oracle); - -// FunctionExecutionContext fn1_exec_ctx(fn2_composer, fn2_oracle_wrapper); - -// // auto result = function2.call(a, b, c); - -// auto& public_inputs = exec_ctx.private_circuit_public_inputs; - -// public_inputs.args[0] = a; -// public_inputs.args[1] = b; -// public_inputs.args[2] = c; - -// // public_inputs.private_call_stack[0] = ... - -// exec_ctx.finalise(); - -// info("public inputs: ", public_inputs); - -// return public_inputs.to_native_type(); -// // TODO: also return note preimages and nullifier preimages. -// }; - -// } // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.hpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.hpp deleted file mode 100644 index 2a0754ff21e..00000000000 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function1.hpp +++ /dev/null @@ -1,15 +0,0 @@ -// #pragma once -// #include "init.hpp" -// #include -// #include - -// namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { - -// using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; - -// OptionalPrivateCircuitPublicInputs function1(FunctionExecutionContext& exec_ctx, -// NT::fr const& _a, -// NT::fr const& _b, -// NT::fr const& _c); - -// } // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function2.cpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function2.cpp deleted file mode 100644 index f873aacccc9..00000000000 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function2.cpp +++ /dev/null @@ -1,50 +0,0 @@ -// #include "contract.hpp" -// #include "function1.hpp" -// #include -// #include - -// namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { - -// using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; - -// OptionalPrivateCircuitPublicInputs function1(FunctionExecutionContext& exec_ctx, -// NT::fr const& _d, -// NT::fr const& _e, -// NT::fr const& _f) -// { -// CT::fr d = to_ct(composer, _d); -// CT::fr e = to_ct(composer, _e); -// CT::fr f = to_ct(composer, _f); - -// CT::address msg_sender = oracle.get_msg_sender(); - -// auto env = init(composer, oracle); - -// auto& y = env.get_private_state_var("y"); - -// auto product = d * e * f; - -// y.add({ -// .value = product, -// .owner = msg_sender, -// .creator_address = msg_sender, -// .memo = 0, -// }); - -// auto& public_inputs = env.private_circuit_public_inputs; - -// public_inputs.args[0] = d; -// public_inputs.args[1] = e; -// public_inputs.args[2] = f; - -// public_inputs.return_values[0] = product; - -// env.finalise(); - -// info("public inputs: ", public_inputs); - -// return public_inputs.to_native_type(); -// // TODO: also return note preimages and nullifier preimages. -// }; - -// } // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function2.hpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function2.hpp deleted file mode 100644 index c624c30c9e4..00000000000 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function2.hpp +++ /dev/null @@ -1,14 +0,0 @@ -// #pragma once -// #include "init.hpp" -// #include - -// namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { - -// using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; - -// OptionalPrivateCircuitPublicInputs function2(FunctionExecutionContext& exec_ctx, -// NT::fr const& _d, -// NT::fr const& _e, -// NT::fr const& _f); - -// } // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_1_1.cpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_1_1.cpp new file mode 100644 index 00000000000..aea929be57a --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_1_1.cpp @@ -0,0 +1,100 @@ +#include "function_1_1.hpp" + +#include "contract.hpp" + +#include +#include + +namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { + +using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; + +OptionalPrivateCircuitPublicInputs function_1_1(FunctionExecutionContext& exec_ctx, + NT::fr const& _a, + NT::fr const& _b, + NT::fr const& _c) +{ + /**************************************************************** + * Initialisation + ****************************************************************/ + + // Make the exec_ctx aware of the contract's layout. + Contract contract_1 = init_contract_1(); + exec_ctx.register_contract(&contract_1); + + // Convert arguments into circuit types: + auto& composer = exec_ctx.composer; + + CT::fr a = to_ct(composer, _a); + CT::fr b = to_ct(composer, _b); + CT::fr c = to_ct(composer, _c); + + /**************************************************************** + * Get States & Globals used by the function + ****************************************************************/ + + auto& oracle = exec_ctx.oracle; + + CT::address msg_sender = oracle.get_msg_sender(); + + // Syntactic sugar for declaring a state variable: + UTXO x(&exec_ctx, "x"); + + /**************************************************************** + * BODY + ****************************************************************/ + + // Hard-coded to match tests. + const CT::address unique_person_who_may_initialise = + NT::uint256(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL); + + unique_person_who_may_initialise.assert_equal(msg_sender); + + x.initialise({ + .value = a, + .owner = msg_sender, + }); + + // auto function_2_1 = contract_1.get_function("function_2_1"); + // const NT::address fn2_contract_address = 23456; + + // C fn2_composer; + + // // Note: it's ok that we swap back into Native Types here - we don't need constraints. Creation of fn2_oracle is + // // necessary for circuit construction only; it's not part of the circuit itself. We check that the call_contexts + // // (msg_sender, contract_address, tx_origin) of functions 1 & 2 relate to one-another in the private kernel + // circuit, + // // by comparing the functions' public inputs. + // NativeOracle fn2_oracle = NativeOracle( // + // oracle.oracle.db, + // fn2_contract_address, + // oracle.get_this_contract_address().get_value(), + // oracle.get_tx_origin().get_value()); + // OracleWrapper fn2_oracle_wrapper = OracleWrapper(fn2_composer, fn2_oracle); + + // FunctionExecutionContext fn1_exec_ctx(fn2_composer, fn2_oracle_wrapper); + + // auto result = function_2_1.call(a, b, c); + + /**************************************************************** + * CLEANUP + ****************************************************************/ + + // Push args to the public inputs. + auto& public_inputs = exec_ctx.private_circuit_public_inputs; + + public_inputs.args[0] = a; + public_inputs.args[1] = b; + public_inputs.args[2] = c; + + // public_inputs.private_call_stack[0] = ... + + exec_ctx.finalise(); + + info("public inputs: ", public_inputs); + + return public_inputs.to_native_type(); + // TODO: also return note preimages and nullifier preimages. +}; + +} // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_1_1.hpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_1_1.hpp new file mode 100644 index 00000000000..62accb6c95e --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_1_1.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include "init.hpp" + +#include +#include + +namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { + +using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; + +OptionalPrivateCircuitPublicInputs function_1_1(FunctionExecutionContext& exec_ctx, + NT::fr const& _a, + NT::fr const& _b, + NT::fr const& _c); + +} // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_2_1.cpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_2_1.cpp new file mode 100644 index 00000000000..b79264a0e31 --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_2_1.cpp @@ -0,0 +1,81 @@ +#include "function_2_1.hpp" + +#include "contract.hpp" + +#include + +namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { + +using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; + +OptionalPrivateCircuitPublicInputs function_2_1(FunctionExecutionContext& exec_ctx, + NT::fr const& _d, + NT::fr const& _e, + NT::fr const& _f) +{ + /**************************************************************** + * Initialisation + ****************************************************************/ + + // Make the exec_ctx aware of the contract's layout. + Contract contract_2 = init_contract_2(); + exec_ctx.register_contract(&contract_2); + + // Convert arguments into circuit types: + auto& composer = exec_ctx.composer; + + CT::fr d = to_ct(composer, _d); + CT::fr e = to_ct(composer, _e); + CT::fr f = to_ct(composer, _f); + + /**************************************************************** + * Get States & Globals used by the function + ****************************************************************/ + + auto& oracle = exec_ctx.oracle; + + CT::address msg_sender = oracle.get_msg_sender(); + + // Syntactic sugar for declaring a state variable: + UTXO y(&exec_ctx, "y"); + + /**************************************************************** + * BODY + ****************************************************************/ + + auto product = d * e * f; + + CT::address unique_person_who_may_initialise = 999999; + + unique_person_who_may_initialise.assert_equal(msg_sender); + + y.initialise({ + .value = product, + .owner = msg_sender, + }); + // TODO: how to initialise a UTXO if it's part of a nested function call, because the msg_sender will be a contract + // address (currently the unique_initialiser_address is asserted to be the msg_sender). + + /**************************************************************** + * CLEANUP + ****************************************************************/ + + // Push args to the public inputs. + + auto& public_inputs = exec_ctx.private_circuit_public_inputs; + + public_inputs.args[0] = d; + public_inputs.args[1] = e; + public_inputs.args[2] = f; + + public_inputs.return_values[0] = product; + + exec_ctx.finalise(); + + info("public inputs: ", public_inputs); + + return public_inputs.to_native_type(); + // TODO: also return note preimages and nullifier preimages. +}; + +} // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_2_1.hpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_2_1.hpp new file mode 100644 index 00000000000..1cfe4aed5ec --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_2_1.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include "init.hpp" + +#include + +namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { + +using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; + +OptionalPrivateCircuitPublicInputs function_2_1(FunctionExecutionContext& exec_ctx, + NT::fr const& _d, + NT::fr const& _e, + NT::fr const& _f); + +} // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/index.hpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/index.hpp index 03f7484f7ee..61fdb7a6444 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/index.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/index.hpp @@ -1,4 +1,4 @@ -// #include "init.hpp" -// #include "contract.hpp" -// #include "function1.hpp" -// // #include "function2.hpp" \ No newline at end of file +#include "init.hpp" +#include "contract.hpp" +#include "function_1_1.hpp" +#include "function_2_1.hpp" \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/init.hpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/init.hpp index 014419598ae..612ec902ada 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/init.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/init.hpp @@ -1,29 +1,43 @@ -// #pragma once +#pragma once -// #include -// #include -// #include +#include +#include +#include +#include +#include -// #include +#include -// #include -// #include -// #include -// #include +#include +#include +#include +#include -// namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { +namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { -// using C = plonk::stdlib::types::turbo::Composer; -// using CT = plonk::stdlib::types::CircuitTypes; -// using NT = plonk::stdlib::types::NativeTypes; +using C = plonk::stdlib::types::turbo::Composer; +using CT = plonk::stdlib::types::CircuitTypes; +using NT = plonk::stdlib::types::NativeTypes; -// using DB = oracle::FakeDB; -// using oracle::NativeOracle; -// using OracleWrapper = OracleWrapperInterface; +using DB = oracle::FakeDB; +using oracle::NativeOracle; +using OracleWrapper = OracleWrapperInterface; -// using Contract = apps::Contract; -// using FunctionExecutionContext = apps::FunctionExecutionContext; +using Contract = apps::Contract; +using FunctionExecutionContext = apps::FunctionExecutionContext; -// using plonk::stdlib::types::to_ct; +using plonk::stdlib::types::to_ct; -// } // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file +// StateVars +using apps::state_vars::UTXOStateVar; + +// Get rid of ugle `Composer` template arg from our state var types: +template struct SpecialisedTypes { + typedef UTXOStateVar utxo; +}; + +template using UTXO = typename SpecialisedTypes::utxo; + +using Note = apps::notes::DefaultSingletonPrivateNote; + +} // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/types/address.hpp b/circuits/src/aztec3/circuits/types/address.hpp index 4de48cbf879..26f734b2d6d 100644 --- a/circuits/src/aztec3/circuits/types/address.hpp +++ b/circuits/src/aztec3/circuits/types/address.hpp @@ -1,4 +1,5 @@ #pragma once +#include #include #include #include @@ -10,6 +11,7 @@ namespace aztec3::circuits::types { using barretenberg::fr; +using numeric::uint256_t; using plonk::stdlib::bool_t; using plonk::stdlib::field_t; using plonk::stdlib::group; @@ -30,6 +32,9 @@ class address { address(fr const& address) : address_(address){}; + address(uint256_t const& address) + : address_(address){}; + address(int const& address) : address_(fr(address)){}; @@ -74,6 +79,10 @@ template class address_t { : address_(address) , context_(address.context){}; + address_t(uint256_t const& address) + : address_(address) + , context_(nullptr){}; + address_t(int const& address) : address_(address) , context_(nullptr){}; @@ -95,6 +104,8 @@ template class address_t { field_t to_field() const { return address_; } + fr get_value() const { return address_.get_value(); }; + void assert_equal(const address_t& rhs, std::string const& msg = "address_t::assert_equal") const { address_.assert_equal(rhs.address_, msg); From 6d62427f33f78e004c2ec14dd2c844edc7f9b538 Mon Sep 17 00:00:00 2001 From: iAmMichaelConnor Date: Tue, 10 Jan 2023 09:54:16 +0000 Subject: [PATCH 027/166] updating abi structs --- .../src/aztec3/circuits/abis/call_context.hpp | 24 ++-- ...contract_deployment_call_public_inputs.hpp | 115 ----------------- .../abis/contract_deployment_data.hpp | 122 ++++++++++++++++++ circuits/src/aztec3/circuits/abis/index.hpp | 1 - .../abis/private_circuit_public_inputs.hpp | 106 ++++++++------- .../call_context_reconciliation_data.hpp | 4 +- .../abis/public_circuit_public_inputs.hpp | 20 +-- .../src/aztec3/circuits/abis/tx_context.hpp | 38 +++--- .../aztec3/circuits/kernel/private/.test.cpp | 15 ++- .../kernel/private/private_kernel_circuit.cpp | 17 ++- circuits/src/aztec3/constants.hpp | 2 +- 11 files changed, 246 insertions(+), 218 deletions(-) delete mode 100644 circuits/src/aztec3/circuits/abis/contract_deployment_call_public_inputs.hpp create mode 100644 circuits/src/aztec3/circuits/abis/contract_deployment_data.hpp diff --git a/circuits/src/aztec3/circuits/abis/call_context.hpp b/circuits/src/aztec3/circuits/abis/call_context.hpp index e98b508ac34..f6ac5031eeb 100644 --- a/circuits/src/aztec3/circuits/abis/call_context.hpp +++ b/circuits/src/aztec3/circuits/abis/call_context.hpp @@ -25,6 +25,7 @@ template struct CallContext { boolean is_delegate_call; boolean is_static_call; + boolean is_contract_deployment; fr reference_block_num; @@ -32,10 +33,11 @@ template struct CallContext { { return msg_sender == other.msg_sender && storage_contract_address == other.storage_contract_address && tx_origin == other.tx_origin && is_delegate_call == other.is_delegate_call && - is_static_call == other.is_static_call && reference_block_num == other.reference_block_num; + is_static_call == other.is_static_call && is_contract_deployment == other.is_contract_deployment && + reference_block_num == other.reference_block_num; }; - static CallContext empty() { return { 0, 0, 0, 0, 0, 0 }; }; + static CallContext empty() { return { 0, 0, 0, 0, 0, 0, 0 }; }; template CallContext> to_circuit_type(Composer& composer) const { @@ -45,8 +47,8 @@ template struct CallContext { auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; CallContext> call_context = { - to_ct(msg_sender), to_ct(storage_contract_address), to_ct(tx_origin), - to_ct(is_delegate_call), to_ct(is_static_call), to_ct(reference_block_num), + to_ct(msg_sender), to_ct(storage_contract_address), to_ct(tx_origin), to_ct(is_delegate_call), + to_ct(is_static_call), to_ct(is_contract_deployment), to_ct(reference_block_num), }; @@ -59,8 +61,8 @@ template struct CallContext { auto to_nt = [&](auto& e) { return plonk::stdlib::types::to_nt(e); }; CallContext call_context = { - to_nt(msg_sender), to_nt(storage_contract_address), to_nt(tx_origin), - to_nt(is_delegate_call), to_nt(is_static_call), to_nt(reference_block_num), + to_nt(msg_sender), to_nt(storage_contract_address), to_nt(tx_origin), to_nt(is_delegate_call), + to_nt(is_static_call), to_nt(is_contract_deployment), to_nt(reference_block_num), }; return call_context; @@ -69,9 +71,8 @@ template struct CallContext { fr hash() const { std::vector inputs = { - msg_sender.to_field(), storage_contract_address.to_field(), - tx_origin.to_field(), fr(is_delegate_call), - fr(is_static_call), reference_block_num, + msg_sender.to_field(), storage_contract_address.to_field(), tx_origin.to_field(), fr(is_delegate_call), + fr(is_static_call), fr(is_contract_deployment), reference_block_num, }; return NCT::compress(inputs, GeneratorIndex::CALL_CONTEXT); @@ -86,6 +87,7 @@ template struct CallContext { tx_origin.to_field().assert_is_zero(); fr(is_delegate_call).assert_is_zero(); fr(is_static_call).assert_is_zero(); + fr(is_contract_deployment).assert_is_zero(); reference_block_num.assert_is_zero(); } @@ -98,6 +100,7 @@ template struct CallContext { tx_origin.to_field().set_public(); fr(is_delegate_call).set_public(); fr(is_static_call).set_public(); + fr(is_contract_deployment).set_public(); reference_block_num.set_public(); } }; @@ -111,6 +114,7 @@ template void read(uint8_t const*& it, CallContext& call_con read(it, call_context.tx_origin); read(it, call_context.is_delegate_call); read(it, call_context.is_static_call); + read(it, call_context.is_contract_deployment); read(it, call_context.reference_block_num); }; @@ -123,6 +127,7 @@ template void write(std::vector& buf, CallContext c write(buf, call_context.tx_origin); write(buf, call_context.is_delegate_call); write(buf, call_context.is_static_call); + write(buf, call_context.is_contract_deployment); write(buf, call_context.reference_block_num); }; @@ -133,6 +138,7 @@ template std::ostream& operator<<(std::ostream& os, CallContext -#include "../../constants.hpp" -#include -#include -#include -#include -#include - -namespace aztec3::circuits::abis { - -using plonk::stdlib::witness_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; - -template class ContractDeploymentCallPublicInputs { - typedef typename NCT::fr fr; - - public: - fr private_constructor_public_inputs_hash; - fr public_constructor_public_inputs_hash; - - fr private_constructor_vk_hash; - fr public_constructor_vk_hash; - - fr contract_address; - fr salt; - fr vk_root; - - fr circuit_data_hash; // TODO: no uint256 circuit type? - - fr portal_contract_address; // TODO: no uint160 circuit type? - - bool operator==(ContractDeploymentCallPublicInputs const&) const = default; - - static ContractDeploymentCallPublicInputs empty() { return { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; }; - - template - ContractDeploymentCallPublicInputs> to_circuit_type(Composer& composer) const - { - static_assert((std::is_same::value)); - - // Capture the composer: - auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; - - ContractDeploymentCallPublicInputs> pis = { - to_ct(private_constructor_public_inputs_hash), - to_ct(public_constructor_public_inputs_hash), - to_ct(private_constructor_vk_hash), - to_ct(public_constructor_vk_hash), - to_ct(contract_address), - to_ct(salt), - to_ct(vk_root), - to_ct(circuit_data_hash), - to_ct(portal_contract_address), - }; - - return pis; - }; -}; - -template -void read(uint8_t const*& it, ContractDeploymentCallPublicInputs& contract_deployment_call_public_inputs) -{ - using serialize::read; - - ContractDeploymentCallPublicInputs& pis = contract_deployment_call_public_inputs; - read(it, pis.private_constructor_public_inputs_hash); - read(it, pis.public_constructor_public_inputs_hash); - read(it, pis.private_constructor_vk_hash); - read(it, pis.public_constructor_vk_hash); - read(it, pis.contract_address); - read(it, pis.salt); - read(it, pis.vk_root); - read(it, pis.circuit_data_hash); - read(it, pis.portal_contract_address); -}; - -template -void write(std::vector& buf, - ContractDeploymentCallPublicInputs const& contract_deployment_call_public_inputs) -{ - using serialize::write; - - ContractDeploymentCallPublicInputs const& pis = contract_deployment_call_public_inputs; - - write(buf, pis.private_constructor_public_inputs_hash); - write(buf, pis.public_constructor_public_inputs_hash); - write(buf, pis.private_constructor_vk_hash); - write(buf, pis.public_constructor_vk_hash); - write(buf, pis.contract_address); - write(buf, pis.salt); - write(buf, pis.vk_root); - write(buf, pis.circuit_data_hash); - write(buf, pis.portal_contract_address); -}; - -template -std::ostream& operator<<(std::ostream& os, - ContractDeploymentCallPublicInputs const& contract_deployment_call_public_inputs) - -{ - ContractDeploymentCallPublicInputs const& pis = contract_deployment_call_public_inputs; - return os << "private_constructor_public_inputs_hash: " << pis.private_constructor_public_inputs_hash << "\n" - << "public_constructor_public_inputs_hash: " << pis.public_constructor_public_inputs_hash << "\n" - << "private_constructor_vk_hash: " << pis.private_constructor_vk_hash << "\n" - << "public_constructor_vk_hash: " << pis.public_constructor_vk_hash << "\n" - << "contract_address: " << pis.contract_address << "\n" - << "salt: " << pis.salt << "\n" - << "vk_root: " << pis.vk_root << "\n" - << "circuit_data_hash: " << pis.circuit_data_hash << "\n" - << "portal_contract_address: " << pis.portal_contract_address << "\n"; -} - -} // namespace aztec3::circuits::abis \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/abis/contract_deployment_data.hpp b/circuits/src/aztec3/circuits/abis/contract_deployment_data.hpp new file mode 100644 index 00000000000..990bbac885b --- /dev/null +++ b/circuits/src/aztec3/circuits/abis/contract_deployment_data.hpp @@ -0,0 +1,122 @@ +#pragma once +#include +#include +#include +#include +#include +#include + +namespace aztec3::circuits::abis { + +using plonk::stdlib::witness_t; +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; +using std::is_same; + +template struct ContractDeploymentData { + typedef typename NCT::boolean boolean; + typedef typename NCT::fr fr; + + fr contract_data_hash; + fr function_tree_root; + fr constructor_hash; + fr contract_address_salt; + fr portal_contract_address; // TODO: no uint160 circuit type? + + bool operator==(ContractDeploymentData const&) const = default; + + static ContractDeploymentData empty() { return { 0, 0, 0, 0, 0 }; }; + + template + ContractDeploymentData> to_circuit_type(Composer& composer) const + { + static_assert((std::is_same::value)); + + // Capture the composer: + auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + + ContractDeploymentData> data = { + to_ct(contract_data_hash), to_ct(function_tree_root), to_ct(constructor_hash), + to_ct(contract_address_salt), to_ct(portal_contract_address), + }; + + return data; + }; + + template ContractDeploymentData to_native_type() const + { + static_assert(std::is_same, NCT>::value); + auto to_nt = [&](auto& e) { return plonk::stdlib::types::to_nt(e); }; + + ContractDeploymentData call_context = { + to_nt(contract_data_hash), to_nt(function_tree_root), to_nt(constructor_hash), + to_nt(contract_address_salt), to_nt(portal_contract_address), + }; + + return call_context; + }; + + template void assert_is_zero() + { + static_assert((std::is_same, NCT>::value)); + + contract_data_hash.assert_is_zero(); + function_tree_root.assert_is_zero(); + constructor_hash.assert_is_zero(); + contract_address_salt.assert_is_zero(); + portal_contract_address.assert_is_zero(); + } + + void set_public() + { + static_assert(!(std::is_same::value)); + + contract_data_hash.set_public(); + function_tree_root.set_public(); + constructor_hash.set_public(); + contract_address_salt.set_public(); + portal_contract_address.set_public(); + } + + fr hash() const + { + std::vector inputs = { + contract_data_hash, function_tree_root, constructor_hash, contract_address_salt, portal_contract_address, + }; + + return NCT::compress(inputs, GeneratorIndex::FUNCTION_SIGNATURE); + } +}; + +template void read(uint8_t const*& it, ContractDeploymentData& data) +{ + using serialize::read; + + read(it, data.contract_data_hash); + read(it, data.function_tree_root); + read(it, data.constructor_hash); + read(it, data.contract_address_salt); + read(it, data.portal_contract_address); +}; + +template void write(std::vector& buf, ContractDeploymentData const& data) +{ + using serialize::write; + + write(buf, data.contract_data_hash); + write(buf, data.function_tree_root); + write(buf, data.constructor_hash); + write(buf, data.contract_address_salt); + write(buf, data.portal_contract_address); +}; + +template std::ostream& operator<<(std::ostream& os, ContractDeploymentData const& data) +{ + return os << "contract_data_hash: " << data.contract_data_hash << "\n" + << "function_tree_root: " << data.function_tree_root << "\n" + << "constructor_hash: " << data.constructor_hash << "\n" + << "contract_address_salt: " << data.contract_address_salt << "\n" + << "portal_contract_address: " << data.portal_contract_address << "\n"; +} + +} // namespace aztec3::circuits::abis \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/abis/index.hpp b/circuits/src/aztec3/circuits/abis/index.hpp index 8ffe84571a4..7d845630ff7 100644 --- a/circuits/src/aztec3/circuits/abis/index.hpp +++ b/circuits/src/aztec3/circuits/abis/index.hpp @@ -1,6 +1,5 @@ #include "call_context.hpp" #include "call_stack_item.hpp" -#include "contract_deployment_call_public_inputs.hpp" #include "function_signature.hpp" #include "private_circuit_public_inputs.hpp" #include "private_circuit_public_inputs.hpp" diff --git a/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp b/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp index 611ea2640b2..45e0a4cf7eb 100644 --- a/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp +++ b/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp @@ -1,6 +1,7 @@ #pragma once #include "call_context.hpp" +#include "contract_deployment_data.hpp" #include "../../constants.hpp" #include @@ -34,13 +35,14 @@ template class PrivateCircuitPublicInputs { std::array private_call_stack; std::array public_call_stack; - std::array contract_deployment_call_stack; - std::array partial_l1_call_stack; + std::array l1_msg_stack; fr old_private_data_tree_root; fr old_nullifier_tree_root; fr old_contract_tree_root; + ContractDeploymentData contract_deployment_data; + template PrivateCircuitPublicInputs> to_circuit_type(Composer& composer) const { @@ -63,12 +65,13 @@ template class PrivateCircuitPublicInputs { to_ct(private_call_stack), to_ct(public_call_stack), - to_ct(contract_deployment_call_stack), - to_ct(partial_l1_call_stack), + to_ct(l1_msg_stack), to_ct(old_private_data_tree_root), to_ct(old_nullifier_tree_root), to_ct(old_contract_tree_root), + + to_circuit_type(contract_deployment_data), }; return pis; @@ -92,13 +95,14 @@ template class PrivateCircuitPublicInputs { spread_arr_into_vec(private_call_stack, inputs); spread_arr_into_vec(public_call_stack, inputs); - spread_arr_into_vec(contract_deployment_call_stack, inputs); - spread_arr_into_vec(partial_l1_call_stack, inputs); + spread_arr_into_vec(l1_msg_stack, inputs); inputs.push_back(old_private_data_tree_root); inputs.push_back(old_nullifier_tree_root); inputs.push_back(old_contract_tree_root); + inputs.push_back(contract_deployment_data.hash()); + return NCT::compress(inputs, GeneratorIndex::PRIVATE_CIRCUIT_PUBLIC_INPUTS); } @@ -132,34 +136,35 @@ template class OptionalPrivateCircuitPublicInputs { std::array private_call_stack; std::array public_call_stack; - std::array contract_deployment_call_stack; - std::array partial_l1_call_stack; + std::array l1_msg_stack; opt_fr old_private_data_tree_root; opt_fr old_nullifier_tree_root; opt_fr old_contract_tree_root; + std::optional> contract_deployment_data; + OptionalPrivateCircuitPublicInputs(){}; - OptionalPrivateCircuitPublicInputs( - std::optional> const& call_context, + OptionalPrivateCircuitPublicInputs(std::optional> const& call_context, - std::array const& args, - std::array const& return_values, + std::array const& args, + std::array const& return_values, - std::array const& emitted_events, + std::array const& emitted_events, - std::array const& output_commitments, - std::array const& input_nullifiers, + std::array const& output_commitments, + std::array const& input_nullifiers, - std::array const& private_call_stack, - std::array const& public_call_stack, - std::array const& contract_deployment_call_stack, - std::array const& partial_l1_call_stack, + std::array const& private_call_stack, + std::array const& public_call_stack, + std::array const& l1_msg_stack, - opt_fr const& old_private_data_tree_root, - opt_fr const& old_nullifier_tree_root, - opt_fr const& old_contract_tree_root) + opt_fr const& old_private_data_tree_root, + opt_fr const& old_nullifier_tree_root, + opt_fr const& old_contract_tree_root, + + std::optional> const& contract_deployment_data) : call_context(call_context) , args(args) , return_values(return_values) @@ -168,11 +173,11 @@ template class OptionalPrivateCircuitPublicInputs { , input_nullifiers(input_nullifiers) , private_call_stack(private_call_stack) , public_call_stack(public_call_stack) - , contract_deployment_call_stack(contract_deployment_call_stack) - , partial_l1_call_stack(partial_l1_call_stack) + , l1_msg_stack(l1_msg_stack) , old_private_data_tree_root(old_private_data_tree_root) , old_nullifier_tree_root(old_nullifier_tree_root) - , old_contract_tree_root(old_contract_tree_root){}; + , old_contract_tree_root(old_contract_tree_root) + , contract_deployment_data(contract_deployment_data){}; bool operator==(OptionalPrivateCircuitPublicInputs const&) const = default; @@ -193,13 +198,14 @@ template class OptionalPrivateCircuitPublicInputs { new_inputs.private_call_stack.fill(std::nullopt); new_inputs.public_call_stack.fill(std::nullopt); - new_inputs.contract_deployment_call_stack.fill(std::nullopt); - new_inputs.partial_l1_call_stack.fill(std::nullopt); + new_inputs.l1_msg_stack.fill(std::nullopt); new_inputs.old_private_data_tree_root = std::nullopt; new_inputs.old_nullifier_tree_root = std::nullopt; new_inputs.old_contract_tree_root = std::nullopt; + new_inputs.contract_deployment_data = std::nullopt; + return new_inputs; }; @@ -239,13 +245,14 @@ template class OptionalPrivateCircuitPublicInputs { make_unused_array_elements_zero(composer, private_call_stack); make_unused_array_elements_zero(composer, public_call_stack); - make_unused_array_elements_zero(composer, contract_deployment_call_stack); - make_unused_array_elements_zero(composer, partial_l1_call_stack); + make_unused_array_elements_zero(composer, l1_msg_stack); make_unused_element_zero(composer, old_private_data_tree_root); make_unused_element_zero(composer, old_nullifier_tree_root); make_unused_element_zero(composer, old_contract_tree_root); + make_unused_element_zero(composer, contract_deployment_data); + all_elements_populated = true; } @@ -269,12 +276,13 @@ template class OptionalPrivateCircuitPublicInputs { set_array_public(private_call_stack); set_array_public(public_call_stack); - set_array_public(contract_deployment_call_stack); - set_array_public(partial_l1_call_stack); + set_array_public(l1_msg_stack); (*old_private_data_tree_root).set_public(); (*old_nullifier_tree_root).set_public(); (*old_contract_tree_root).set_public(); + + (*contract_deployment_data).set_public(); } template @@ -301,12 +309,13 @@ template class OptionalPrivateCircuitPublicInputs { to_ct(private_call_stack), to_ct(public_call_stack), - to_ct(contract_deployment_call_stack), - to_ct(partial_l1_call_stack), + to_ct(l1_msg_stack), to_ct(old_private_data_tree_root), to_ct(old_nullifier_tree_root), to_ct(old_contract_tree_root), + + to_circuit_type(contract_deployment_data), }; return pis; @@ -334,12 +343,13 @@ template class OptionalPrivateCircuitPublicInputs { to_nt(private_call_stack), to_nt(public_call_stack), - to_nt(contract_deployment_call_stack), - to_nt(partial_l1_call_stack), + to_nt(l1_msg_stack), to_nt(old_private_data_tree_root), to_nt(old_nullifier_tree_root), to_nt(old_contract_tree_root), + + to_native_type(contract_deployment_data), }; return pis; @@ -368,13 +378,14 @@ template class OptionalPrivateCircuitPublicInputs { spread_arr_opt_into_vec(private_call_stack, inputs); spread_arr_opt_into_vec(public_call_stack, inputs); - spread_arr_opt_into_vec(contract_deployment_call_stack, inputs); - spread_arr_opt_into_vec(partial_l1_call_stack, inputs); + spread_arr_opt_into_vec(l1_msg_stack, inputs); inputs.push_back(*old_private_data_tree_root); inputs.push_back(*old_nullifier_tree_root); inputs.push_back(*old_contract_tree_root); + inputs.push_back((*contract_deployment_data).hash()); + return NCT::compress(inputs, GeneratorIndex::PRIVATE_CIRCUIT_PUBLIC_INPUTS); } @@ -396,12 +407,13 @@ template class OptionalPrivateCircuitPublicInputs { .private_call_stack = map(private_call_stack, get_value), .public_call_stack = map(public_call_stack, get_value), - .contract_deployment_call_stack = map(contract_deployment_call_stack, get_value), - .partial_l1_call_stack = map(partial_l1_call_stack, get_value), + .l1_msg_stack = map(l1_msg_stack, get_value), .old_private_data_tree_root = old_private_data_tree_root.value(), .old_nullifier_tree_root = old_nullifier_tree_root.value(), .old_contract_tree_root = old_contract_tree_root.value(), + + .contract_deployment_data = contract_deployment_data.value(), }; } @@ -487,11 +499,12 @@ void read(uint8_t const*& it, OptionalPrivateCircuitPublicInputs& private_c read(it, pis.input_nullifiers); read(it, pis.private_call_stack); read(it, pis.public_call_stack); - read(it, pis.contract_deployment_call_stack); - read(it, pis.partial_l1_call_stack); + read(it, pis.l1_msg_stack); read(it, pis.old_private_data_tree_root); read(it, pis.old_nullifier_tree_root); read(it, pis.old_contract_tree_root); + + read(it, pis.contract_deployment_data); }; template @@ -509,11 +522,12 @@ void write(std::vector& buf, OptionalPrivateCircuitPublicInputs co write(buf, pis.input_nullifiers); write(buf, pis.private_call_stack); write(buf, pis.public_call_stack); - write(buf, pis.contract_deployment_call_stack); - write(buf, pis.partial_l1_call_stack); + write(buf, pis.l1_msg_stack); write(buf, pis.old_private_data_tree_root); write(buf, pis.old_nullifier_tree_root); write(buf, pis.old_contract_tree_root); + + write(buf, pis.contract_deployment_data); }; template @@ -529,11 +543,11 @@ std::ostream& operator<<(std::ostream& os, OptionalPrivateCircuitPublicInputs struct CallContextReconciliationData { // std::array contract_deployment_call_stack; - std::array, PARTIAL_L1_CALL_STACK_LENGTH> l1_call_contexts; - std::array l1_counterparts; // TODO: this is probably wrong. + std::array, L1_MSG_STACK_LENGTH> l1_call_contexts; + std::array l1_counterparts; // TODO: this is probably wrong. template CallContextReconciliationData> to_circuit_type(Composer& composer) const diff --git a/circuits/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp b/circuits/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp index 3ca59f2a181..8205b2714cd 100644 --- a/circuits/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp +++ b/circuits/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp @@ -32,8 +32,7 @@ template struct PublicCircuitPublicInputs { std::array, STATE_READS_LENGTH> state_reads; std::array public_call_stack; - std::array contract_deployment_call_stack; - std::array partial_l1_call_stack; + std::array l1_msg_stack; fr old_private_data_tree_root; @@ -55,7 +54,7 @@ template struct PublicCircuitPublicInputs { // std::array::fill(0), // std::array::fill(0), - // std::array::fill(0), + // std::array::fill(0), // .old_private_data_tree_root = 0, @@ -86,8 +85,7 @@ template struct PublicCircuitPublicInputs { .state_reads = map(state_reads, to_circuit_type), .public_call_stack = to_ct(public_call_stack), - .contract_deployment_call_stack = to_ct(contract_deployment_call_stack), - .partial_l1_call_stack = to_ct(partial_l1_call_stack), + .l1_msg_stack = to_ct(l1_msg_stack), .old_private_data_tree_root = to_ct(old_private_data_tree_root), @@ -116,8 +114,7 @@ template struct PublicCircuitPublicInputs { spread_arr_into_vec(map(state_reads, to_hashes), inputs); spread_arr_into_vec(public_call_stack, inputs); - spread_arr_into_vec(contract_deployment_call_stack, inputs); - spread_arr_into_vec(partial_l1_call_stack, inputs); + spread_arr_into_vec(l1_msg_stack, inputs); inputs.push_back(old_private_data_tree_root); @@ -145,8 +142,7 @@ template void read(uint8_t const*& it, PublicCircuitPublicInputs< read(it, pis.state_reads); read(it, pis.public_call_stack); - read(it, pis.contract_deployment_call_stack); - read(it, pis.partial_l1_call_stack); + read(it, pis.l1_msg_stack); read(it, pis.old_private_data_tree_root); @@ -169,8 +165,7 @@ void write(std::vector& buf, PublicCircuitPublicInputs const& priv write(buf, pis.state_reads); write(buf, pis.public_call_stack); - write(buf, pis.contract_deployment_call_stack); - write(buf, pis.partial_l1_call_stack); + write(buf, pis.l1_msg_stack); write(buf, pis.old_private_data_tree_root); @@ -190,8 +185,7 @@ std::ostream& operator<<(std::ostream& os, PublicCircuitPublicInputs const& << "state_reads: " << pis.state_reads << "\n" << "public_call_stack: " << pis.public_call_stack << "\n" - << "contract_deployment_call_stack: " << pis.contract_deployment_call_stack << "\n" - << "partial_l1_call_stack: " << pis.partial_l1_call_stack << "\n" + << "l1_msg_stack: " << pis.l1_msg_stack << "\n" << "old_private_data_tree_root: " << pis.old_private_data_tree_root << "\n" diff --git a/circuits/src/aztec3/circuits/abis/tx_context.hpp b/circuits/src/aztec3/circuits/abis/tx_context.hpp index aad6ae396d6..6a65bbd9206 100644 --- a/circuits/src/aztec3/circuits/abis/tx_context.hpp +++ b/circuits/src/aztec3/circuits/abis/tx_context.hpp @@ -1,4 +1,5 @@ #pragma once +#include "contract_deployment_data.hpp" #include "function_signature.hpp" #include #include @@ -19,10 +20,12 @@ template struct TxContext { typedef typename NCT::fr fr; typedef typename NCT::boolean boolean; - boolean called_from_l1; - boolean called_from_public_l2; - boolean is_fee_payment_tx; - // FeeData fee_data; + boolean is_fee_payment_tx = false; + boolean is_rebate_payment_tx = false; + boolean is_contract_deployment_tx = false; + + ContractDeploymentData contract_deployment_data; + fr reference_block_num; template TxContext> to_circuit_type(Composer& composer) const @@ -34,9 +37,8 @@ template struct TxContext { // auto to_circuit_type = [&](auto& e) { return e.to_circuit_type(composer); }; TxContext> tx_context = { - to_ct(called_from_l1), - to_ct(called_from_public_l2), - to_ct(is_fee_payment_tx), + to_ct(is_fee_payment_tx), to_ct(is_rebate_payment_tx), + to_ct(is_contract_deployment_tx), contract_deployment_data.to_circuit_type(composer), to_ct(reference_block_num), }; @@ -47,9 +49,10 @@ template struct TxContext { { static_assert(!(std::is_same::value)); - fr(called_from_l1).set_public(); - fr(called_from_public_l2).set_public(); fr(is_fee_payment_tx).set_public(); + fr(is_rebate_payment_tx).set_public(); + fr(is_contract_deployment_tx).set_public(); + contract_deployment_data.set_public(); reference_block_num.set_public(); } }; @@ -58,9 +61,10 @@ template void read(uint8_t const*& it, TxContext& tx_context { using serialize::read; - read(it, tx_context.called_from_l1); - read(it, tx_context.called_from_public_l2); read(it, tx_context.is_fee_payment_tx); + read(it, tx_context.is_rebate_payment_tx); + read(it, tx_context.is_contract_deployment_tx); + read(it, tx_context.contract_deployment_data); read(it, tx_context.reference_block_num); }; @@ -68,17 +72,19 @@ template void write(std::vector& buf, TxContext con { using serialize::write; - write(buf, tx_context.called_from_l1); - write(buf, tx_context.called_from_public_l2); write(buf, tx_context.is_fee_payment_tx); + write(buf, tx_context.is_rebate_payment_tx); + write(buf, tx_context.is_contract_deployment_tx); + write(buf, tx_context.contract_deployment_data); write(buf, tx_context.reference_block_num); }; template std::ostream& operator<<(std::ostream& os, TxContext const& tx_context) { - return os << "called_from_l1: " << tx_context.called_from_l1 << "\n" - << "called_from_public_l2: " << tx_context.called_from_public_l2 << "\n" - << "is_fee_payment_tx: " << tx_context.is_fee_payment_tx << "\n" + return os << "is_fee_payment_tx: " << tx_context.is_fee_payment_tx << "\n" + << "is_rebate_payment_tx: " << tx_context.is_rebate_payment_tx << "\n" + << "is_contract_deployment_tx: " << tx_context.is_contract_deployment_tx << "\n" + << "contract_deployment_data: " << tx_context.contract_deployment_data << "\n" << "reference_block_num: " << tx_context.reference_block_num << "\n"; } diff --git a/circuits/src/aztec3/circuits/kernel/private/.test.cpp b/circuits/src/aztec3/circuits/kernel/private/.test.cpp index c4af8b8da35..8e26007c0c9 100644 --- a/circuits/src/aztec3/circuits/kernel/private/.test.cpp +++ b/circuits/src/aztec3/circuits/kernel/private/.test.cpp @@ -7,13 +7,14 @@ #include -#include -#include #include -#include +#include +#include +#include #include +#include #include -#include +#include #include #include #include @@ -39,6 +40,7 @@ namespace { using aztec3::circuits::abis::CallContext; using aztec3::circuits::abis::CallStackItem; using aztec3::circuits::abis::CallType; +using aztec3::circuits::abis::ContractDeploymentData; using aztec3::circuits::abis::FunctionSignature; using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; using aztec3::circuits::abis::PrivateCircuitPublicInputs; @@ -121,9 +123,10 @@ TEST(private_kernel_tests, test_deposit) .nonce = 0, .tx_context = TxContext{ - .called_from_l1 = false, - .called_from_public_l2 = false, .is_fee_payment_tx = false, + .is_rebate_payment_tx = false, + .is_contract_deployment_tx = false, + .contract_deployment_data = ContractDeploymentData{}, .reference_block_num = 0, }, .chain_id = 1, diff --git a/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp b/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp index 1d4f8abc732..7a87dbf4053 100644 --- a/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp +++ b/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp @@ -191,15 +191,14 @@ void update_end_values(PrivateInputs const& private_inputs, PublicInputs const auto& portal_contract_address = private_inputs.private_call.portal_contract_address; { - const auto& partial_l1_call_stack = private_call_public_inputs.partial_l1_call_stack; - std::array l1_call_stack; - - for (size_t i = 0; i < partial_l1_call_stack.size(); ++i) { - l1_call_stack[i] = - CT::fr::conditional_assign(partial_l1_call_stack[i] == 0, - 0, - CT::compress({ portal_contract_address, partial_l1_call_stack[i] }, - GeneratorIndex::L1_CALL_STACK_ITEM)); + const auto& l1_msg_stack = private_call_public_inputs.l1_msg_stack; + std::array l1_call_stack; + + for (size_t i = 0; i < l1_msg_stack.size(); ++i) { + l1_call_stack[i] = CT::fr::conditional_assign( + l1_msg_stack[i] == 0, + 0, + CT::compress({ portal_contract_address, l1_msg_stack[i] }, GeneratorIndex::L1_CALL_STACK_ITEM)); } } } diff --git a/circuits/src/aztec3/constants.hpp b/circuits/src/aztec3/constants.hpp index 664e51ef5d5..42c3e402da1 100644 --- a/circuits/src/aztec3/constants.hpp +++ b/circuits/src/aztec3/constants.hpp @@ -16,7 +16,7 @@ constexpr size_t STATE_READS_LENGTH = 4; constexpr size_t PRIVATE_CALL_STACK_LENGTH = 4; constexpr size_t PUBLIC_CALL_STACK_LENGTH = 4; constexpr size_t CONTRACT_DEPLOYMENT_CALL_STACK_LENGTH = 2; -constexpr size_t PARTIAL_L1_CALL_STACK_LENGTH = 2; +constexpr size_t L1_MSG_STACK_LENGTH = 2; constexpr size_t KERNEL_OUTPUT_COMMITMENTS_LENGTH = 16; constexpr size_t KERNEL_INPUT_NULLIFIERS_LENGTH = 16; From 153ef604c5a1c3df5880eee470f06dbfdcff5098 Mon Sep 17 00:00:00 2001 From: iAmMichaelConnor Date: Wed, 11 Jan 2023 21:26:06 +0000 Subject: [PATCH 028/166] support for external private function calls --- .../abis/private_circuit_public_inputs.hpp | 97 +++++++++++- .../abis/private_kernel/accumulated_data.hpp | 9 +- .../call_context_reconciliation_data.hpp | 82 +++++----- .../abis/private_kernel/private_call_data.hpp | 4 +- .../apps/function_execution_context.hpp | 72 +++++++++ .../.test.cpp | 6 +- .../function_1_1.cpp | 64 ++++---- .../function_1_1.hpp | 8 +- .../function_2_1.cpp | 21 +-- .../function_2_1.hpp | 5 +- .../kernel/private/private_kernel_circuit.cpp | 128 ++++------------ circuits/src/aztec3/circuits/types/array.hpp | 140 ++++++++++++++++++ 12 files changed, 422 insertions(+), 214 deletions(-) create mode 100644 circuits/src/aztec3/circuits/types/array.hpp diff --git a/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp b/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp index 45e0a4cf7eb..0db607150c2 100644 --- a/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp +++ b/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp @@ -2,7 +2,7 @@ #include "call_context.hpp" #include "contract_deployment_data.hpp" -#include "../../constants.hpp" +#include #include #include @@ -77,6 +77,37 @@ template class PrivateCircuitPublicInputs { return pis; }; + template PrivateCircuitPublicInputs to_native_type() const + { + static_assert(std::is_same, NCT>::value); + auto to_nt = [&](auto& e) { return plonk::stdlib::types::to_nt(e); }; + auto to_native_type = [](T& e) { return e.template to_native_type(); }; + + PrivateCircuitPublicInputs pis = { + to_native_type(call_context), + + to_nt(args), + to_nt(return_values), + + to_nt(emitted_events), + + to_nt(output_commitments), + to_nt(input_nullifiers), + + to_nt(private_call_stack), + to_nt(public_call_stack), + to_nt(l1_msg_stack), + + to_nt(old_private_data_tree_root), + to_nt(old_nullifier_tree_root), + to_nt(old_contract_tree_root), + + to_native_type(contract_deployment_data), + }; + + return pis; + }; + fr hash() const { // auto to_hashes = [](const T& e) { return e.hash(); }; @@ -113,6 +144,70 @@ template class PrivateCircuitPublicInputs { } }; +template void read(uint8_t const*& it, PrivateCircuitPublicInputs& private_circuit_public_inputs) +{ + using serialize::read; + + PrivateCircuitPublicInputs& pis = private_circuit_public_inputs; + read(it, pis.call_context); + read(it, pis.args); + read(it, pis.return_values); + read(it, pis.emitted_events); + read(it, pis.output_commitments); + read(it, pis.input_nullifiers); + read(it, pis.private_call_stack); + read(it, pis.public_call_stack); + read(it, pis.l1_msg_stack); + read(it, pis.old_private_data_tree_root); + read(it, pis.old_nullifier_tree_root); + read(it, pis.old_contract_tree_root); + + read(it, pis.contract_deployment_data); +}; + +template +void write(std::vector& buf, PrivateCircuitPublicInputs const& private_circuit_public_inputs) +{ + using serialize::write; + + PrivateCircuitPublicInputs const& pis = private_circuit_public_inputs; + + write(buf, pis.call_context); + write(buf, pis.args); + write(buf, pis.return_values); + write(buf, pis.emitted_events); + write(buf, pis.output_commitments); + write(buf, pis.input_nullifiers); + write(buf, pis.private_call_stack); + write(buf, pis.public_call_stack); + write(buf, pis.l1_msg_stack); + write(buf, pis.old_private_data_tree_root); + write(buf, pis.old_nullifier_tree_root); + write(buf, pis.old_contract_tree_root); + + write(buf, pis.contract_deployment_data); +}; + +template +std::ostream& operator<<(std::ostream& os, PrivateCircuitPublicInputs const& private_circuit_public_inputs) + +{ + PrivateCircuitPublicInputs const& pis = private_circuit_public_inputs; + return os << "call_context: " << pis.call_context << "\n" + << "args: " << pis.args << "\n" + << "return_values: " << pis.return_values << "\n" + << "emitted_events: " << pis.emitted_events << "\n" + << "output_commitments: " << pis.output_commitments << "\n" + << "input_nullifiers: " << pis.input_nullifiers << "\n" + << "private_call_stack: " << pis.private_call_stack << "\n" + << "public_call_stack: " << pis.public_call_stack << "\n" + << "l1_msg_stack: " << pis.l1_msg_stack << "\n" + << "old_private_data_tree_root: " << pis.old_private_data_tree_root << "\n" + << "old_nullifier_tree_root: " << pis.old_nullifier_tree_root << "\n" + << "old_nullifier_tree_root: " << pis.old_nullifier_tree_root << "\n" + << "contract_deployment_data: " << pis.contract_deployment_data << "\n"; +} + // It's been extremely useful for all members here to be std::optional. It allows test app circuits to be very // quickly drafted without worrying about any of the public inputs which aren't relevant to that circuit. Any values // which aren't set by the circuit can then be safely set to zero when calling `set_public` (by checking for diff --git a/circuits/src/aztec3/circuits/abis/private_kernel/accumulated_data.hpp b/circuits/src/aztec3/circuits/abis/private_kernel/accumulated_data.hpp index 1ad6414ffe8..593da76bf58 100644 --- a/circuits/src/aztec3/circuits/abis/private_kernel/accumulated_data.hpp +++ b/circuits/src/aztec3/circuits/abis/private_kernel/accumulated_data.hpp @@ -26,8 +26,7 @@ template struct AccumulatedData { std::array private_call_stack; std::array public_call_stack; - std::array contract_deployment_call_stack; - std::array l1_call_stack; + std::array l1_msg_stack; std::array, KERNEL_OPTIONALLY_REVEALED_DATA_LENGTH> optionally_revealed_data; @@ -56,8 +55,7 @@ template struct AccumulatedData { to_ct(private_call_stack), to_ct(public_call_stack), - to_ct(contract_deployment_call_stack), - to_ct(l1_call_stack), + to_ct(l1_msg_stack), map(optionally_revealed_data, to_circuit_type), }; @@ -78,8 +76,7 @@ template struct AccumulatedData { set_array_public(private_call_stack); set_array_public(public_call_stack); - set_array_public(contract_deployment_call_stack); - set_array_public(l1_call_stack); + set_array_public(l1_msg_stack); set_array_public(optionally_revealed_data); } diff --git a/circuits/src/aztec3/circuits/abis/private_kernel/call_context_reconciliation_data.hpp b/circuits/src/aztec3/circuits/abis/private_kernel/call_context_reconciliation_data.hpp index 62f1c566522..154fc4f62fa 100644 --- a/circuits/src/aztec3/circuits/abis/private_kernel/call_context_reconciliation_data.hpp +++ b/circuits/src/aztec3/circuits/abis/private_kernel/call_context_reconciliation_data.hpp @@ -1,58 +1,58 @@ -#pragma once +// #pragma once -#include "../call_context.hpp" +// #include "../call_context.hpp" -#include -#include -#include -#include -#include +// #include +// #include +// #include +// #include +// #include -namespace aztec3::circuits::abis::private_kernel { +// namespace aztec3::circuits::abis::private_kernel { -using plonk::stdlib::witness_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; -using std::is_same; +// using plonk::stdlib::witness_t; +// using plonk::stdlib::types::CircuitTypes; +// using plonk::stdlib::types::NativeTypes; +// using std::is_same; -template struct CallContextReconciliationData { - typedef typename NCT::fr fr; +// template struct CallContextReconciliationData { +// typedef typename NCT::fr fr; - /** - * This class needs an explanation... - * - */ - std::array, PRIVATE_CALL_STACK_LENGTH> private_call_contexts; - std::array private_counterparts; +// /** +// * This class needs an explanation... +// * +// */ +// std::array, PRIVATE_CALL_STACK_LENGTH> private_call_contexts; +// std::array private_counterparts; - std::array, PUBLIC_CALL_STACK_LENGTH> public_call_contexts; - std::array public_counterparts; +// std::array, PUBLIC_CALL_STACK_LENGTH> public_call_contexts; +// std::array public_counterparts; - // std::array contract_deployment_call_stack; +// // std::array contract_deployment_call_stack; - std::array, L1_MSG_STACK_LENGTH> l1_call_contexts; - std::array l1_counterparts; // TODO: this is probably wrong. +// std::array, L1_MSG_STACK_LENGTH> l1_call_contexts; +// std::array l1_counterparts; // TODO: this is probably wrong. - template - CallContextReconciliationData> to_circuit_type(Composer& composer) const - { - static_assert((std::is_same::value)); +// template +// CallContextReconciliationData> to_circuit_type(Composer& composer) const +// { +// static_assert((std::is_same::value)); - // Capture the composer: - auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; - auto to_circuit_type = [&](auto& e) { return e.to_circuit_type(composer); }; +// // Capture the composer: +// auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; +// auto to_circuit_type = [&](auto& e) { return e.to_circuit_type(composer); }; - CallContextReconciliationData> data = { +// CallContextReconciliationData> data = { - map(private_call_contexts, to_circuit_type), to_ct(private_counterparts), +// map(private_call_contexts, to_circuit_type), to_ct(private_counterparts), - map(public_call_contexts, to_circuit_type), to_ct(public_counterparts), +// map(public_call_contexts, to_circuit_type), to_ct(public_counterparts), - map(l1_call_contexts, to_circuit_type), to_ct(l1_counterparts), - }; +// map(l1_call_contexts, to_circuit_type), to_ct(l1_counterparts), +// }; - return data; - }; -}; +// return data; +// }; +// }; -} // namespace aztec3::circuits::abis::private_kernel \ No newline at end of file +// } // namespace aztec3::circuits::abis::private_kernel \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/abis/private_kernel/private_call_data.hpp b/circuits/src/aztec3/circuits/abis/private_kernel/private_call_data.hpp index 443e9222d16..2683646b565 100644 --- a/circuits/src/aztec3/circuits/abis/private_kernel/private_call_data.hpp +++ b/circuits/src/aztec3/circuits/abis/private_kernel/private_call_data.hpp @@ -21,7 +21,7 @@ template struct PrivateCallData { typedef typename NCT::VK VK; CallStackItem call_stack_item; - CallContextReconciliationData call_context_reconciliation_data; + // CallContextReconciliationData call_context_reconciliation_data; NativeTypes::Proof proof; // TODO: how to express proof as native/circuit type when it gets used as a buffer? std::shared_ptr vk; @@ -44,7 +44,7 @@ template struct PrivateCallData { PrivateCallData> data = { call_stack_item.to_circuit_type(composer), - call_context_reconciliation_data.to_circuit_type(composer), + // call_context_reconciliation_data.to_circuit_type(composer), proof, // Notice: not converted! Stays as native. This is because of how the verify_proof function currently // works. diff --git a/circuits/src/aztec3/circuits/apps/function_execution_context.hpp b/circuits/src/aztec3/circuits/apps/function_execution_context.hpp index a0cbfca827b..b3aa99c5bc4 100644 --- a/circuits/src/aztec3/circuits/apps/function_execution_context.hpp +++ b/circuits/src/aztec3/circuits/apps/function_execution_context.hpp @@ -11,6 +11,8 @@ #include #include +#include + #include #include @@ -24,19 +26,24 @@ namespace aztec3::circuits::apps { using aztec3::circuits::abis::FunctionSignature; using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; +using aztec3::circuits::abis::PrivateCircuitPublicInputs; using aztec3::circuits::apps::notes::NoteInterface; using aztec3::circuits::apps::opcodes::Opcodes; +using aztec3::circuits::types::array_push; + using plonk::stdlib::witness_t; using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::to_nt; using NT = plonk::stdlib::types::NativeTypes; template class FunctionExecutionContext { typedef NativeTypes NT; typedef CircuitTypes CT; typedef typename CT::fr fr; + typedef typename CT::address address; // We restrict only the opcodes to be able to push to the private members of the exec_ctx. // This will just help us build better separation of concerns. @@ -48,9 +55,13 @@ template class FunctionExecutionContext { Contract* contract = nullptr; + std::map>> nested_execution_contexts; + // TODO: make this private! OptionalPrivateCircuitPublicInputs private_circuit_public_inputs; + PrivateCircuitPublicInputs final_private_circuit_public_inputs; + private: std::vector>> new_notes; std::vector new_commitments; @@ -86,6 +97,65 @@ template class FunctionExecutionContext { void push_newly_nullified_note(NoteInterface* note_ptr) { nullified_notes.push_back(note_ptr); } + // Allows a call to be made to a function of another contract + template + std::array call( + address const& external_contract_address, + std::string const& external_function_name, + std::function&, std::array)> f, + std::array const& args) + { + if (nested_execution_contexts.contains(external_function_name)) { + throw_or_abort("Choose a different string to represent the function being called"); + } + + Composer f_composer; + NativeOracle f_oracle(oracle.oracle.db, + external_contract_address.get_value(), + oracle.get_this_contract_address().get_value(), + oracle.get_tx_origin().get_value(), + oracle.get_msg_sender_private_key().get_value()); + OracleWrapperInterface f_oracle_wrapper(f_composer, f_oracle); + + // We need an exec_ctx reference which won't go out of scope, so we store a shared_ptr to the newly created + // exec_ctx in `this` exec_ctx, and pass a reference to the function we're calling: + auto& f_exec_ctx = nested_execution_contexts[external_function_name]; + + f_exec_ctx = std::make_shared>(f_composer, f_oracle_wrapper); + + auto native_args = to_nt(args); + + // This calls the function `f`, passing the arguments shown. + // The f_exec_ctx will be populated with all the information about that function's execution. + std::apply(f, std::forward_as_tuple(*f_exec_ctx, native_args)); + + // Remember: the data held in the f_exec_ctc was built with a different composer than that + // of `this` exec_ctx. So we only allow ourselves to get the native types, so that we can consciously declare + // circuit types for `this` exec_ctx using `this->composer`. + auto& f_public_inputs_nt = f_exec_ctx->final_private_circuit_public_inputs; + + // Since we've made a call to another function, we now need to push a call_stack_item_hash to `this` function's + // private call stack. + // Note: we need to constrain some of `this` circuit's variables against f's public inputs: + // - args + // - return_values + // - call_context (TODO: maybe this only needs to be done in the kernel circuit). + auto f_public_inputs_ct = f_public_inputs_nt.to_circuit_type(composer); + + for (size_t i = 0; i < f_public_inputs_ct.args.size(); ++i) { + args[i].assert_equal(f_public_inputs_ct.args[i]); + } + + auto call_stack_item_hash = f_public_inputs_ct.hash(); + + array_push(private_circuit_public_inputs.private_call_stack, call_stack_item_hash); + + // The return values are implicitly constrained by being returned as circuit types from this method, for + // further use in the circuit. Note: ALL elements of the return_values array MUST be constrained, even if + // they're placeholder zeroes. + return f_public_inputs_ct.return_values; + } + /** * @brief This is an important optimisation, to save on the number of emitted nullifiers. * @@ -157,6 +227,8 @@ template class FunctionExecutionContext { private_circuit_public_inputs.set_commitments(new_commitments); private_circuit_public_inputs.set_nullifiers(new_nullifiers); private_circuit_public_inputs.set_public(composer); + final_private_circuit_public_inputs = + private_circuit_public_inputs.remove_optionality().template to_native_type(); }; }; diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp index 27e02abe96e..ac64b0060f4 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp @@ -28,9 +28,11 @@ TEST(private_to_private_function_call_tests, test_private_to_private_function_ca auto b = NT::fr(222); auto c = NT::fr(333); - auto result = function_1_1(fn1_exec_ctx, a, b, c); + function_1_1(fn1_exec_ctx, { a, b, c, 0, 0, 0, 0, 0 }); - info("result: ", result); + const auto& function_1_1_public_inputs = fn1_exec_ctx.final_private_circuit_public_inputs; + + info("function_1_1_public_inputs: ", function_1_1_public_inputs); info("computed witness: ", fn1_composer.computed_witness); info("witness: ", fn1_composer.witness); diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_1_1.cpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_1_1.cpp index aea929be57a..7686d15a6c3 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_1_1.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_1_1.cpp @@ -1,18 +1,13 @@ #include "function_1_1.hpp" +#include "function_2_1.hpp" #include "contract.hpp" -#include #include namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { -using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; - -OptionalPrivateCircuitPublicInputs function_1_1(FunctionExecutionContext& exec_ctx, - NT::fr const& _a, - NT::fr const& _b, - NT::fr const& _c) +void function_1_1(FunctionExecutionContext& exec_ctx, std::array const& _args) { /**************************************************************** * Initialisation @@ -24,10 +19,9 @@ OptionalPrivateCircuitPublicInputs function_1_1(FunctionExecutionContext& ex // Convert arguments into circuit types: auto& composer = exec_ctx.composer; - - CT::fr a = to_ct(composer, _a); - CT::fr b = to_ct(composer, _b); - CT::fr c = to_ct(composer, _c); + const auto a = to_ct(composer, _args[0]); + const auto b = to_ct(composer, _args[1]); + const auto c = to_ct(composer, _args[2]); /**************************************************************** * Get States & Globals used by the function @@ -50,31 +44,32 @@ OptionalPrivateCircuitPublicInputs function_1_1(FunctionExecutionContext& ex unique_person_who_may_initialise.assert_equal(msg_sender); - x.initialise({ - .value = a, - .owner = msg_sender, - }); - + /** + * Now we want to call an external function of another smart contract. + * What I've written below is a bit of a hack. + * In reality what we'll need from Noir++ is syntax which hides all of the boilerplate I write below. + * Also, I _know_ where all the code for `function_2_1` is, so I've taken a big shortcut and #included + * `function_2_1.hpp`. This won't be the way we'll fetch bytecode in practice. In practice, we might only learn the + * contract address at runtime, and hence we'll have to fetch some acir bytecode at runtime from a DB and execute + * that in a simulator (e.g. the ACVM). This is where all this noddy C++ example code that I'm writing falls short. + * But hopefully this code still serves as a useful example of how the public inputs of a private function should be + * computed. + */ // auto function_2_1 = contract_1.get_function("function_2_1"); - // const NT::address fn2_contract_address = 23456; + const CT::address fn_2_1_contract_address = 23456; - // C fn2_composer; + // TODO: this can probably be tidied up. + auto return_values = + exec_ctx.call(fn_2_1_contract_address, + "function_2_1", + std::function)>(function_2_1), + { a, b, c, 0, 0, 0, 0, 0 }); - // // Note: it's ok that we swap back into Native Types here - we don't need constraints. Creation of fn2_oracle is - // // necessary for circuit construction only; it's not part of the circuit itself. We check that the call_contexts - // // (msg_sender, contract_address, tx_origin) of functions 1 & 2 relate to one-another in the private kernel - // circuit, - // // by comparing the functions' public inputs. - // NativeOracle fn2_oracle = NativeOracle( // - // oracle.oracle.db, - // fn2_contract_address, - // oracle.get_this_contract_address().get_value(), - // oracle.get_tx_origin().get_value()); - // OracleWrapper fn2_oracle_wrapper = OracleWrapper(fn2_composer, fn2_oracle); - - // FunctionExecutionContext fn1_exec_ctx(fn2_composer, fn2_oracle_wrapper); - - // auto result = function_2_1.call(a, b, c); + // Use the return value in some way, just for fun: + x.initialise({ + .value = return_values[0], + .owner = msg_sender, + }); /**************************************************************** * CLEANUP @@ -91,9 +86,8 @@ OptionalPrivateCircuitPublicInputs function_1_1(FunctionExecutionContext& ex exec_ctx.finalise(); - info("public inputs: ", public_inputs); + info("final public inputs: ", exec_ctx.final_private_circuit_public_inputs); - return public_inputs.to_native_type(); // TODO: also return note preimages and nullifier preimages. }; diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_1_1.hpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_1_1.hpp index 62accb6c95e..5414327892f 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_1_1.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_1_1.hpp @@ -2,16 +2,10 @@ #include "init.hpp" -#include #include namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { -using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; - -OptionalPrivateCircuitPublicInputs function_1_1(FunctionExecutionContext& exec_ctx, - NT::fr const& _a, - NT::fr const& _b, - NT::fr const& _c); +void function_1_1(FunctionExecutionContext& exec_ctx, std::array const& _args); } // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_2_1.cpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_2_1.cpp index b79264a0e31..3d4c88ed2d1 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_2_1.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_2_1.cpp @@ -8,10 +8,7 @@ namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; -OptionalPrivateCircuitPublicInputs function_2_1(FunctionExecutionContext& exec_ctx, - NT::fr const& _d, - NT::fr const& _e, - NT::fr const& _f) +void function_2_1(FunctionExecutionContext& exec_ctx, std::array const& _args) { /**************************************************************** * Initialisation @@ -23,10 +20,9 @@ OptionalPrivateCircuitPublicInputs function_2_1(FunctionExecutionContext& ex // Convert arguments into circuit types: auto& composer = exec_ctx.composer; - - CT::fr d = to_ct(composer, _d); - CT::fr e = to_ct(composer, _e); - CT::fr f = to_ct(composer, _f); + const auto a = to_ct(composer, _args[0]); + const auto b = to_ct(composer, _args[1]); + const auto c = to_ct(composer, _args[2]); /**************************************************************** * Get States & Globals used by the function @@ -43,7 +39,7 @@ OptionalPrivateCircuitPublicInputs function_2_1(FunctionExecutionContext& ex * BODY ****************************************************************/ - auto product = d * e * f; + auto product = a * b * c; CT::address unique_person_who_may_initialise = 999999; @@ -64,9 +60,9 @@ OptionalPrivateCircuitPublicInputs function_2_1(FunctionExecutionContext& ex auto& public_inputs = exec_ctx.private_circuit_public_inputs; - public_inputs.args[0] = d; - public_inputs.args[1] = e; - public_inputs.args[2] = f; + public_inputs.args[0] = a; + public_inputs.args[1] = b; + public_inputs.args[2] = c; public_inputs.return_values[0] = product; @@ -74,7 +70,6 @@ OptionalPrivateCircuitPublicInputs function_2_1(FunctionExecutionContext& ex info("public inputs: ", public_inputs); - return public_inputs.to_native_type(); // TODO: also return note preimages and nullifier preimages. }; diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_2_1.hpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_2_1.hpp index 1cfe4aed5ec..0342925213a 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_2_1.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_2_1.hpp @@ -8,9 +8,6 @@ namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; -OptionalPrivateCircuitPublicInputs function_2_1(FunctionExecutionContext& exec_ctx, - NT::fr const& _d, - NT::fr const& _e, - NT::fr const& _f); +void function_2_1(FunctionExecutionContext& exec_ctx, std::array const& _args); } // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp b/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp index 7a87dbf4053..0f6f1921c27 100644 --- a/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp +++ b/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp @@ -1,5 +1,7 @@ #include "init.hpp" +#include + #include #include @@ -8,92 +10,10 @@ namespace aztec3::circuits::kernel::private_kernel { using aztec3::circuits::abis::private_kernel::PrivateInputs; using aztec3::circuits::abis::private_kernel::PublicInputs; -/****************************************************************************************************************** - * Calcs on circuit arrays. - * TODO: move these array calcs to a common/circuit_array.hpp file. - *****************************************************************************************************************/ - -/** - * Gets the number of contiguous nonzero values of an array. - * Note: this assumes `0` always means 'not used', so be careful. If you actually want `0` to be counted, you'll need - * something else. - */ -// TODO: move to own file of helper functions. -template CT::fr array_length(std::array const& arr) -{ - CT::fr length = 0; - CT::boolean hit_zero = false; - for (const auto& e : arr) { - hit_zero |= e == 0; - const CT::fr increment = !hit_zero; - length += increment; - } - return length; -}; - -/** - * Note: doesn't remove the last element from the array; only returns it! - * Note: this assumes `0` always means 'not used', so be careful. If you actually want `0` to be counted, you'll need - * something else. - * If it returns `0`, the array is considered 'empty'. - */ -template CT::fr array_pop(std::array const& arr) -{ - CT::fr popped_value; - CT::boolean already_popped = false; - for (size_t i = arr.size() - 1; i != (size_t)-1; i--) { - CT::boolean is_non_zero = arr[i] != 0; - popped_value = CT::fr::conditional_assign(!already_popped && is_non_zero, arr[i], popped_value); - - already_popped |= is_non_zero; - } - return popped_value; -}; - -/** - * Note: this assumes `0` always means 'not used', so be careful. If you actually want `0` to be counted, you'll need - * something else. - */ -template CT::boolean is_array_empty(std::array const& arr) -{ - CT::boolean nonzero_found = false; - for (size_t i = arr.size() - 1; i != (size_t)-1; i--) { - CT::boolean is_non_zero = arr[i] != 0; - nonzero_found |= is_non_zero; - } - return !nonzero_found; -}; - -/** - * Inserts the `source` array at the first zero-valued index of the `target` array. - * Fails if the `source` array is too large vs the remaining capacity of the `target` array. - */ -template -void push_array_to_array(std::array const& source, std::array& target) -{ - CT::fr target_length = array_length(target); - CT::fr source_length = array_length(source); - - CT::fr target_capacity = CT::fr(target.size()); - // TODO: using safe_fr for an underflow check, do: - // remaining_target_capacity = target_capacity.subtract(target_length + source_length); - - CT::fr t_i = 0; - CT::fr next_index = target_length; - for (const auto& s : source) { - for (auto& t : target) { - next_index.assert_not_equal(target_capacity, "Target array capacity exceeded"); - CT::boolean at_index = t_i == next_index; - t = CT::fr::conditional_assign(at_index, s, t); - next_index = CT::fr::conditional_assign(at_index, next_index + 1, next_index); - ++t_i; - } - } -} - -/*************************************************************************************************************** - * End of array calcs. - **************************************************************************************************************/ +using aztec3::circuits::types::array_length; +using aztec3::circuits::types::array_pop; +using aztec3::circuits::types::is_array_empty; +using aztec3::circuits::types::push_array_to_array; // TODO: NEED TO RECONCILE THE `proof`'s public inputs (which are uint8's) with the // private_call.call_stack_item.public_inputs! @@ -127,8 +47,7 @@ void initialise_end_values(PrivateInputs const& private_inputs, PublicInputs end.private_call_stack = start.private_call_stack; end.public_call_stack = start.public_call_stack; - end.contract_deployment_call_stack = start.contract_deployment_call_stack; - end.l1_call_stack = start.l1_call_stack; + end.l1_msg_stack = start.l1_msg_stack; end.optionally_revealed_data = start.optionally_revealed_data; } @@ -143,8 +62,8 @@ void update_end_values(PrivateInputs const& private_inputs, PublicInputs const auto& is_static_call = private_inputs.private_call.call_stack_item.public_inputs.call_context.is_static_call; // No state changes are allowed for static calls: - is_static_call.must_imply(is_array_empty(output_commitments) == true); - is_static_call.must_imply(is_array_empty(input_nullifiers) == true); + is_static_call.must_imply(is_array_empty(output_commitments) == true); + is_static_call.must_imply(is_array_empty(input_nullifiers) == true); const auto& storage_contract_address = private_inputs.private_call.call_stack_item.public_inputs.call_context.storage_contract_address; @@ -167,8 +86,8 @@ void update_end_values(PrivateInputs const& private_inputs, PublicInputs GeneratorIndex::OUTER_NULLIFIER)); } - push_array_to_array(siloed_output_commitments, public_inputs.end.output_commitments); - push_array_to_array(siloed_input_nullifiers, public_inputs.end.input_nullifiers); + push_array_to_array(siloed_output_commitments, public_inputs.end.output_commitments); + push_array_to_array(siloed_input_nullifiers, public_inputs.end.input_nullifiers); } { @@ -206,7 +125,7 @@ void update_end_values(PrivateInputs const& private_inputs, PublicInputs void validate_private_call_hash(PrivateInputs const& private_inputs) { const auto& start = private_inputs.previous_kernel.public_inputs.end; - const auto private_call_hash = array_pop(start.private_call_stack); + const auto private_call_hash = array_pop(start.private_call_stack); const auto calculated_private_call_hash = private_inputs.private_call.call_stack_item.hash(); private_call_hash.assert_equal(calculated_private_call_hash, "private_call_hash does not reconcile"); @@ -225,19 +144,18 @@ void validate_inputs(PrivateInputs const& private_inputs) const CT::boolean is_base_case = start.private_call_count == 0; const CT::boolean is_recursive_case = !is_base_case; - CT::fr start_private_call_stack_length = array_length(start.private_call_stack); - CT::fr start_public_call_stack_length = array_length(start.public_call_stack); - CT::fr start_contract_deployment_call_stack_length = array_length(start.contract_deployment_call_stack); - CT::fr start_l1_call_stack_length = array_length(start.l1_call_stack); + CT::fr start_private_call_stack_length = array_length(start.private_call_stack); + CT::fr start_public_call_stack_length = array_length(start.public_call_stack); + CT::fr start_l1_msg_stack_length = array_length(start.l1_msg_stack); // Base Case { // Validate callstack lengths: - is_base_case.must_imply(start_private_call_stack_length == - 1 // TODO: might change to allow 2, so a fee can be paid. - && start_public_call_stack_length == 0 && - start_contract_deployment_call_stack_length == 0 && start_l1_call_stack_length == 0, - "Invalid callstacks for base case."); + is_base_case.must_imply( + start_private_call_stack_length == + 1 // TODO: might change to allow 3, so a fee can be paid and a gas rebate can be paid. + && start_public_call_stack_length == 0 && start_l1_msg_stack_length == 0, + "Invalid callstacks for base case."); is_base_case.must_imply(next_call.public_inputs.call_context.is_delegate_call == false && next_call.public_inputs.call_context.is_static_call == false, @@ -264,12 +182,16 @@ void validate_inputs(PrivateInputs const& private_inputs) } // TODO: decide what to return. +// TODO: is there a way to identify whether an input has not been used by ths circuit? This would help us more-safely +// ensure we're constraining everything. void private_kernel_circuit(Composer& composer, OracleWrapper& oracle, PrivateInputs const& _private_inputs) { (void)oracle; // To avoid unused variable compiler errors whilst building. const PrivateInputs private_inputs = _private_inputs.to_circuit_type(composer); - PublicInputs public_inputs; + + // We'll be pushing data to this during execution of this circuit. + PublicInputs public_inputs{}; // const auto& start = private_inputs.previous_kernel.public_inputs.end; diff --git a/circuits/src/aztec3/circuits/types/array.hpp b/circuits/src/aztec3/circuits/types/array.hpp new file mode 100644 index 00000000000..20bac55f209 --- /dev/null +++ b/circuits/src/aztec3/circuits/types/array.hpp @@ -0,0 +1,140 @@ +#pragma once + +#include + +namespace aztec3::circuits::types { + +using plonk::stdlib::types::CircuitTypes; + +/** + * Gets the number of contiguous nonzero values of an array. + * Note: this assumes `0` always means 'not used', so be careful. If you actually want `0` to be counted, you'll need + * something else. + */ +// TODO: move to own file of helper functions. +template +typename CircuitTypes::fr array_length(std::array::fr, SIZE> const& arr) +{ + typedef CircuitTypes CT; + typedef typename CT::fr fr; + typedef typename CT::boolean boolean; + + fr length = 0; + boolean hit_zero = false; + for (const auto& e : arr) { + hit_zero |= e == 0; + const fr increment = !hit_zero; + length += increment; + } + return length; +}; + +/** + * Note: doesn't remove the last element from the array; only returns it! + * Note: this assumes `0` always means 'not used', so be careful. If you actually want `0` to be counted, you'll need + * something else. + * If it returns `0`, the array is considered 'empty'. + */ +template +typename CircuitTypes::fr array_pop(std::array::fr, SIZE> const& arr) +{ + typedef CircuitTypes CT; + typedef typename CT::fr fr; + typedef typename CT::boolean boolean; + + fr popped_value; + boolean already_popped = false; + for (size_t i = arr.size() - 1; i != (size_t)-1; i--) { + boolean is_non_zero = arr[i] != 0; + popped_value = fr::conditional_assign(!already_popped && is_non_zero, arr[i], popped_value); + + already_popped |= is_non_zero; + } + return popped_value; +}; + +/** + * Note: this assumes `0` always means 'not used', so be careful. If you actually want `0` to be counted, you'll need + * something else. + */ +template +void array_push(std::array::fr, SIZE>& arr, + typename CircuitTypes::fr const& value) +{ + typedef CircuitTypes CT; + typedef typename CT::fr fr; + typedef typename CT::boolean boolean; + + boolean already_pushed = false; + for (size_t i = 0; i < arr.size(); ++i) { + boolean is_zero = arr[i] == 0; + arr[i] = fr::conditional_assign(!already_pushed && is_zero, value, arr[i]); + + already_pushed |= is_zero; + } +}; + +template +inline void array_push(std::array::fr>, SIZE>& arr, + typename CircuitTypes::fr const& value) +{ + for (size_t i = 0; i < arr.size(); ++i) { + if (arr[i] == std::nullopt) { + arr[i] = value; + return; + } + } +}; + +/** + * Note: this assumes `0` always means 'not used', so be careful. If you actually want `0` to be counted, you'll need + * something else. + */ +template +typename CircuitTypes::boolean is_array_empty( + std::array::fr, SIZE> const& arr) +{ + typedef CircuitTypes CT; + typedef typename CT::boolean boolean; + + boolean nonzero_found = false; + for (size_t i = arr.size() - 1; i != (size_t)-1; i--) { + boolean is_non_zero = arr[i] != 0; + nonzero_found |= is_non_zero; + } + return !nonzero_found; +}; + +/** + * Inserts the `source` array at the first zero-valued index of the `target` array. + * Fails if the `source` array is too large vs the remaining capacity of the `target` array. + */ +template +void push_array_to_array(std::array::fr, size_1> const& source, + std::array::fr, size_2>& target) +{ + typedef CircuitTypes CT; + typedef typename CT::fr fr; + typedef typename CT::boolean boolean; + + fr target_length = array_length(target); + // fr source_length = array_length(source); + + fr target_capacity = fr(target.size()); + // TODO: using safe_fr for an underflow check, do: + // remaining_target_capacity = target_capacity.subtract(target_length + source_length); + + fr t_i = 0; + fr next_index = target_length; + for (const auto& s : source) { + for (auto& t : target) { + next_index.assert_not_equal(target_capacity, "Target array capacity exceeded"); + boolean at_index = t_i == next_index; + t = fr::conditional_assign(at_index, s, t); + next_index = fr::conditional_assign(at_index, next_index + 1, next_index); + ++t_i; + } + } +} + +} // namespace aztec3::circuits::types \ No newline at end of file From 9e6393135da53308bb792b728b4d6cc94450f84a Mon Sep 17 00:00:00 2001 From: iAmMichaelConnor Date: Fri, 13 Jan 2023 06:52:51 +0000 Subject: [PATCH 029/166] extracting call stack item preimages --- circuits/src/aztec3/circuits/abis/.test.cpp | 8 +- .../aztec3/circuits/abis/call_stack_item.hpp | 12 +- .../circuits/abis/function_signature.hpp | 17 +- .../abis/private_circuit_public_inputs.hpp | 88 ++++---- .../abis/private_kernel/accumulated_data.hpp | 14 +- .../private_kernel/previous_kernel_data.hpp | 3 + .../abis/private_kernel/private_call_data.hpp | 29 ++- circuits/src/aztec3/circuits/apps/.test.cpp | 85 +++++--- .../src/aztec3/circuits/apps/contract.tpp | 3 +- .../apps/function_execution_context.cpp | 205 ++++++++++++++++++ .../apps/function_execution_context.hpp | 125 +++++++++-- .../aztec3/circuits/apps/oracle_wrapper.hpp | 19 +- .../circuits/apps/test_apps/escrow/.test.cpp | 117 +++++----- .../.test.cpp | 27 ++- .../function_1_1.cpp | 2 +- .../src/aztec3/circuits/kernel/CMakeLists.txt | 2 + .../aztec3/circuits/kernel/private/.test.cpp | 36 +-- .../kernel/private/private_kernel_circuit.cpp | 101 ++++----- .../kernel/private/private_kernel_circuit.hpp | 2 +- circuits/src/aztec3/circuits/types/array.hpp | 22 +- circuits/src/aztec3/constants.hpp | 12 +- circuits/src/aztec3/oracle/oracle.hpp | 66 ++---- 22 files changed, 653 insertions(+), 342 deletions(-) create mode 100644 circuits/src/aztec3/circuits/apps/function_execution_context.cpp diff --git a/circuits/src/aztec3/circuits/abis/.test.cpp b/circuits/src/aztec3/circuits/abis/.test.cpp index 6d4c0e60e3c..beefe7d42cd 100644 --- a/circuits/src/aztec3/circuits/abis/.test.cpp +++ b/circuits/src/aztec3/circuits/abis/.test.cpp @@ -16,7 +16,7 @@ class abi_tests : public ::testing::Test {}; TEST(abi_tests, test_native_function_signature) { FunctionSignature function_signature = { - .vk_index = 11, + .function_encoding = 11, .is_private = false, .is_constructor = false, }; @@ -32,7 +32,7 @@ TEST(abi_tests, test_native_function_signature) TEST(abi_tests, test_native_to_circuit_function_signature) { FunctionSignature native_function_signature = { - .vk_index = 11, + .function_encoding = 11, .is_private = false, .is_constructor = false, }; @@ -132,7 +132,7 @@ TEST(abi_tests, test_native_to_circuit_call_context) // CallStackItem call_stack_item = { // .function_signature = { // // .contract_address = 10, -// .vk_index = 11, +// .function_encoding = 11, // .is_private = false, // .is_constructor = false, // }, @@ -165,7 +165,7 @@ TEST(abi_tests, test_native_to_circuit_call_context) // CallStackItem native_call_stack_item = { // .function_signature = { // // .contract_address = 10, -// .vk_index = 11, +// .function_encoding = 11, // .is_private = false, // .is_constructor = false, // }, diff --git a/circuits/src/aztec3/circuits/abis/call_stack_item.hpp b/circuits/src/aztec3/circuits/abis/call_stack_item.hpp index b80b865ae22..0166c3c7ef8 100644 --- a/circuits/src/aztec3/circuits/abis/call_stack_item.hpp +++ b/circuits/src/aztec3/circuits/abis/call_stack_item.hpp @@ -2,6 +2,7 @@ #include "function_signature.hpp" #include "private_circuit_public_inputs.hpp" #include "public_circuit_public_inputs.hpp" + #include #include #include @@ -62,17 +63,10 @@ template struct CallStackItem { std::vector inputs = { contract_address.to_field(), function_signature.hash(), - public_inputs - .hash(), // Note: this public_inputs.hash() omits hashing of the public_inputs.call_context, because we - // want to 'unwrap' it with the fewest hashes possible in the kernel circuit. + public_inputs.hash(), }; - fr call_stack_item_hash_no_context = NCT::compress(inputs, GeneratorIndex::CALL_STACK_ITEM); - - fr call_context_hash = public_inputs.call_context.hash(); - - fr call_stack_item_hash = - NCT::compress({ call_context_hash, call_stack_item_hash_no_context }, GeneratorIndex::CALL_STACK_ITEM_2); + fr call_stack_item_hash = NCT::compress(inputs, GeneratorIndex::CALL_STACK_ITEM); return call_stack_item_hash; } diff --git a/circuits/src/aztec3/circuits/abis/function_signature.hpp b/circuits/src/aztec3/circuits/abis/function_signature.hpp index 7a2a7e94dc2..7d53d37a002 100644 --- a/circuits/src/aztec3/circuits/abis/function_signature.hpp +++ b/circuits/src/aztec3/circuits/abis/function_signature.hpp @@ -20,13 +20,13 @@ template struct FunctionSignature { typedef typename NCT::grumpkin_point grumpkin_point; typedef typename NCT::fr fr; - uint32 vk_index; + uint32 function_encoding; // e.g. 1st 4-bytes of abi-encoding of function. boolean is_private = false; boolean is_constructor = false; bool operator==(FunctionSignature const&) const = default; - static FunctionSignature empty() { return { 0, 0, 0, 0, 0 }; }; + static FunctionSignature empty() { return { 0, 0, 0 }; }; template FunctionSignature> to_circuit_type(Composer& composer) const { @@ -36,7 +36,7 @@ template struct FunctionSignature { auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; FunctionSignature> function_signature = { - to_ct(vk_index), + to_ct(function_encoding), to_ct(is_private), to_ct(is_constructor), }; @@ -48,15 +48,16 @@ template struct FunctionSignature { { static_assert(!(std::is_same::value)); - fr(vk_index).set_public(); + fr(function_encoding).set_public(); fr(is_private).set_public(); fr(is_constructor).set_public(); } + // TODO: this can all be packed into 1 field element, so this `hash` function should just return that field element. fr hash() const { std::vector inputs = { - fr(vk_index), + fr(function_encoding), fr(is_private), fr(is_constructor), }; @@ -69,7 +70,7 @@ template void read(uint8_t const*& it, FunctionSignature& fu { using serialize::read; - read(it, function_signature.vk_index); + read(it, function_signature.function_encoding); read(it, function_signature.is_private); read(it, function_signature.is_constructor); }; @@ -78,14 +79,14 @@ template void write(std::vector& buf, FunctionSignature< { using serialize::write; - write(buf, function_signature.vk_index); + write(buf, function_signature.function_encoding); write(buf, function_signature.is_private); write(buf, function_signature.is_constructor); }; template std::ostream& operator<<(std::ostream& os, FunctionSignature const& function_signature) { - return os << "vk_index: " << function_signature.vk_index << "\n" + return os << "function_encoding: " << function_signature.function_encoding << "\n" << "is_private: " << function_signature.is_private << "\n" << "is_constructor: " << function_signature.is_constructor << "\n"; } diff --git a/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp b/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp index 0db607150c2..b90eeb09e31 100644 --- a/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp +++ b/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp @@ -30,8 +30,8 @@ template class PrivateCircuitPublicInputs { std::array emitted_events; - std::array output_commitments; - std::array input_nullifiers; + std::array new_commitments; + std::array new_nullifiers; std::array private_call_stack; std::array public_call_stack; @@ -60,8 +60,8 @@ template class PrivateCircuitPublicInputs { to_ct(emitted_events), - to_ct(output_commitments), - to_ct(input_nullifiers), + to_ct(new_commitments), + to_ct(new_nullifiers), to_ct(private_call_stack), to_ct(public_call_stack), @@ -91,8 +91,8 @@ template class PrivateCircuitPublicInputs { to_nt(emitted_events), - to_nt(output_commitments), - to_nt(input_nullifiers), + to_nt(new_commitments), + to_nt(new_nullifiers), to_nt(private_call_stack), to_nt(public_call_stack), @@ -121,8 +121,8 @@ template class PrivateCircuitPublicInputs { spread_arr_into_vec(emitted_events, inputs); - spread_arr_into_vec(output_commitments, inputs); - spread_arr_into_vec(input_nullifiers, inputs); + spread_arr_into_vec(new_commitments, inputs); + spread_arr_into_vec(new_nullifiers, inputs); spread_arr_into_vec(private_call_stack, inputs); spread_arr_into_vec(public_call_stack, inputs); @@ -153,8 +153,8 @@ template void read(uint8_t const*& it, PrivateCircuitPublicInputs read(it, pis.args); read(it, pis.return_values); read(it, pis.emitted_events); - read(it, pis.output_commitments); - read(it, pis.input_nullifiers); + read(it, pis.new_commitments); + read(it, pis.new_nullifiers); read(it, pis.private_call_stack); read(it, pis.public_call_stack); read(it, pis.l1_msg_stack); @@ -176,8 +176,8 @@ void write(std::vector& buf, PrivateCircuitPublicInputs const& pri write(buf, pis.args); write(buf, pis.return_values); write(buf, pis.emitted_events); - write(buf, pis.output_commitments); - write(buf, pis.input_nullifiers); + write(buf, pis.new_commitments); + write(buf, pis.new_nullifiers); write(buf, pis.private_call_stack); write(buf, pis.public_call_stack); write(buf, pis.l1_msg_stack); @@ -197,8 +197,8 @@ std::ostream& operator<<(std::ostream& os, PrivateCircuitPublicInputs const << "args: " << pis.args << "\n" << "return_values: " << pis.return_values << "\n" << "emitted_events: " << pis.emitted_events << "\n" - << "output_commitments: " << pis.output_commitments << "\n" - << "input_nullifiers: " << pis.input_nullifiers << "\n" + << "new_commitments: " << pis.new_commitments << "\n" + << "new_nullifiers: " << pis.new_nullifiers << "\n" << "private_call_stack: " << pis.private_call_stack << "\n" << "public_call_stack: " << pis.public_call_stack << "\n" << "l1_msg_stack: " << pis.l1_msg_stack << "\n" @@ -226,8 +226,8 @@ template class OptionalPrivateCircuitPublicInputs { std::array emitted_events; - std::array output_commitments; - std::array input_nullifiers; + std::array new_commitments; + std::array new_nullifiers; std::array private_call_stack; std::array public_call_stack; @@ -248,8 +248,8 @@ template class OptionalPrivateCircuitPublicInputs { std::array const& emitted_events, - std::array const& output_commitments, - std::array const& input_nullifiers, + std::array const& new_commitments, + std::array const& new_nullifiers, std::array const& private_call_stack, std::array const& public_call_stack, @@ -264,8 +264,8 @@ template class OptionalPrivateCircuitPublicInputs { , args(args) , return_values(return_values) , emitted_events(emitted_events) - , output_commitments(output_commitments) - , input_nullifiers(input_nullifiers) + , new_commitments(new_commitments) + , new_nullifiers(new_nullifiers) , private_call_stack(private_call_stack) , public_call_stack(public_call_stack) , l1_msg_stack(l1_msg_stack) @@ -288,8 +288,8 @@ template class OptionalPrivateCircuitPublicInputs { new_inputs.emitted_events.fill(std::nullopt); - new_inputs.output_commitments.fill(std::nullopt); - new_inputs.input_nullifiers.fill(std::nullopt); + new_inputs.new_commitments.fill(std::nullopt); + new_inputs.new_nullifiers.fill(std::nullopt); new_inputs.private_call_stack.fill(std::nullopt); new_inputs.public_call_stack.fill(std::nullopt); @@ -306,21 +306,21 @@ template class OptionalPrivateCircuitPublicInputs { void set_commitments(std::vector commitments) { - if (commitments.size() > output_commitments.size()) { + if (commitments.size() > new_commitments.size()) { throw_or_abort("Too many commitments for the number supported by the public inputs ABI."); } for (size_t i = 0; i < commitments.size(); ++i) { - output_commitments[i] = commitments[i]; + new_commitments[i] = commitments[i]; } } void set_nullifiers(std::vector nullifiers) { - if (nullifiers.size() > input_nullifiers.size()) { + if (nullifiers.size() > new_nullifiers.size()) { throw_or_abort("Too many commitments for the number supported by the public inputs ABI."); } for (size_t i = 0; i < nullifiers.size(); ++i) { - input_nullifiers[i] = nullifiers[i]; + new_nullifiers[i] = nullifiers[i]; } } @@ -335,8 +335,8 @@ template class OptionalPrivateCircuitPublicInputs { make_unused_array_elements_zero(composer, emitted_events); - make_unused_array_elements_zero(composer, output_commitments); - make_unused_array_elements_zero(composer, input_nullifiers); + make_unused_array_elements_zero(composer, new_commitments); + make_unused_array_elements_zero(composer, new_nullifiers); make_unused_array_elements_zero(composer, private_call_stack); make_unused_array_elements_zero(composer, public_call_stack); @@ -366,8 +366,8 @@ template class OptionalPrivateCircuitPublicInputs { set_array_public(emitted_events); - set_array_public(output_commitments); - set_array_public(input_nullifiers); + set_array_public(new_commitments); + set_array_public(new_nullifiers); set_array_public(private_call_stack); set_array_public(public_call_stack); @@ -399,8 +399,8 @@ template class OptionalPrivateCircuitPublicInputs { to_ct(emitted_events), - to_ct(output_commitments), - to_ct(input_nullifiers), + to_ct(new_commitments), + to_ct(new_nullifiers), to_ct(private_call_stack), to_ct(public_call_stack), @@ -433,8 +433,8 @@ template class OptionalPrivateCircuitPublicInputs { to_nt(emitted_events), - to_nt(output_commitments), - to_nt(input_nullifiers), + to_nt(new_commitments), + to_nt(new_nullifiers), to_nt(private_call_stack), to_nt(public_call_stack), @@ -468,8 +468,8 @@ template class OptionalPrivateCircuitPublicInputs { spread_arr_opt_into_vec(emitted_events, inputs); - spread_arr_opt_into_vec(output_commitments, inputs); - spread_arr_opt_into_vec(input_nullifiers, inputs); + spread_arr_opt_into_vec(new_commitments, inputs); + spread_arr_opt_into_vec(new_nullifiers, inputs); spread_arr_opt_into_vec(private_call_stack, inputs); spread_arr_opt_into_vec(public_call_stack, inputs); @@ -497,8 +497,8 @@ template class OptionalPrivateCircuitPublicInputs { .emitted_events = map(emitted_events, get_value), - .output_commitments = map(output_commitments, get_value), - .input_nullifiers = map(input_nullifiers, get_value), + .new_commitments = map(new_commitments, get_value), + .new_nullifiers = map(new_nullifiers, get_value), .private_call_stack = map(private_call_stack, get_value), .public_call_stack = map(public_call_stack, get_value), @@ -590,8 +590,8 @@ void read(uint8_t const*& it, OptionalPrivateCircuitPublicInputs& private_c read(it, pis.args); read(it, pis.return_values); read(it, pis.emitted_events); - read(it, pis.output_commitments); - read(it, pis.input_nullifiers); + read(it, pis.new_commitments); + read(it, pis.new_nullifiers); read(it, pis.private_call_stack); read(it, pis.public_call_stack); read(it, pis.l1_msg_stack); @@ -613,8 +613,8 @@ void write(std::vector& buf, OptionalPrivateCircuitPublicInputs co write(buf, pis.args); write(buf, pis.return_values); write(buf, pis.emitted_events); - write(buf, pis.output_commitments); - write(buf, pis.input_nullifiers); + write(buf, pis.new_commitments); + write(buf, pis.new_nullifiers); write(buf, pis.private_call_stack); write(buf, pis.public_call_stack); write(buf, pis.l1_msg_stack); @@ -634,8 +634,8 @@ std::ostream& operator<<(std::ostream& os, OptionalPrivateCircuitPublicInputs struct AccumulatedData { fr private_call_count; - std::array output_commitments; - std::array input_nullifiers; + std::array new_commitments; + std::array new_nullifiers; std::array private_call_stack; std::array public_call_stack; - std::array l1_msg_stack; + std::array l1_msg_stack; std::array, KERNEL_OPTIONALLY_REVEALED_DATA_LENGTH> optionally_revealed_data; @@ -50,8 +50,8 @@ template struct AccumulatedData { to_ct(private_call_count), - to_ct(output_commitments), - to_ct(input_nullifiers), + to_ct(new_commitments), + to_ct(new_nullifiers), to_ct(private_call_stack), to_ct(public_call_stack), @@ -71,8 +71,8 @@ template struct AccumulatedData { private_call_count.set_public(); - set_array_public(output_commitments); - set_array_public(input_nullifiers); + set_array_public(new_commitments); + set_array_public(new_nullifiers); set_array_public(private_call_stack); set_array_public(public_call_stack); diff --git a/circuits/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp b/circuits/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp index 32648930e4a..1165c202142 100644 --- a/circuits/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp +++ b/circuits/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp @@ -19,6 +19,9 @@ template struct PreviousKernelData { PublicInputs public_inputs; // TODO: not needed as already contained in proof? NativeTypes::Proof proof; // TODO: how to express proof as native/circuit type when it gets used as a buffer? std::shared_ptr vk; + + // TODO: this index and path are meant to be those of a tree of _kernel circuit_ vks; not the tree of functions + // within the contract tree. fr vk_index; std::array vk_path; diff --git a/circuits/src/aztec3/circuits/abis/private_kernel/private_call_data.hpp b/circuits/src/aztec3/circuits/abis/private_kernel/private_call_data.hpp index 2683646b565..5512431deaa 100644 --- a/circuits/src/aztec3/circuits/abis/private_kernel/private_call_data.hpp +++ b/circuits/src/aztec3/circuits/abis/private_kernel/private_call_data.hpp @@ -3,6 +3,7 @@ #include "call_context_reconciliation_data.hpp" #include "../call_stack_item.hpp" +#include #include #include #include @@ -21,19 +22,25 @@ template struct PrivateCallData { typedef typename NCT::VK VK; CallStackItem call_stack_item; - // CallContextReconciliationData call_context_reconciliation_data; + + std::array, PRIVATE_CALL_STACK_LENGTH> private_call_stack_preimages; + + // std::array, PUBLIC_CALL_STACK_LENGTH> public_call_stack_preimages; NativeTypes::Proof proof; // TODO: how to express proof as native/circuit type when it gets used as a buffer? std::shared_ptr vk; - std::array vk_path; + + fr function_leaf_index; + std::array function_leaf_path; fr contract_tree_root; fr contract_leaf_index; - std::array contract_path; + std::array contract_leaf_path; fr portal_contract_address; // an ETH address - // WARNING: the `proof` does NOT get converted! + // WARNING: the `proof` does NOT get converted! (because the current implementation of `verify_proof` takes a proof + // of native bytes; any conversion to circuit types happens within the `verify_proof` function) template PrivateCallData> to_circuit_type(Composer& composer) const { typedef CircuitTypes CT; @@ -41,19 +48,23 @@ template struct PrivateCallData { // Capture the composer: auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + auto to_circuit_type = [&](auto& e) { return e.to_circuit_type(composer); }; PrivateCallData> data = { call_stack_item.to_circuit_type(composer), - // call_context_reconciliation_data.to_circuit_type(composer), - proof, // Notice: not converted! Stays as native. This is because of how the verify_proof function currently - // works. + map(private_call_stack_preimages, to_circuit_type), + + proof, // Notice: not converted! Stays as native. This is because of how the verify_proof function + // currently works. CT::VK::from_witness(&composer, vk), - to_ct(vk_path), + + to_ct(function_leaf_index), + to_ct(function_leaf_path), to_ct(contract_tree_root), to_ct(contract_leaf_index), - to_ct(contract_path), + to_ct(contract_leaf_path), to_ct(portal_contract_address), }; diff --git a/circuits/src/aztec3/circuits/apps/.test.cpp b/circuits/src/aztec3/circuits/apps/.test.cpp index a8ebc2571d8..96cfef310cd 100644 --- a/circuits/src/aztec3/circuits/apps/.test.cpp +++ b/circuits/src/aztec3/circuits/apps/.test.cpp @@ -88,26 +88,47 @@ namespace aztec3::circuits::apps { class state_var_tests : public ::testing::Test { protected: - NativeOracle get_test_native_oracle() + FunctionExecutionContext get_test_exec_ctx() { + C composer; DB db; - // No cheating: you have to grab this stuff from the oracle in your tests - hence the 'private' scope. - NT::fr msg_sender_private_key = 123456789; - NT::address contract_address = 12345; - NT::address msg_sender = NT::fr( - uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); - NT::address tx_origin = msg_sender; - return NativeOracle(db, contract_address, msg_sender, tx_origin, msg_sender_private_key); + const NT::address contract_address = 12345; + const NT::fr msg_sender_private_key = 123456789; + const NT::address msg_sender = NT::fr( + uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); + const NT::address tx_origin = msg_sender; + + FunctionSignature function_signature{ + .function_encoding = 1, // TODO: deduce this from the contract, somehow. + .is_private = true, + .is_constructor = false, + }; + + CallContext call_context{ + .msg_sender = msg_sender, + .storage_contract_address = contract_address, + .tx_origin = msg_sender, + .is_delegate_call = false, + .is_static_call = false, + .is_contract_deployment = false, + .reference_block_num = 0, + }; + + NativeOracle oracle = + NativeOracle(db, contract_address, function_signature, call_context, msg_sender_private_key); + OracleWrapper oracle_wrapper = OracleWrapper(composer, oracle); + + FunctionExecutionContext exec_ctx(composer, oracle_wrapper); + + return exec_ctx; }; }; TEST_F(state_var_tests, mapping) { - C composer; - NativeOracle native_oracle = get_test_native_oracle(); - OracleWrapper oracle = OracleWrapper(composer, native_oracle); - FunctionExecutionContext exec_ctx(composer, oracle); + auto exec_ctx = get_test_exec_ctx(); + auto& composer = exec_ctx.composer; // TODO: // Interestingly, if I scope the below, the debugger works, but running the test via the command line fails. This is @@ -135,10 +156,8 @@ TEST_F(state_var_tests, mapping) TEST_F(state_var_tests, mapping_within_mapping) { - C composer; - NativeOracle native_oracle = get_test_native_oracle(); - OracleWrapper oracle = OracleWrapper(composer, native_oracle); - FunctionExecutionContext exec_ctx(composer, oracle); + auto exec_ctx = get_test_exec_ctx(); + // auto& composer = exec_ctx.composer; // { ::Contract contract("TestContract"); @@ -156,10 +175,8 @@ TEST_F(state_var_tests, mapping_within_mapping) TEST_F(state_var_tests, partial_mapping) { - C composer; - NativeOracle native_oracle = get_test_native_oracle(); - OracleWrapper oracle = OracleWrapper(composer, native_oracle); - FunctionExecutionContext exec_ctx(composer, oracle); + auto exec_ctx = get_test_exec_ctx(); + // auto& composer = exec_ctx.composer; // { ::Contract contract("TestContract"); @@ -177,10 +194,9 @@ TEST_F(state_var_tests, partial_mapping) TEST_F(state_var_tests, utxo_of_default_private_note_fr) { - C composer; - NativeOracle native_oracle = get_test_native_oracle(); - OracleWrapper oracle = OracleWrapper(composer, native_oracle); - FunctionExecutionContext exec_ctx(composer, oracle); + auto exec_ctx = get_test_exec_ctx(); + // auto& composer = exec_ctx.composer; + auto& oracle = exec_ctx.oracle; ::Contract contract("TestContract"); exec_ctx.register_contract(&contract); @@ -223,10 +239,9 @@ TEST_F(state_var_tests, utxo_of_default_private_note_fr) TEST_F(state_var_tests, utxo_set_of_default_private_notes_fr) { - C composer; - NativeOracle native_oracle = get_test_native_oracle(); - OracleWrapper oracle = OracleWrapper(composer, native_oracle); - FunctionExecutionContext exec_ctx(composer, oracle); + auto exec_ctx = get_test_exec_ctx(); + // auto& composer = exec_ctx.composer; + auto& oracle = exec_ctx.oracle; // bool sort(NT::uint256 i, NT::uint256 j) // { @@ -284,10 +299,9 @@ TEST_F(state_var_tests, utxo_set_of_default_private_notes_fr) TEST_F(state_var_tests, initialise_utxo_of_default_singleton_private_note_fr) { - C composer; - NativeOracle native_oracle = get_test_native_oracle(); - OracleWrapper oracle = OracleWrapper(composer, native_oracle); - FunctionExecutionContext exec_ctx(composer, oracle); + auto exec_ctx = get_test_exec_ctx(); + // auto& composer = exec_ctx.composer; + auto& oracle = exec_ctx.oracle; ::Contract contract("TestContract"); exec_ctx.register_contract(&contract); @@ -331,10 +345,9 @@ TEST_F(state_var_tests, initialise_utxo_of_default_singleton_private_note_fr) TEST_F(state_var_tests, modify_utxo_of_default_singleton_private_note_fr) { - C composer; - NativeOracle native_oracle = get_test_native_oracle(); - OracleWrapper oracle = OracleWrapper(composer, native_oracle); - FunctionExecutionContext exec_ctx(composer, oracle); + auto exec_ctx = get_test_exec_ctx(); + // auto& composer = exec_ctx.composer; + auto& oracle = exec_ctx.oracle; ::Contract contract("TestContract"); exec_ctx.register_contract(&contract); diff --git a/circuits/src/aztec3/circuits/apps/contract.tpp b/circuits/src/aztec3/circuits/apps/contract.tpp index c833af0df6a..60e36d1d806 100644 --- a/circuits/src/aztec3/circuits/apps/contract.tpp +++ b/circuits/src/aztec3/circuits/apps/contract.tpp @@ -27,8 +27,7 @@ template void Contract::set_functions(std::vector{ - // TODO: vk_index to actually be derived as 1st 4-bytes of hash of function signature. - .vk_index = uint32(i), + .function_encoding = uint32(i), .is_private = function.is_private, .is_constructor = function.is_constructor, }; diff --git a/circuits/src/aztec3/circuits/apps/function_execution_context.cpp b/circuits/src/aztec3/circuits/apps/function_execution_context.cpp new file mode 100644 index 00000000000..3421c75733b --- /dev/null +++ b/circuits/src/aztec3/circuits/apps/function_execution_context.cpp @@ -0,0 +1,205 @@ +// #include "function_execution_context.hpp" + +// #include "contract.hpp" +// #include "oracle_wrapper.hpp" + +// #include "notes/note_interface.hpp" + +// #include "opcodes/opcodes.hpp" + +// #include + +// #include +// #include +// #include + +// #include + +// #include + +// #include + +// namespace aztec3::circuits::apps { + +// using aztec3::circuits::abis::CallStackItem; +// using aztec3::circuits::abis::CallType; +// using aztec3::circuits::abis::FunctionSignature; +// using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; +// using aztec3::circuits::abis::PrivateCircuitPublicInputs; + +// using aztec3::circuits::apps::notes::NoteInterface; +// using aztec3::circuits::apps::opcodes::Opcodes; + +// using aztec3::circuits::types::array_push; + +// using plonk::stdlib::witness_t; +// using plonk::stdlib::types::CircuitTypes; +// using NT = plonk::stdlib::types::NativeTypes; +// using plonk::stdlib::types::to_nt; + +// template +// CallStackItem FunctionExecutionContext::get_call_stack_item() +// { +// const NT::address& actual_contract_address = oracle.native_oracle.get_actual_contract_address(); +// const FunctionSignature& function_signature = oracle.native_oracle.get_function_signature(); + +// return CallStackItem{ +// .contract_address = actual_contract_address, +// .function_signature = function_signature, +// .public_inputs = get_final_private_circuit_public_inputs(), +// }; +// } + +// template +// std::array, PRIVATE_CALL_STACK_LENGTH> FunctionExecutionContext< +// Composer>::get_private_call_stack_items() +// { +// std::array, PRIVATE_CALL_STACK_LENGTH> result; + +// for (size_t i = 0; i < result.size(); ++i) { +// auto& nested_exec_ctx = nested_private_call_exec_ctxs[i]; +// if (nested_exec_ctx != nullptr) { +// const NT::address& actual_contract_address = +// nested_exec_ctx->oracle.native_oracle.get_actual_contract_address(); +// const FunctionSignature& function_signature = +// nested_exec_ctx->oracle.native_oracle.get_function_signature(); + +// result[i] = CallStackItem{ +// .contract_address = actual_contract_address, +// .function_signature = function_signature, +// .public_inputs = nested_exec_ctx->get_final_private_circuit_public_inputs(), +// }; +// } +// } + +// // TODO: do we need to instantiate-with-zeros the structs at the unused indices of `result`? + +// return result; +// } + +// template +// std::array::fr, RETURN_VALUES_LENGTH> FunctionExecutionContext::call( +// typename CircuitTypes::address const& external_contract_address, +// std::string const& external_function_name, +// std::function&, std::array)> f, +// std::array::fr, ARGS_LENGTH> const& args) +// { + +// Composer f_composer; + +// // Convert function name to bytes and use the first 4 bytes as the function encoding, for now: +// std::vector f_name_bytes(external_function_name.begin(), external_function_name.end()); +// std::vector f_encoding_bytes(f_name_bytes.begin(), f_name_bytes.begin() + 4); +// uint32_t f_encoding; +// memcpy(&f_encoding, f_encoding_bytes.data(), sizeof(f_encoding)); + +// const FunctionSignature f_function_signature{ +// .function_encoding = f_encoding, +// .is_private = true, +// .is_constructor = false, +// }; + +// const CallContext f_call_context{ +// .msg_sender = oracle.get_this_contract_address(), // the sender is `this` contract! +// .storage_contract_address = external_contract_address, +// .tx_origin = oracle.get_tx_origin(), +// .is_delegate_call = false, +// .is_static_call = false, +// .is_contract_deployment = false, +// .reference_block_num = 0, +// }; + +// NativeOracle f_oracle(oracle.oracle.db, +// external_contract_address.get_value(), +// f_function_signature, +// f_call_context, +// oracle.get_msg_sender_private_key() +// .get_value() // TODO: consider whether a nested function should even be able to access +// a +// // private key, given that the call is now coming from a contract (which +// // cannot own a secret), rather than a human. +// ); +// OracleWrapperInterface f_oracle_wrapper(f_composer, f_oracle); + +// // We need an exec_ctx reference which won't go out of scope, so we store a shared_ptr to the newly created +// // exec_ctx in `this` exec_ctx. +// auto f_exec_ctx = std::make_shared>(f_composer, f_oracle_wrapper); + +// array_push(nested_private_call_exec_ctxs, f_exec_ctx); + +// auto native_args = to_nt(args); + +// // This calls the function `f`, passing the arguments shown. +// // The f_exec_ctx will be populated with all the information about that function's execution. +// std::apply(f, std::forward_as_tuple(*f_exec_ctx, native_args)); + +// // Remember: the data held in the f_exec_ctc was built with a different composer than that +// // of `this` exec_ctx. So we only allow ourselves to get the native types, so that we can consciously declare +// // circuit types for `this` exec_ctx using `this->composer`. +// auto& f_public_inputs_nt = f_exec_ctx->final_private_circuit_public_inputs; + +// // Since we've made a call to another function, we now need to push a call_stack_item_hash to `this` function's +// // private call stack. +// // Note: we need to constrain some of `this` circuit's variables against f's public inputs: +// // - args +// // - return_values +// // - call_context (TODO: maybe this only needs to be done in the kernel circuit). +// auto f_public_inputs_ct = f_public_inputs_nt.to_circuit_type(composer); + +// for (size_t i = 0; i < f_public_inputs_ct.args.size(); ++i) { +// args[i].assert_equal(f_public_inputs_ct.args[i]); +// } + +// auto call_stack_item_hash = f_public_inputs_ct.hash(); + +// array_push(private_circuit_public_inputs.private_call_stack, call_stack_item_hash); + +// // The return values are implicitly constrained by being returned as circuit types from this method, for +// // further use in the circuit. Note: ALL elements of the return_values array MUST be constrained, even if +// // they're placeholder zeroes. +// return f_public_inputs_ct.return_values; +// } + +// template void FunctionExecutionContext::finalise_utxos() +// { +// // Copy some vectors, as we can't control whether they'll be pushed-to further, when we call Note methods. +// auto new_nullifiers_copy = new_nullifiers; + +// size_t used_nullifiers_count = 0; +// fr next_nullifier; +// std::vector new_nonces; + +// // This is almost a visitor pattern. Call methods on each note. The note will choose what to do. +// for (size_t i = 0; i < new_notes.size(); ++i) { +// NoteInterface& note = *new_notes[i]; + +// if (note.needs_nonce()) { +// const bool next_nullifier_available = new_nullifiers_copy.size() > used_nullifiers_count; + +// if (next_nullifier_available) { +// next_nullifier = new_nullifiers_copy[used_nullifiers_count++]; +// note.set_nonce(next_nullifier); +// } else { +// const fr new_nonce = note.generate_nonce(); +// new_nonces.push_back(new_nonce); +// } +// } + +// new_commitments.push_back(note.get_commitment()); +// } + +// // Push new_nonces to the end of new_nullifiers: +// std::copy(new_nonces.begin(), new_nonces.end(), std::back_inserter(new_nullifiers)); +// } + +// template void FunctionExecutionContext::finalise() +// { +// finalise_utxos(); +// private_circuit_public_inputs.set_commitments(new_commitments); +// private_circuit_public_inputs.set_nullifiers(new_nullifiers); +// private_circuit_public_inputs.set_public(composer); +// final_private_circuit_public_inputs = +// private_circuit_public_inputs.remove_optionality().template to_native_type(); +// }; + +// } // namespace aztec3::circuits::apps \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/function_execution_context.hpp b/circuits/src/aztec3/circuits/apps/function_execution_context.hpp index b3aa99c5bc4..78dcb3049a1 100644 --- a/circuits/src/aztec3/circuits/apps/function_execution_context.hpp +++ b/circuits/src/aztec3/circuits/apps/function_execution_context.hpp @@ -8,6 +8,8 @@ #include "opcodes/opcodes.hpp" #include + +#include #include #include @@ -17,27 +19,23 @@ #include -// #include - -// #include "function_declaration.hpp" -// #include "l1_function_interface.hpp" - namespace aztec3::circuits::apps { +using aztec3::circuits::abis::CallStackItem; +using aztec3::circuits::abis::CallType; using aztec3::circuits::abis::FunctionSignature; using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; using aztec3::circuits::abis::PrivateCircuitPublicInputs; using aztec3::circuits::apps::notes::NoteInterface; - using aztec3::circuits::apps::opcodes::Opcodes; using aztec3::circuits::types::array_push; using plonk::stdlib::witness_t; using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::to_nt; using NT = plonk::stdlib::types::NativeTypes; +using plonk::stdlib::types::to_nt; template class FunctionExecutionContext { typedef NativeTypes NT; @@ -55,13 +53,12 @@ template class FunctionExecutionContext { Contract* contract = nullptr; - std::map>> nested_execution_contexts; + std::array>, PRIVATE_CALL_STACK_LENGTH> + nested_private_call_exec_ctxs; // TODO: make this private! OptionalPrivateCircuitPublicInputs private_circuit_public_inputs; - PrivateCircuitPublicInputs final_private_circuit_public_inputs; - private: std::vector>> new_notes; std::vector new_commitments; @@ -70,6 +67,10 @@ template class FunctionExecutionContext { std::vector>> nullified_notes; std::vector new_nullifiers; + PrivateCircuitPublicInputs final_private_circuit_public_inputs; + + bool is_finalised = false; + public: FunctionExecutionContext(Composer& composer, OracleWrapperInterface& oracle) : composer(composer) @@ -91,37 +92,115 @@ template class FunctionExecutionContext { // Not a reference, because we won't want to allow unsafe access. Hmmm, except it's a vector of pointers, so one can // still modify the pointers... But at least the original vector isn't being pushed-to or deleted-from. std::vector>> get_new_notes() { return new_notes; } + std::vector get_new_nullifiers() { return new_nullifiers; } void push_new_note(NoteInterface* const note_ptr) { new_notes.push_back(note_ptr); } void push_newly_nullified_note(NoteInterface* note_ptr) { nullified_notes.push_back(note_ptr); } - // Allows a call to be made to a function of another contract - template + PrivateCircuitPublicInputs get_final_private_circuit_public_inputs() + { + // For safety, only return this if the circuit is complete. + if (!is_finalised) { + throw_or_abort("You need to call exec_ctx.finalise() in your circuit first."); + } + return final_private_circuit_public_inputs; + } + + /** + * @brief Get the call_stack_item representing `this` exec_ctx's function call. + */ + CallStackItem get_call_stack_item() + { + const NT::address& actual_contract_address = oracle.native_oracle.get_actual_contract_address(); + const FunctionSignature& function_signature = oracle.native_oracle.get_function_signature(); + + return CallStackItem{ + .contract_address = actual_contract_address, + .function_signature = function_signature, + .public_inputs = get_final_private_circuit_public_inputs(), + }; + } + + /** + * @brief Get the call_stack_items of any nested function calls made by this exec_ctx's function. + */ + std::array, PRIVATE_CALL_STACK_LENGTH> get_private_call_stack_items() + { + std::array, PRIVATE_CALL_STACK_LENGTH> result; + + for (size_t i = 0; i < result.size(); ++i) { + auto& nested_exec_ctx = nested_private_call_exec_ctxs[i]; + if (nested_exec_ctx != nullptr) { + const NT::address& actual_contract_address = + nested_exec_ctx->oracle.native_oracle.get_actual_contract_address(); + const FunctionSignature& function_signature = + nested_exec_ctx->oracle.native_oracle.get_function_signature(); + + result[i] = CallStackItem{ + .contract_address = actual_contract_address, + .function_signature = function_signature, + .public_inputs = nested_exec_ctx->get_final_private_circuit_public_inputs(), + }; + } + } + + // TODO: do we need to instantiate-with-zeros the structs at the unused indices of `result`? + + return result; + } + + /** + * @brief Allows a call to be made to a function of another contract + */ std::array call( address const& external_contract_address, std::string const& external_function_name, std::function&, std::array)> f, std::array const& args) { - if (nested_execution_contexts.contains(external_function_name)) { - throw_or_abort("Choose a different string to represent the function being called"); - } Composer f_composer; - NativeOracle f_oracle(oracle.oracle.db, + + // Convert function name to bytes and use the first 4 bytes as the function encoding, for now: + std::vector f_name_bytes(external_function_name.begin(), external_function_name.end()); + std::vector f_encoding_bytes(f_name_bytes.begin(), f_name_bytes.begin() + 4); + uint32_t f_encoding; + memcpy(&f_encoding, f_encoding_bytes.data(), sizeof(f_encoding)); + + const FunctionSignature f_function_signature{ + .function_encoding = f_encoding, + .is_private = true, + .is_constructor = false, + }; + + const CallContext f_call_context{ + .msg_sender = oracle.get_this_contract_address().get_value(), // the sender is `this` contract! + .storage_contract_address = external_contract_address.get_value(), + .tx_origin = oracle.get_tx_origin().get_value(), + .is_delegate_call = false, + .is_static_call = false, + .is_contract_deployment = false, + .reference_block_num = 0, + }; + + NativeOracle f_oracle(oracle.native_oracle.db, external_contract_address.get_value(), - oracle.get_this_contract_address().get_value(), - oracle.get_tx_origin().get_value(), - oracle.get_msg_sender_private_key().get_value()); + f_function_signature, + f_call_context, + oracle.get_msg_sender_private_key() + .get_value() // TODO: consider whether a nested function should even be able to access + // a private key, given that the call is now coming from a contract + // (which cannot own a secret), rather than a human. + ); OracleWrapperInterface f_oracle_wrapper(f_composer, f_oracle); // We need an exec_ctx reference which won't go out of scope, so we store a shared_ptr to the newly created - // exec_ctx in `this` exec_ctx, and pass a reference to the function we're calling: - auto& f_exec_ctx = nested_execution_contexts[external_function_name]; + // exec_ctx in `this` exec_ctx. + auto f_exec_ctx = std::make_shared>(f_composer, f_oracle_wrapper); - f_exec_ctx = std::make_shared>(f_composer, f_oracle_wrapper); + array_push(nested_private_call_exec_ctxs, f_exec_ctx); auto native_args = to_nt(args); @@ -229,7 +308,7 @@ template class FunctionExecutionContext { private_circuit_public_inputs.set_public(composer); final_private_circuit_public_inputs = private_circuit_public_inputs.remove_optionality().template to_native_type(); - }; + } }; } // namespace aztec3::circuits::apps \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/oracle_wrapper.hpp b/circuits/src/aztec3/circuits/apps/oracle_wrapper.hpp index 254ec7e9e08..20edde26f45 100644 --- a/circuits/src/aztec3/circuits/apps/oracle_wrapper.hpp +++ b/circuits/src/aztec3/circuits/apps/oracle_wrapper.hpp @@ -31,20 +31,20 @@ template class OracleWrapperInterface { public: Composer& composer; - NativeOracle& oracle; + NativeOracle& native_oracle; // Initialise from Native. // Used when initialising for a user's first call. - OracleWrapperInterface(Composer& composer, NativeOracle& oracle) + OracleWrapperInterface(Composer& composer, NativeOracle& native_oracle) : composer(composer) - , oracle(oracle){}; + , native_oracle(native_oracle){}; fr& get_msg_sender_private_key() { if (msg_sender_private_key) { return *msg_sender_private_key; } - msg_sender_private_key = plonk::stdlib::types::to_ct(composer, oracle.get_msg_sender_private_key()); + msg_sender_private_key = plonk::stdlib::types::to_ct(composer, native_oracle.get_msg_sender_private_key()); validate_msg_sender_private_key(); return *msg_sender_private_key; }; @@ -56,7 +56,7 @@ template class OracleWrapperInterface { if (call_context) { return *call_context; } - call_context = oracle.get_call_context().to_circuit_type(composer); + call_context = native_oracle.get_call_context().to_circuit_type(composer); return *call_context; }; @@ -66,11 +66,11 @@ template class OracleWrapperInterface { address& get_tx_origin() { return get_call_context().tx_origin; }; - fr generate_salt() const { return plonk::stdlib::types::to_ct(composer, oracle.generate_salt()); } + fr generate_salt() const { return plonk::stdlib::types::to_ct(composer, native_oracle.generate_salt()); } fr generate_random_element() const { - return plonk::stdlib::types::to_ct(composer, oracle.generate_random_element()); + return plonk::stdlib::types::to_ct(composer, native_oracle.generate_random_element()); } template @@ -80,7 +80,7 @@ template class OracleWrapperInterface { auto native_advice = advice.template to_native_type(); - auto native_utxo_sload_datum = oracle.get_utxo_sload_datum(native_storage_slot_point, native_advice); + auto native_utxo_sload_datum = native_oracle.get_utxo_sload_datum(native_storage_slot_point, native_advice); return native_utxo_sload_datum.to_circuit_type(composer); } @@ -94,7 +94,8 @@ template class OracleWrapperInterface { auto native_advice = advice.template to_native_type(); - auto native_utxo_sload_data = oracle.get_utxo_sload_data(native_storage_slot_point, num_notes, native_advice); + auto native_utxo_sload_data = + native_oracle.get_utxo_sload_data(native_storage_slot_point, num_notes, native_advice); auto to_circuit_type = [&](auto& e) { return e.to_circuit_type(composer); }; diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp index 8557540be57..96dffa72fde 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp @@ -1,31 +1,61 @@ +#include "index.hpp" +#include "contract.hpp" + +// #include +// #include + +// #include + #include #include // #include // #include // #include -#include "index.hpp" -#include "contract.hpp" namespace aztec3::circuits::apps::test_apps::escrow { -class escrow_tests : public ::testing::Test {}; +class escrow_tests : public ::testing::Test { + protected: + FunctionExecutionContext get_test_exec_ctx() + { + C composer; + DB db; + + const NT::address contract_address = 12345; + const NT::fr msg_sender_private_key = 123456789; + const NT::address msg_sender = NT::fr( + uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); + + const FunctionSignature function_signature{ + .function_encoding = 1, // TODO: deduce this from the contract, somehow. + .is_private = true, + .is_constructor = false, + }; + + const CallContext call_context{ + .msg_sender = msg_sender, + .storage_contract_address = contract_address, + .tx_origin = msg_sender, + .is_delegate_call = false, + .is_static_call = false, + .is_contract_deployment = false, + .reference_block_num = 0, + }; + + NativeOracle oracle = + NativeOracle(db, contract_address, function_signature, call_context, msg_sender_private_key); + OracleWrapper oracle_wrapper = OracleWrapper(composer, oracle); + + FunctionExecutionContext exec_ctx(composer, oracle_wrapper); + + return exec_ctx; + }; +}; -TEST(escrow_tests, test_deposit) +TEST_F(escrow_tests, test_deposit) { - - C composer; - DB db; - - const NT::address contract_address = 12345; - const NT::fr msg_sender_private_key = 123456789; - const NT::address msg_sender = - NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); - const NT::address tx_origin = msg_sender; - - NativeOracle oracle = NativeOracle(db, contract_address, msg_sender, tx_origin, msg_sender_private_key); - OracleWrapper oracle_wrapper = OracleWrapper(composer, oracle); - - FunctionExecutionContext exec_ctx(composer, oracle_wrapper); + auto exec_ctx = get_test_exec_ctx(); + auto& composer = exec_ctx.composer; auto amount = NT::fr(5); auto asset_id = NT::fr(1); @@ -43,30 +73,10 @@ TEST(escrow_tests, test_deposit) info("n: ", composer.n); } -TEST(escrow_tests, test_transfer) +TEST_F(escrow_tests, test_transfer) { - - C composer; - DB db; - - const NT::address contract_address = 12345; - const NT::fr msg_sender_private_key = 123456789; - const NT::address msg_sender = - NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); - const NT::address tx_origin = msg_sender; - - CallContext call_context = { - .msg_sender = msg_sender, - .storage_contract_address = contract_address, - .tx_origin = msg_sender, - .is_delegate_call = false, - .is_static_call = false, - }; - - NativeOracle oracle = NativeOracle(db, call_context, msg_sender_private_key); - OracleWrapper oracle_wrapper = OracleWrapper(composer, oracle); - - FunctionExecutionContext exec_ctx(composer, oracle_wrapper); + auto exec_ctx = get_test_exec_ctx(); + auto& composer = exec_ctx.composer; auto amount = NT::fr(5); auto to = NT::address(657756); @@ -86,29 +96,10 @@ TEST(escrow_tests, test_transfer) info("n: ", composer.n); } -TEST(escrow_tests, test_withdraw) +TEST_F(escrow_tests, test_withdraw) { - - C composer; - DB db; - - const NT::address contract_address = 12345; - const NT::fr msg_sender_private_key = 123456789; - const NT::address msg_sender = - NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); - - CallContext call_context = { - .msg_sender = msg_sender, - .storage_contract_address = contract_address, - .tx_origin = msg_sender, - .is_delegate_call = false, - .is_static_call = false, - }; - - NativeOracle oracle = NativeOracle(db, call_context, msg_sender_private_key); - OracleWrapper oracle_wrapper = OracleWrapper(composer, oracle); - - FunctionExecutionContext exec_ctx(composer, oracle_wrapper); + auto exec_ctx = get_test_exec_ctx(); + auto& composer = exec_ctx.composer; auto amount = NT::fr(5); auto asset_id = NT::fr(1); diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp index ac64b0060f4..c855ea4c5bb 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp @@ -1,5 +1,10 @@ #include "index.hpp" +#include +#include + +// #include + #include #include @@ -17,9 +22,25 @@ TEST(private_to_private_function_call_tests, test_private_to_private_function_ca const NT::fr msg_sender_private_key = 123456789; const NT::address msg_sender = uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL); - const NT::address tx_origin = msg_sender; - NativeOracle fn1_oracle = NativeOracle(db, contract_address, msg_sender, tx_origin, msg_sender_private_key); + const FunctionSignature function_signature{ + .function_encoding = 1, // TODO: deduce this from the contract, somehow. + .is_private = true, + .is_constructor = false, + }; + + const CallContext call_context{ + .msg_sender = msg_sender, + .storage_contract_address = contract_address, + .tx_origin = msg_sender, + .is_delegate_call = false, + .is_static_call = false, + .is_contract_deployment = false, + .reference_block_num = 0, + }; + + NativeOracle fn1_oracle = + NativeOracle(db, contract_address, function_signature, call_context, msg_sender_private_key); OracleWrapper fn1_oracle_wrapper = OracleWrapper(fn1_composer, fn1_oracle); FunctionExecutionContext fn1_exec_ctx(fn1_composer, fn1_oracle_wrapper); @@ -30,7 +51,7 @@ TEST(private_to_private_function_call_tests, test_private_to_private_function_ca function_1_1(fn1_exec_ctx, { a, b, c, 0, 0, 0, 0, 0 }); - const auto& function_1_1_public_inputs = fn1_exec_ctx.final_private_circuit_public_inputs; + const auto& function_1_1_public_inputs = fn1_exec_ctx.get_final_private_circuit_public_inputs(); info("function_1_1_public_inputs: ", function_1_1_public_inputs); diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_1_1.cpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_1_1.cpp index 7686d15a6c3..553a48dea0d 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_1_1.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_1_1.cpp @@ -86,7 +86,7 @@ void function_1_1(FunctionExecutionContext& exec_ctx, std::array // #include #include "index.hpp" +#include "init.hpp" #include @@ -24,6 +25,8 @@ // #include // #include +#include + // #include #include @@ -86,8 +89,24 @@ TEST(private_kernel_tests, test_deposit) Composer deposit_composer; DB db; + FunctionSignature function_signature{ + .function_encoding = 1, // TODO: deduce this from the contract, somehow. + .is_private = true, + .is_constructor = false, + }; + + CallContext call_context{ + .msg_sender = msg_sender, + .storage_contract_address = escrow_contract_address, + .tx_origin = msg_sender, + .is_delegate_call = false, + .is_static_call = false, + .is_contract_deployment = false, + .reference_block_num = 0, + }; + NativeOracle deposit_oracle = - NativeOracle(db, escrow_contract_address, msg_sender, tx_origin, msg_sender_private_key); + NativeOracle(db, escrow_contract_address, function_signature, call_context, msg_sender_private_key); OracleWrapper deposit_oracle_wrapper = OracleWrapper(deposit_composer, deposit_oracle); FunctionExecutionContext deposit_ctx(deposit_composer, deposit_oracle_wrapper); @@ -113,12 +132,7 @@ TEST(private_kernel_tests, test_deposit) TxObject deposit_tx_object = TxObject{ .from = tx_origin, .to = escrow_contract_address, - .function_signature = - FunctionSignature{ - .vk_index = 0, // TODO: deduce this from the contract, somehow. - .is_private = true, - .is_constructor = false, - }, + .function_signature = function_signature, .args = deposit_public_inputs.args, .nonce = 0, .tx_context = @@ -203,10 +217,6 @@ TEST(private_kernel_tests, test_deposit) Composer private_kernel_composer; - // TODO: I think we need a different kind of oracle for the kernel circuits... - NativeOracle private_kernel_oracle = NativeOracle(db, escrow_contract_address, msg_sender, msg_sender_private_key); - OracleWrapper private_kernel_oracle_wrapper = OracleWrapper(private_kernel_composer, private_kernel_oracle); - PrivateInputs private_inputs = PrivateInputs{ .signed_tx_object = signed_deposit_tx_object, @@ -220,7 +230,7 @@ TEST(private_kernel_tests, test_deposit) .private_call = PrivateCallData{ .call_stack_item = deposit_call_stack_item, - // .call_context_reconciliation_data = TODO + .private_call_stack_preimages = deposit_ctx.get_private_call_stack_items(), .proof = deposit_proof, .vk = deposit_vk, @@ -234,7 +244,7 @@ TEST(private_kernel_tests, test_deposit) }, }; - private_kernel_circuit(private_kernel_composer, private_kernel_oracle_wrapper, private_inputs); + private_kernel_circuit(private_kernel_composer, private_inputs); info("computed witness: ", private_kernel_composer.computed_witness); info("witness: ", private_kernel_composer.witness); diff --git a/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp b/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp index 0f6f1921c27..6ac465a2650 100644 --- a/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp +++ b/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp @@ -38,12 +38,13 @@ void initialise_end_values(PrivateInputs const& private_inputs, PublicInputs { public_inputs.constants = private_inputs.previous_kernel.public_inputs.constants; - // Ensure the arrays are the same as previously, before we start pushing more data onto them: + // Ensure the arrays are the same as previously, before we start pushing more data onto them in other functions + // within this circuit: auto& end = public_inputs.end; const auto& start = private_inputs.previous_kernel.public_inputs.end; - end.output_commitments = start.output_commitments; - end.input_nullifiers = start.input_nullifiers; + end.new_commitments = start.new_commitments; + end.new_nullifiers = start.new_nullifiers; end.private_call_stack = start.private_call_stack; end.public_call_stack = start.public_call_stack; @@ -56,38 +57,38 @@ void update_end_values(PrivateInputs const& private_inputs, PublicInputs { const auto private_call_public_inputs = private_inputs.private_call.call_stack_item.public_inputs; - const auto& output_commitments = private_call_public_inputs.output_commitments; - const auto& input_nullifiers = private_call_public_inputs.input_nullifiers; + const auto& new_commitments = private_call_public_inputs.new_commitments; + const auto& new_nullifiers = private_call_public_inputs.new_nullifiers; const auto& is_static_call = private_inputs.private_call.call_stack_item.public_inputs.call_context.is_static_call; // No state changes are allowed for static calls: - is_static_call.must_imply(is_array_empty(output_commitments) == true); - is_static_call.must_imply(is_array_empty(input_nullifiers) == true); + is_static_call.must_imply(is_array_empty(new_commitments) == true); + is_static_call.must_imply(is_array_empty(new_nullifiers) == true); const auto& storage_contract_address = private_inputs.private_call.call_stack_item.public_inputs.call_context.storage_contract_address; { // commitments & nullifiers - std::array siloed_output_commitments; - for (size_t i = 0; i < output_commitments.size(); ++i) { - siloed_output_commitments[i] = - CT::fr::conditional_assign(output_commitments[i] == 0, + std::array siloed_new_commitments; + for (size_t i = 0; i < new_commitments.size(); ++i) { + siloed_new_commitments[i] = + CT::fr::conditional_assign(new_commitments[i] == 0, 0, - CT::compress({ storage_contract_address.to_field(), output_commitments[i] }, + CT::compress({ storage_contract_address.to_field(), new_commitments[i] }, GeneratorIndex::OUTER_COMMITMENT)); } - std::array siloed_input_nullifiers; - for (size_t i = 0; i < input_nullifiers.size(); ++i) { - siloed_input_nullifiers[i] = - CT::fr::conditional_assign(input_nullifiers[i] == 0, + std::array siloed_new_nullifiers; + for (size_t i = 0; i < new_nullifiers.size(); ++i) { + siloed_new_nullifiers[i] = + CT::fr::conditional_assign(new_nullifiers[i] == 0, 0, - CT::compress({ storage_contract_address.to_field(), input_nullifiers[i] }, + CT::compress({ storage_contract_address.to_field(), new_nullifiers[i] }, GeneratorIndex::OUTER_NULLIFIER)); } - push_array_to_array(siloed_output_commitments, public_inputs.end.output_commitments); - push_array_to_array(siloed_input_nullifiers, public_inputs.end.input_nullifiers); + push_array_to_array(siloed_new_commitments, public_inputs.end.new_commitments); + push_array_to_array(siloed_new_nullifiers, public_inputs.end.new_nullifiers); } { @@ -101,10 +102,6 @@ void update_end_values(PrivateInputs const& private_inputs, PublicInputs // - Commitment and nullifier preimages // - Hash paths and leaf indices // - Any and all preimage data derived by the circuit or through oracle calls. - - // Update on this topic: I've created call_context_reconciliation_data, which allows the call_context to - // be efficiently unpacked from a call_stack_item_hash. We'll need some "functions calling functions" - // tests cases to see how best to move this data around neatly. } const auto& portal_contract_address = private_inputs.private_call.portal_contract_address; @@ -150,54 +147,52 @@ void validate_inputs(PrivateInputs const& private_inputs) // Base Case { - // Validate callstack lengths: - is_base_case.must_imply( - start_private_call_stack_length == - 1 // TODO: might change to allow 3, so a fee can be paid and a gas rebate can be paid. - && start_public_call_stack_length == 0 && start_l1_msg_stack_length == 0, - "Invalid callstacks for base case."); - - is_base_case.must_imply(next_call.public_inputs.call_context.is_delegate_call == false && - next_call.public_inputs.call_context.is_static_call == false, - "A user cannot make a delegatecall or staticcall"); - - // The below also prevents delegatecall/staticcall - is_base_case.must_imply(next_call.public_inputs.call_context.storage_contract_address == - next_call.contract_address, - "Storage contract address must be that of the called contract in the base case"); + std::vector> base_case_conditions{ + { start_private_call_stack_length == 1, + "Private call stack must be length 1" }, // TODO: might change to allow 3, so a fee can be paid and a gas + // rebate can be paid. + { start_public_call_stack_length == 0, "Public call stack must be empty" }, + { start_l1_msg_stack_length == 0, "L1 msg stack must be empty" }, + + { next_call.public_inputs.call_context.is_delegate_call == false, "Users cannot make a delegatecall" }, + { next_call.public_inputs.call_context.is_static_call == false, "Users cannot make a static call" }, + + // The below also prevents delegatecall/staticcall in the base case + { next_call.public_inputs.call_context.storage_contract_address == next_call.contract_address, + "Storage contract address must be that of the called contract" } + }; + + is_base_case.must_imply(base_case_conditions); } // Recursive Case { - is_recursive_case.must_imply(private_inputs.previous_kernel.public_inputs.is_private == true, - "Cannot verify a non-private kernel snark in the private kernel circuit"); - - is_recursive_case.must_imply(next_call.function_signature.is_constructor == false, - "A constructor must be executed as the first tx in the recursion"); - - is_recursive_case.must_imply(start_private_call_stack_length != 0); + std::vector> recursive_case_conditions{ + { private_inputs.previous_kernel.public_inputs.is_private == true, + "Cannot verify a non-private kernel snark in the private kernel circuit" }, + { next_call.function_signature.is_constructor == false, + "A constructor must be executed as the first tx in the recursion" }, + { start_private_call_stack_length != 0, + "Cannot execute private kernel circuit with an empty private call stack" } + }; + + is_recursive_case.must_imply(recursive_case_conditions); } validate_private_call_hash(private_inputs); } +// NOTE: THIS IS A VERY UNFINISHED WORK IN PROGRESS. // TODO: decide what to return. // TODO: is there a way to identify whether an input has not been used by ths circuit? This would help us more-safely // ensure we're constraining everything. -void private_kernel_circuit(Composer& composer, OracleWrapper& oracle, PrivateInputs const& _private_inputs) +void private_kernel_circuit(Composer& composer, PrivateInputs const& _private_inputs) { - (void)oracle; // To avoid unused variable compiler errors whilst building. - const PrivateInputs private_inputs = _private_inputs.to_circuit_type(composer); // We'll be pushing data to this during execution of this circuit. PublicInputs public_inputs{}; - // const auto& start = private_inputs.previous_kernel.public_inputs.end; - - // const CT::boolean is_base_case = start.private_call_count == 0; - // const CT::boolean is_recursive_case = !is_base_case; - validate_inputs(private_inputs); initialise_end_values(private_inputs, public_inputs); diff --git a/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.hpp b/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.hpp index 4b6f6b4b3b3..b0f33e89a66 100644 --- a/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.hpp +++ b/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.hpp @@ -11,6 +11,6 @@ using aztec3::circuits::abis::private_kernel::PrivateInputs; // using abis::private_kernel::PublicInputs; // TODO: decide what to return. -void private_kernel_circuit(Composer& composer, OracleWrapper& oracle, PrivateInputs const& _private_inputs); +void private_kernel_circuit(Composer& composer, PrivateInputs const& _private_inputs); } // namespace aztec3::circuits::kernel::private_kernel \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/types/array.hpp b/circuits/src/aztec3/circuits/types/array.hpp index 20bac55f209..1df42bd7bb4 100644 --- a/circuits/src/aztec3/circuits/types/array.hpp +++ b/circuits/src/aztec3/circuits/types/array.hpp @@ -50,6 +50,8 @@ typename CircuitTypes::fr array_pop(std::array::fr, SIZE>& arr, already_pushed |= is_zero; } + already_pushed.assert_equal(true, "Cannot push to a full array"); }; template -inline void array_push(std::array::fr>, SIZE>& arr, - typename CircuitTypes::fr const& value) +inline size_t array_push(std::array::fr>, SIZE>& arr, + typename CircuitTypes::fr const& value) { for (size_t i = 0; i < arr.size(); ++i) { if (arr[i] == std::nullopt) { arr[i] = value; - return; + return i; + } + } + throw_or_abort("Cannot push to a full array"); +}; + +template +inline size_t array_push(std::array, SIZE>& arr, std::shared_ptr const& value) +{ + for (size_t i = 0; i < arr.size(); ++i) { + if (arr[i] == nullptr) { + arr[i] = value; + return i; } } + throw_or_abort("Cannot push to a full array"); }; /** diff --git a/circuits/src/aztec3/constants.hpp b/circuits/src/aztec3/constants.hpp index 42c3e402da1..ed17a672101 100644 --- a/circuits/src/aztec3/constants.hpp +++ b/circuits/src/aztec3/constants.hpp @@ -7,23 +7,21 @@ constexpr size_t ARGS_LENGTH = 8; constexpr size_t RETURN_VALUES_LENGTH = 4; constexpr size_t EMITTED_EVENTS_LENGTH = 4; -constexpr size_t OUTPUT_COMMITMENTS_LENGTH = 4; -constexpr size_t INPUT_NULLIFIERS_LENGTH = 4; +constexpr size_t NEW_COMMITMENTS_LENGTH = 4; +constexpr size_t NEW_NULLIFIERS_LENGTH = 4; constexpr size_t STATE_TRANSITIONS_LENGTH = 4; constexpr size_t STATE_READS_LENGTH = 4; constexpr size_t PRIVATE_CALL_STACK_LENGTH = 4; constexpr size_t PUBLIC_CALL_STACK_LENGTH = 4; -constexpr size_t CONTRACT_DEPLOYMENT_CALL_STACK_LENGTH = 2; constexpr size_t L1_MSG_STACK_LENGTH = 2; -constexpr size_t KERNEL_OUTPUT_COMMITMENTS_LENGTH = 16; -constexpr size_t KERNEL_INPUT_NULLIFIERS_LENGTH = 16; +constexpr size_t KERNEL_NEW_COMMITMENTS_LENGTH = 16; +constexpr size_t KERNEL_NEW_NULLIFIERS_LENGTH = 16; constexpr size_t KERNEL_PRIVATE_CALL_STACK_LENGTH = 8; constexpr size_t KERNEL_PUBLIC_CALL_STACK_LENGTH = 8; -constexpr size_t KERNEL_CONTRACT_DEPLOYMENT_CALL_STACK_LENGTH = 4; -constexpr size_t KERNEL_L1_CALL_STACK_LENGTH = 4; +constexpr size_t KERNEL_L1_MSG_STACK_LENGTH = 4; constexpr size_t KERNEL_OPTIONALLY_REVEALED_DATA_LENGTH = 4; constexpr size_t VK_TREE_HEIGHT = 3; diff --git a/circuits/src/aztec3/oracle/oracle.hpp b/circuits/src/aztec3/oracle/oracle.hpp index cbe82604ae4..bf100facf08 100644 --- a/circuits/src/aztec3/oracle/oracle.hpp +++ b/circuits/src/aztec3/oracle/oracle.hpp @@ -3,6 +3,7 @@ #include "fake_db.hpp" #include +#include #include @@ -14,12 +15,10 @@ namespace aztec3::oracle { using aztec3::circuits::abis::CallContext; +using aztec3::circuits::abis::FunctionSignature; using aztec3::circuits::apps::UTXOSLoadDatum; -using aztec3::circuits::apps::notes::DefaultPrivateNotePreimage; -using aztec3::circuits::apps::notes::DefaultSingletonPrivateNotePreimage; - using plonk::stdlib::types::CircuitTypes; using NT = plonk::stdlib::types::NativeTypes; @@ -30,50 +29,13 @@ template class NativeOracleInterface { DB& db; NativeOracleInterface(DB& db, - NT::fr const& contract_address, - // NT::fr const& portal_contract_address, - NT::address const& msg_sender, - NT::address const& tx_origin, - NT::boolean const& is_delegate_call = false, - NT::boolean const& is_static_call = false, - NT::fr const& reference_block_num = 0) - : db(db) - , call_context({ - .msg_sender = msg_sender, - .storage_contract_address = contract_address, - .tx_origin = tx_origin, - .is_delegate_call = is_delegate_call, - .is_static_call = is_static_call, - .reference_block_num = reference_block_num, - }) - // , portal_contract_address(portal_contract_address) - {}; - - // Include the msg_sender_private_key - NativeOracleInterface(DB& db, - NT::fr const& contract_address, - // NT::fr const& portal_contract_address, - NT::address const& msg_sender, - NT::address const& tx_origin, - std::optional msg_sender_private_key, - NT::boolean const& is_delegate_call = false, - NT::boolean const& is_static_call = false, - NT::fr const& reference_block_num = 0) - : db(db) - , call_context({ - .msg_sender = msg_sender, - .storage_contract_address = contract_address, - .tx_origin = tx_origin, - .is_delegate_call = is_delegate_call, - .is_static_call = is_static_call, - .reference_block_num = reference_block_num, - }) - // , portal_contract_address(portal_contract_address) - , msg_sender_private_key(msg_sender_private_key){}; - - // CallContext as struct - NativeOracleInterface(DB& db, CallContext call_context, std::optional msg_sender_private_key) + NT::address const& actual_contract_address, + FunctionSignature function_signature, + CallContext const& call_context, + std::optional const& msg_sender_private_key = std::nullopt) : db(db) + , actual_contract_address(actual_contract_address) + , function_signature(function_signature) , call_context(call_context) // , portal_contract_address(portal_contract_address) , msg_sender_private_key(msg_sender_private_key){}; @@ -99,6 +61,10 @@ template class NativeOracleInterface { // return portal_contract_address; // }; + NT::address get_actual_contract_address() { return actual_contract_address; }; + + FunctionSignature get_function_signature() { return function_signature; }; + CallContext get_call_context() { if (call_context_already_got) { @@ -137,12 +103,18 @@ template class NativeOracleInterface { // untrustworthy oracle could give two different pieces of information. As long as this (trusted) oracle catches // double-queries, we can ensure the circuit we build doesn't query twice. - // A circuit doesn't know its own address, so we need to track the address from 'outside'. + // Note: actual_contract_address and function_signature are NOT to be provided to the circuit, so don't include + // getter methods for these in the OracleWrapper. + NT::address actual_contract_address; // not to be confused with call_context.storage_contract_address; + FunctionSignature function_signature; + CallContext call_context; // NT::fr portal_contract_address; std::optional msg_sender_private_key; // Ensure functions called only once: + bool actual_contract_address_already_got = false; + bool function_signature_already_got = false; bool call_context_already_got = false; // bool portal_contract_address_already_got = false; bool msg_sender_private_key_already_got = false; From a8cefd2a4b67874bbe25d51e78af38efcd5c889d Mon Sep 17 00:00:00 2001 From: iAmMichaelConnor Date: Fri, 13 Jan 2023 10:27:58 +0000 Subject: [PATCH 030/166] fix: test fixture functions caused dangling references --- circuits/src/aztec3/circuits/apps/.test.cpp | 79 +++++++++++-------- .../apps/function_execution_context.hpp | 6 +- .../circuits/apps/test_apps/escrow/.test.cpp | 42 +++++----- .../function_1_1.cpp | 6 -- circuits/src/aztec3/oracle/oracle.hpp | 2 +- 5 files changed, 74 insertions(+), 61 deletions(-) diff --git a/circuits/src/aztec3/circuits/apps/.test.cpp b/circuits/src/aztec3/circuits/apps/.test.cpp index 96cfef310cd..894a202c34f 100644 --- a/circuits/src/aztec3/circuits/apps/.test.cpp +++ b/circuits/src/aztec3/circuits/apps/.test.cpp @@ -88,16 +88,12 @@ namespace aztec3::circuits::apps { class state_var_tests : public ::testing::Test { protected: - FunctionExecutionContext get_test_exec_ctx() + NativeOracle get_test_native_oracle(DB& db) { - C composer; - DB db; - const NT::address contract_address = 12345; const NT::fr msg_sender_private_key = 123456789; const NT::address msg_sender = NT::fr( uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); - const NT::address tx_origin = msg_sender; FunctionSignature function_signature{ .function_encoding = 1, // TODO: deduce this from the contract, somehow. @@ -115,20 +111,21 @@ class state_var_tests : public ::testing::Test { .reference_block_num = 0, }; - NativeOracle oracle = - NativeOracle(db, contract_address, function_signature, call_context, msg_sender_private_key); - OracleWrapper oracle_wrapper = OracleWrapper(composer, oracle); - - FunctionExecutionContext exec_ctx(composer, oracle_wrapper); - - return exec_ctx; + return NativeOracle(db, contract_address, function_signature, call_context, msg_sender_private_key); }; }; TEST_F(state_var_tests, mapping) { - auto exec_ctx = get_test_exec_ctx(); - auto& composer = exec_ctx.composer; + // TODO: currently, we can't hide all of this boilerplate in a test fixture function, because each of these classes + // contains a reference to earlier-declared classes... so we'd end up with classes containing dangling references, + // if all this stuff were to be declared in a setup function's scope. + // We could instead store shared_ptrs in every class...? + C composer; + DB db; + NativeOracle native_oracle = get_test_native_oracle(db); + OracleWrapper oracle_wrapper = OracleWrapper(composer, native_oracle); + FunctionExecutionContext exec_ctx(composer, oracle_wrapper); // TODO: // Interestingly, if I scope the below, the debugger works, but running the test via the command line fails. This is @@ -156,8 +153,11 @@ TEST_F(state_var_tests, mapping) TEST_F(state_var_tests, mapping_within_mapping) { - auto exec_ctx = get_test_exec_ctx(); - // auto& composer = exec_ctx.composer; + C composer; + DB db; + NativeOracle native_oracle = get_test_native_oracle(db); + OracleWrapper oracle_wrapper = OracleWrapper(composer, native_oracle); + FunctionExecutionContext exec_ctx(composer, oracle_wrapper); // { ::Contract contract("TestContract"); @@ -175,8 +175,11 @@ TEST_F(state_var_tests, mapping_within_mapping) TEST_F(state_var_tests, partial_mapping) { - auto exec_ctx = get_test_exec_ctx(); - // auto& composer = exec_ctx.composer; + C composer; + DB db; + NativeOracle native_oracle = get_test_native_oracle(db); + OracleWrapper oracle_wrapper = OracleWrapper(composer, native_oracle); + FunctionExecutionContext exec_ctx(composer, oracle_wrapper); // { ::Contract contract("TestContract"); @@ -194,9 +197,11 @@ TEST_F(state_var_tests, partial_mapping) TEST_F(state_var_tests, utxo_of_default_private_note_fr) { - auto exec_ctx = get_test_exec_ctx(); - // auto& composer = exec_ctx.composer; - auto& oracle = exec_ctx.oracle; + C composer; + DB db; + NativeOracle native_oracle = get_test_native_oracle(db); + OracleWrapper oracle_wrapper = OracleWrapper(composer, native_oracle); + FunctionExecutionContext exec_ctx(composer, oracle_wrapper); ::Contract contract("TestContract"); exec_ctx.register_contract(&contract); @@ -209,7 +214,7 @@ TEST_F(state_var_tests, utxo_of_default_private_note_fr) UTXO my_utxo(&exec_ctx, "my_utxo"); - const auto& msg_sender = oracle.get_msg_sender(); + const auto& msg_sender = oracle_wrapper.get_msg_sender(); Note old_note = my_utxo.get({ .owner = msg_sender }); @@ -239,9 +244,11 @@ TEST_F(state_var_tests, utxo_of_default_private_note_fr) TEST_F(state_var_tests, utxo_set_of_default_private_notes_fr) { - auto exec_ctx = get_test_exec_ctx(); - // auto& composer = exec_ctx.composer; - auto& oracle = exec_ctx.oracle; + C composer; + DB db; + NativeOracle native_oracle = get_test_native_oracle(db); + OracleWrapper oracle_wrapper = OracleWrapper(composer, native_oracle); + FunctionExecutionContext exec_ctx(composer, oracle_wrapper); // bool sort(NT::uint256 i, NT::uint256 j) // { @@ -263,7 +270,7 @@ TEST_F(state_var_tests, utxo_set_of_default_private_notes_fr) CT::fr amount = 5; CT::address to_address = 765976; - const auto& msg_sender = oracle.get_msg_sender(); + const auto& msg_sender = oracle_wrapper.get_msg_sender(); std::vector old_balance_notes = balances.get(2, { .owner = msg_sender }); @@ -299,9 +306,11 @@ TEST_F(state_var_tests, utxo_set_of_default_private_notes_fr) TEST_F(state_var_tests, initialise_utxo_of_default_singleton_private_note_fr) { - auto exec_ctx = get_test_exec_ctx(); - // auto& composer = exec_ctx.composer; - auto& oracle = exec_ctx.oracle; + C composer; + DB db; + NativeOracle native_oracle = get_test_native_oracle(db); + OracleWrapper oracle_wrapper = OracleWrapper(composer, native_oracle); + FunctionExecutionContext exec_ctx(composer, oracle_wrapper); ::Contract contract("TestContract"); exec_ctx.register_contract(&contract); @@ -321,7 +330,7 @@ TEST_F(state_var_tests, initialise_utxo_of_default_singleton_private_note_fr) const CT::address unique_person_who_may_initialise = NT::uint256(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL); - unique_person_who_may_initialise.assert_equal(oracle.get_msg_sender()); + unique_person_who_may_initialise.assert_equal(oracle_wrapper.get_msg_sender()); // The person who may initialise the note might be different from the person who's actually given the note to own. // (E.g. the caller of this function might be the deployer of the contract, who is initialising notes on behalf of @@ -345,9 +354,11 @@ TEST_F(state_var_tests, initialise_utxo_of_default_singleton_private_note_fr) TEST_F(state_var_tests, modify_utxo_of_default_singleton_private_note_fr) { - auto exec_ctx = get_test_exec_ctx(); - // auto& composer = exec_ctx.composer; - auto& oracle = exec_ctx.oracle; + C composer; + DB db; + NativeOracle native_oracle = get_test_native_oracle(db); + OracleWrapper oracle_wrapper = OracleWrapper(composer, native_oracle); + FunctionExecutionContext exec_ctx(composer, oracle_wrapper); ::Contract contract("TestContract"); exec_ctx.register_contract(&contract); @@ -362,7 +373,7 @@ TEST_F(state_var_tests, modify_utxo_of_default_singleton_private_note_fr) UTXO my_utxo(&exec_ctx, "my_utxo"); - const auto& msg_sender = oracle.get_msg_sender(); + const auto& msg_sender = oracle_wrapper.get_msg_sender(); Note old_note = my_utxo.get({ .owner = msg_sender }); diff --git a/circuits/src/aztec3/circuits/apps/function_execution_context.hpp b/circuits/src/aztec3/circuits/apps/function_execution_context.hpp index 78dcb3049a1..d2647488888 100644 --- a/circuits/src/aztec3/circuits/apps/function_execution_context.hpp +++ b/circuits/src/aztec3/circuits/apps/function_execution_context.hpp @@ -153,6 +153,9 @@ template class FunctionExecutionContext { /** * @brief Allows a call to be made to a function of another contract + * + * TODO: maybe we want to move some of the code that's in this function into a method in the Opcodes class. Although + * that class was really shoehorned into existence, and is a bit bleurgh. */ std::array call( address const& external_contract_address, @@ -211,7 +214,7 @@ template class FunctionExecutionContext { // Remember: the data held in the f_exec_ctc was built with a different composer than that // of `this` exec_ctx. So we only allow ourselves to get the native types, so that we can consciously declare // circuit types for `this` exec_ctx using `this->composer`. - auto& f_public_inputs_nt = f_exec_ctx->final_private_circuit_public_inputs; + auto f_public_inputs_nt = f_exec_ctx->get_final_private_circuit_public_inputs(); // Since we've made a call to another function, we now need to push a call_stack_item_hash to `this` function's // private call stack. @@ -308,6 +311,7 @@ template class FunctionExecutionContext { private_circuit_public_inputs.set_public(composer); final_private_circuit_public_inputs = private_circuit_public_inputs.remove_optionality().template to_native_type(); + is_finalised = true; } }; diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp index 96dffa72fde..ec2cc6520f0 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp @@ -16,23 +16,20 @@ namespace aztec3::circuits::apps::test_apps::escrow { class escrow_tests : public ::testing::Test { protected: - FunctionExecutionContext get_test_exec_ctx() + NativeOracle get_test_native_oracle(DB& db) { - C composer; - DB db; - const NT::address contract_address = 12345; const NT::fr msg_sender_private_key = 123456789; const NT::address msg_sender = NT::fr( uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); - const FunctionSignature function_signature{ + FunctionSignature function_signature{ .function_encoding = 1, // TODO: deduce this from the contract, somehow. .is_private = true, .is_constructor = false, }; - const CallContext call_context{ + CallContext call_context{ .msg_sender = msg_sender, .storage_contract_address = contract_address, .tx_origin = msg_sender, @@ -42,20 +39,21 @@ class escrow_tests : public ::testing::Test { .reference_block_num = 0, }; - NativeOracle oracle = - NativeOracle(db, contract_address, function_signature, call_context, msg_sender_private_key); - OracleWrapper oracle_wrapper = OracleWrapper(composer, oracle); - - FunctionExecutionContext exec_ctx(composer, oracle_wrapper); - - return exec_ctx; + return NativeOracle(db, contract_address, function_signature, call_context, msg_sender_private_key); }; }; TEST_F(escrow_tests, test_deposit) { - auto exec_ctx = get_test_exec_ctx(); - auto& composer = exec_ctx.composer; + // TODO: currently, we can't hide all of this boilerplate in a test fixture function, because each of these classes + // contains a reference to earlier-declared classes... so we'd end up with classes containing dangling references, + // if all this stuff were to be declared in a setup function's scope. + // We could instead store shared_ptrs in every class...? + C composer; + DB db; + NativeOracle native_oracle = get_test_native_oracle(db); + OracleWrapper oracle_wrapper = OracleWrapper(composer, native_oracle); + FunctionExecutionContext exec_ctx(composer, oracle_wrapper); auto amount = NT::fr(5); auto asset_id = NT::fr(1); @@ -75,8 +73,11 @@ TEST_F(escrow_tests, test_deposit) TEST_F(escrow_tests, test_transfer) { - auto exec_ctx = get_test_exec_ctx(); - auto& composer = exec_ctx.composer; + C composer; + DB db; + NativeOracle native_oracle = get_test_native_oracle(db); + OracleWrapper oracle_wrapper = OracleWrapper(composer, native_oracle); + FunctionExecutionContext exec_ctx(composer, oracle_wrapper); auto amount = NT::fr(5); auto to = NT::address(657756); @@ -98,8 +99,11 @@ TEST_F(escrow_tests, test_transfer) TEST_F(escrow_tests, test_withdraw) { - auto exec_ctx = get_test_exec_ctx(); - auto& composer = exec_ctx.composer; + C composer; + DB db; + NativeOracle native_oracle = get_test_native_oracle(db); + OracleWrapper oracle_wrapper = OracleWrapper(composer, native_oracle); + FunctionExecutionContext exec_ctx(composer, oracle_wrapper); auto amount = NT::fr(5); auto asset_id = NT::fr(1); diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_1_1.cpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_1_1.cpp index 553a48dea0d..7e1b26f61c9 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_1_1.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_1_1.cpp @@ -82,13 +82,7 @@ void function_1_1(FunctionExecutionContext& exec_ctx, std::array class NativeOracleInterface { NativeOracleInterface(DB& db, NT::address const& actual_contract_address, - FunctionSignature function_signature, + FunctionSignature const& function_signature, CallContext const& call_context, std::optional const& msg_sender_private_key = std::nullopt) : db(db) From 52f8d5c326c55f793552cd712b1b056ec69a7f3e Mon Sep 17 00:00:00 2001 From: iAmMichaelConnor Date: Fri, 13 Jan 2023 14:34:44 +0000 Subject: [PATCH 031/166] convert constant to fixed witness --- .../aztec3/circuits/abis/call_stack_item.hpp | 7 ++- .../circuits/abis/function_signature.hpp | 14 +++++ .../apps/function_execution_context.hpp | 52 +++++++++++++------ 3 files changed, 55 insertions(+), 18 deletions(-) diff --git a/circuits/src/aztec3/circuits/abis/call_stack_item.hpp b/circuits/src/aztec3/circuits/abis/call_stack_item.hpp index 0166c3c7ef8..c32f9a79b48 100644 --- a/circuits/src/aztec3/circuits/abis/call_stack_item.hpp +++ b/circuits/src/aztec3/circuits/abis/call_stack_item.hpp @@ -30,7 +30,12 @@ template struct CallStackItem { using PublicInputs = typename std:: conditional, PrivateCircuitPublicInputs>::type; - address contract_address; + address + contract_address; // This is the _actual_ contract address relating to where this function's code resides in the + // contract tree. Regardless of whether this is a call or delegatecall, this + // `contract_address` _does not change_. Amongst other things, it's used as a lookup for + // getting the correct code from the tree. There is a separate `storage_contract_address` + // within a CallStackItem which varies depending on whether this is a call or delegatecall. FunctionSignature function_signature; PublicInputs public_inputs; diff --git a/circuits/src/aztec3/circuits/abis/function_signature.hpp b/circuits/src/aztec3/circuits/abis/function_signature.hpp index 7d53d37a002..069f9eda68a 100644 --- a/circuits/src/aztec3/circuits/abis/function_signature.hpp +++ b/circuits/src/aztec3/circuits/abis/function_signature.hpp @@ -44,6 +44,20 @@ template struct FunctionSignature { return function_signature; }; + template FunctionSignature to_native_type() const + { + static_assert(std::is_same, NCT>::value); + auto to_nt = [&](auto& e) { return plonk::stdlib::types::to_nt(e); }; + + FunctionSignature fs = { + to_nt(function_encoding), + to_nt(is_private), + to_nt(is_constructor), + }; + + return fs; + }; + void set_public() { static_assert(!(std::is_same::value)); diff --git a/circuits/src/aztec3/circuits/apps/function_execution_context.hpp b/circuits/src/aztec3/circuits/apps/function_execution_context.hpp index d2647488888..9ba270bfd5f 100644 --- a/circuits/src/aztec3/circuits/apps/function_execution_context.hpp +++ b/circuits/src/aztec3/circuits/apps/function_execution_context.hpp @@ -35,6 +35,7 @@ using aztec3::circuits::types::array_push; using plonk::stdlib::witness_t; using plonk::stdlib::types::CircuitTypes; using NT = plonk::stdlib::types::NativeTypes; +using plonk::stdlib::types::to_ct; using plonk::stdlib::types::to_nt; template class FunctionExecutionContext { @@ -158,30 +159,37 @@ template class FunctionExecutionContext { * that class was really shoehorned into existence, and is a bit bleurgh. */ std::array call( - address const& external_contract_address, - std::string const& external_function_name, + address const& f_contract_address, + std::string const& f_name, std::function&, std::array)> f, std::array const& args) { - - Composer f_composer; - // Convert function name to bytes and use the first 4 bytes as the function encoding, for now: - std::vector f_name_bytes(external_function_name.begin(), external_function_name.end()); + std::vector f_name_bytes(f_name.begin(), f_name.end()); std::vector f_encoding_bytes(f_name_bytes.begin(), f_name_bytes.begin() + 4); uint32_t f_encoding; memcpy(&f_encoding, f_encoding_bytes.data(), sizeof(f_encoding)); - const FunctionSignature f_function_signature{ - .function_encoding = f_encoding, + fr f_encoding_ct = fr(f_encoding); + // Important Note: we MUST constrain this function_encoding value against a fixed selector value. Without the + // below line, an attacker could pass any f_encoding as a witness. + f_encoding_ct.convert_constant_to_fixed_witness(&composer); + + /// @dev The above constraining could alternatively be achieved as follows: + // fr alternative_f_encoding_ct = fr(to_ct(composer, f_encoding)); + // alternative_f_encoding_ct.fix_witness(); + + const FunctionSignature f_function_signature_ct{ + // Note: we MUST + .function_encoding = f_encoding_ct, .is_private = true, .is_constructor = false, }; - const CallContext f_call_context{ - .msg_sender = oracle.get_this_contract_address().get_value(), // the sender is `this` contract! - .storage_contract_address = external_contract_address.get_value(), - .tx_origin = oracle.get_tx_origin().get_value(), + const CallContext f_call_context_ct{ + .msg_sender = oracle.get_this_contract_address(), // the sender is `this` contract! + .storage_contract_address = f_contract_address, + .tx_origin = oracle.get_tx_origin(), .is_delegate_call = false, .is_static_call = false, .is_contract_deployment = false, @@ -189,17 +197,20 @@ template class FunctionExecutionContext { }; NativeOracle f_oracle(oracle.native_oracle.db, - external_contract_address.get_value(), - f_function_signature, - f_call_context, + f_contract_address.get_value(), + f_function_signature_ct.template to_native_type(), + f_call_context_ct.template to_native_type(), oracle.get_msg_sender_private_key() .get_value() // TODO: consider whether a nested function should even be able to access // a private key, given that the call is now coming from a contract // (which cannot own a secret), rather than a human. ); + + Composer f_composer; + OracleWrapperInterface f_oracle_wrapper(f_composer, f_oracle); - // We need an exec_ctx reference which won't go out of scope, so we store a shared_ptr to the newly created + // We need an exec_ctx reference which won't go out of scope, so we store a shared_ptr to the newly-created // exec_ctx in `this` exec_ctx. auto f_exec_ctx = std::make_shared>(f_composer, f_oracle_wrapper); @@ -224,11 +235,18 @@ template class FunctionExecutionContext { // - call_context (TODO: maybe this only needs to be done in the kernel circuit). auto f_public_inputs_ct = f_public_inputs_nt.to_circuit_type(composer); + // Constrain that the arguments of the executed function match those we expect: for (size_t i = 0; i < f_public_inputs_ct.args.size(); ++i) { args[i].assert_equal(f_public_inputs_ct.args[i]); } - auto call_stack_item_hash = f_public_inputs_ct.hash(); + CallStackItem f_call_stack_item_ct{ + .contract_address = f_contract_address, + .function_signature = f_function_signature_ct, + .public_inputs = f_public_inputs_ct, + }; + + auto call_stack_item_hash = f_call_stack_item_ct.hash(); array_push(private_circuit_public_inputs.private_call_stack, call_stack_item_hash); From dd600d1731fa477b661151e2cf84df2ea118cb1e Mon Sep 17 00:00:00 2001 From: iAmMichaelConnor Date: Wed, 18 Jan 2023 21:53:51 +0000 Subject: [PATCH 032/166] wip: pushing in case mainframe loses data --- .../kernel-circuits/private-kernel.md | 33 +++--- .../kernel/private/private_kernel_circuit.cpp | 107 +++++++++++------- 2 files changed, 84 insertions(+), 56 deletions(-) diff --git a/circuits/specs/src/architecture/kernel-circuits/private-kernel.md b/circuits/specs/src/architecture/kernel-circuits/private-kernel.md index 51a140000b8..beabbeb33fc 100644 --- a/circuits/specs/src/architecture/kernel-circuits/private-kernel.md +++ b/circuits/specs/src/architecture/kernel-circuits/private-kernel.md @@ -125,14 +125,15 @@ Contains many of the same values as [`TxContext`](../contracts/transactions.md#t In practice, we'll modularise this all into neat functions when we actually write the code. Base case: -* Let `start := previousKernelData.publicInputs.end` -* if `start.privateCallCount == 0`: - * Require previous kernel data to be empty. (Note: bear in mind - the `verify_proof()` function needs a valid dummy proof and vk to complete execution). - * Validate that `start.privateCallStack.length == 1 && start.publicCallStack.length == 0 && start.contractDeploymentCallStack.length == 0 && start.l1CallStack.length == 0` - - TBD: to allow the option of a fee payment, we might require `start.privateCallStack.length` to be "1" or "2, where one tx has an `isFeePayment` indicator". - * Pop the only (TBD) `privateCallHash` off the `start.privateCallStack`. - - Validate that `hash(privateCall.callStackItem) == privateCallHash` - - If `privateCall.callStackItem.functionSignature.isConstructor == true`: +* Let `start := previousKernelData.publicInputs.end` ✅ +* if `start.privateCallCount == 0`: ✅ + * Require previous kernel data to be empty. (Note: bear in mind - the `verify_proof()` function needs a valid dummy proof and vk to complete execution). ❓ + * Validate that `start.privateCallStack.length == 1 && start.publicCallStack.length == 0 && start.contractDeploymentCallStack.length == 0 && start.l1CallStack.length == 0` ✅ + - TBD: to allow the option of a fee payment, we might require `start.privateCallStack.length` to be "1" or "2, where one tx has an `isFeePayment` indicator". ✅ + * Pop the only (TBD) `privateCallHash` off the `start.privateCallStack`. ✅ + - Validate that `hash(privateCall.callStackItem) == privateCallHash` ✅ + - If `privateCall.callStackItem.functionSignature.isConstructor == true`: ❌ + - THIS SECTION IS OUT OF DATE - IGNORE! - then we don't need a signature from the user, since this entire 'callstack' has been instantiated by a Contract Deployment kernel snark (which itself will have been signed by the user). - Set `constants.recursionContext.isConstructor := true` - This public input will percolate to -- and be checked by -- the Contract Deployment Kernel Circuit which calls this constructor. This check is required to prevent a person from circumventing the ECDSA signature check by simply setting `isConstructor = true` when making a private call. If this aggregated kernel snark reaches the rollup circuit without this flag being reset to `false` by the Contract Deployment Kernel Circuit (to say "yes, this kernel was indeed a constructor for a Contract Deployment Kernel Circuit"), then the entire tx will be rejected by the rollup circuit. - Else: @@ -145,20 +146,20 @@ Base case: - Assert `privateCall.callStackItem.publicInputs.callContext.storageContractAddress == privateCall.callStackItem.contractAddress` Recursion: -* If `previousKernel.publicInputs.isPrivate && start.privateCallCount > 0`: +* If `previousKernel.publicInputs.isPrivate && start.privateCallCount > 0`: ✅ - If `privateCall.callStackItem.functionSignature.isConstructor == true`: - Revert - only the first call in the kernel recursion can be a constructor. - * Verify the `previousKernel.proof` using the `previousKernel.vk` + * Verify the `previousKernel.proof` using the `previousKernel.vk` ✅ * Validate that the `previousKernel.vk` is a valid private kernel VK with a membership check: * Calculate `previousKernelVKHash := hash(previousKernel.vk);` * Compute `root` using the `previousKernelVKHash`, `previousKernel.vkPath` and `previousKernel.vkIndex`. * Validate that `root == privateKernelVKTreeRoot`. - * Validate consistency of 'starting' and 'previous end' values: - - verify that the `start...` values match the `previousKernel.publicInputs.end...` equivalents. - * Validate consistency of values which must remain the same throughout the recursion (when passed from kernel circuit to kernel circuit): - * ensure this kernel circuit's 'constant' public inputs match the `previousKernel.publicInputs.constants`. - * E.g. old tree roots. - - Also ensure that any 'append-only' stacks or arrays have the same entries as the previous kernel proof, before pushing more data onto them! + * Validate consistency of 'starting' and 'previous end' values: ✅ + - verify that the `start...` values match the `previousKernel.publicInputs.end...` equivalents. ✅ + * Validate consistency of values which must remain the same throughout the recursion (when passed from kernel circuit to kernel circuit): ✅ + * ensure this kernel circuit's 'constant' public inputs match the `previousKernel.publicInputs.constants`. ✅ + * E.g. old tree roots. ✅ + - Also ensure that any 'append-only' stacks or arrays have the same entries as the previous kernel proof, before pushing more data onto them! ✅ Verify the next call on the callstack: * Verify `start.privateCallStack.length > 0` and (if not already done during the 'Base Case' logic above, depending on how we do the implementation), pop 1 item off of `start.privateCallStack` (a `privateCallStackItemHash`) diff --git a/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp b/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp index 6ac465a2650..9c3a951f70c 100644 --- a/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp +++ b/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp @@ -119,67 +119,87 @@ void update_end_values(PrivateInputs const& private_inputs, PublicInputs } } -void validate_private_call_hash(PrivateInputs const& private_inputs) +void validate_this_private_call_hash(PrivateInputs const& private_inputs) { const auto& start = private_inputs.previous_kernel.public_inputs.end; - const auto private_call_hash = array_pop(start.private_call_stack); - const auto calculated_private_call_hash = private_inputs.private_call.call_stack_item.hash(); + // TODO: this logic might need to change to accommodate the weird edge 3 initial txs (the 'main' tx, the 'fee' tx, + // and the 'gas rebate' tx). + const auto this_private_call_hash = array_pop(start.private_call_stack); + const auto calculated_this_private_call_hash = private_inputs.private_call.call_stack_item.hash(); - private_call_hash.assert_equal(calculated_private_call_hash, "private_call_hash does not reconcile"); + this_private_call_hash.assert_equal(calculated_this_private_call_hash, "this private_call_hash does not reconcile"); }; -void validate_inputs(PrivateInputs const& private_inputs) +void validate_this_private_call_stack(PrivateInputs const& private_inputs) { + auto& stack = private_inputs.private_call.call_stack_item.public_inputs.private_call_stack; + auto& preimages = private_inputs.private_call.private_call_stack_preimages; + for (size_t i = 0; i < stack.size(); ++i) { + const auto& hash = stack[i]; + const auto& preimage = preimages[i]; + + // Note: this assumes it's computationally infeasible to have `0` as a valid call_stack_item_hash. + // Assumes `hash == 0` means "this stack item is empty". + const auto calculated_hash = CT::fr::conditional_assign(hash == 0, 0, preimage.hash()); + + hash.assert_equal(calculated_hash, format("private_call_stack[", i, "] = ", hash, "; does not reconcile")); + } +}; - const auto& next_call = private_inputs.private_call.call_stack_item; +void validate_inputs(PrivateInputs const& private_inputs) +{ + const auto& this_call_stack_item = private_inputs.private_call.call_stack_item; - next_call.function_signature.is_private.assert_equal( + this_call_stack_item.function_signature.is_private.assert_equal( true, "Cannot execute a non-private function with the private kernel circuit"); const auto& start = private_inputs.previous_kernel.public_inputs.end; const CT::boolean is_base_case = start.private_call_count == 0; + + // TODO: we might want to range-constrain the call_count to prevent some kind of overflow errors const CT::boolean is_recursive_case = !is_base_case; CT::fr start_private_call_stack_length = array_length(start.private_call_stack); CT::fr start_public_call_stack_length = array_length(start.public_call_stack); CT::fr start_l1_msg_stack_length = array_length(start.l1_msg_stack); + // Recall: we can't do traditional `if` statements in a circuit; all code paths are always executed. The below is + // some syntactic sugar, which seeks readability similar to an `if` statement. + // Base Case - { - std::vector> base_case_conditions{ - { start_private_call_stack_length == 1, - "Private call stack must be length 1" }, // TODO: might change to allow 3, so a fee can be paid and a gas - // rebate can be paid. - { start_public_call_stack_length == 0, "Public call stack must be empty" }, - { start_l1_msg_stack_length == 0, "L1 msg stack must be empty" }, - - { next_call.public_inputs.call_context.is_delegate_call == false, "Users cannot make a delegatecall" }, - { next_call.public_inputs.call_context.is_static_call == false, "Users cannot make a static call" }, - - // The below also prevents delegatecall/staticcall in the base case - { next_call.public_inputs.call_context.storage_contract_address == next_call.contract_address, - "Storage contract address must be that of the called contract" } - }; - - is_base_case.must_imply(base_case_conditions); - } + std::vector> base_case_conditions{ + // TODO: change to allow 3 initial calls on the private call stack, so a fee can be paid and a gas + // rebate can be paid. + { start_private_call_stack_length == 1, "Private call stack must be length 1" }, + { start_public_call_stack_length == 0, "Public call stack must be empty" }, + { start_l1_msg_stack_length == 0, "L1 msg stack must be empty" }, + + { this_call_stack_item.public_inputs.call_context.is_delegate_call == false, + "Users cannot make a delegatecall" }, + { this_call_stack_item.public_inputs.call_context.is_static_call == false, "Users cannot make a static call" }, + + // The below also prevents delegatecall/staticcall in the base case + { this_call_stack_item.public_inputs.call_context.storage_contract_address == + this_call_stack_item.contract_address, + "Storage contract address must be that of the called contract" } + + // TODO: Assert that the previous kernel data is empty. (Or rather, the verify_proof() function needs a valid + // dummy proof and vk to complete execution, so actually what we want is for that mockvk to be + // hard-coded into the circuit and assert that that is the one which has been used in the base case). + }; + is_base_case.must_imply(base_case_conditions); // Recursive Case - { - std::vector> recursive_case_conditions{ - { private_inputs.previous_kernel.public_inputs.is_private == true, - "Cannot verify a non-private kernel snark in the private kernel circuit" }, - { next_call.function_signature.is_constructor == false, - "A constructor must be executed as the first tx in the recursion" }, - { start_private_call_stack_length != 0, - "Cannot execute private kernel circuit with an empty private call stack" } - }; - - is_recursive_case.must_imply(recursive_case_conditions); - } - - validate_private_call_hash(private_inputs); + std::vector> recursive_case_conditions{ + { private_inputs.previous_kernel.public_inputs.is_private == true, + "Cannot verify a non-private kernel snark in the private kernel circuit" }, + { this_call_stack_item.function_signature.is_constructor == false, + "A constructor must be executed as the first tx in the recursion" }, + { start_private_call_stack_length != 0, + "Cannot execute private kernel circuit with an empty private call stack" } + }; + is_recursive_case.must_imply(recursive_case_conditions); } // NOTE: THIS IS A VERY UNFINISHED WORK IN PROGRESS. @@ -193,9 +213,16 @@ void private_kernel_circuit(Composer& composer, PrivateInputs const& _privat // We'll be pushing data to this during execution of this circuit. PublicInputs public_inputs{}; + // Do this before any functions can modify the inputs. + initialise_end_values(private_inputs, public_inputs); + validate_inputs(private_inputs); - initialise_end_values(private_inputs, public_inputs); + validate_this_private_call_hash(private_inputs); + + validate_this_private_call_stack(private_inputs); + + // update_end_values(private_inputs, public_inputs); auto aggregation_object = verify_proofs(composer, private_inputs, From 3f63763c2bf166388f26e55f290dde5b3dfea367 Mon Sep 17 00:00:00 2001 From: iAmMichaelConnor Date: Thu, 2 Feb 2023 16:45:12 +0000 Subject: [PATCH 033/166] fix: array pushing of call stacks --- .../kernel/private/private_kernel_circuit.cpp | 43 ++++++++----------- circuits/src/aztec3/circuits/types/array.hpp | 43 ++++++++++++++----- circuits/src/aztec3/constants.hpp | 3 +- 3 files changed, 50 insertions(+), 39 deletions(-) diff --git a/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp b/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp index 9c3a951f70c..20b89a90fee 100644 --- a/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp +++ b/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp @@ -60,14 +60,13 @@ void update_end_values(PrivateInputs const& private_inputs, PublicInputs const auto& new_commitments = private_call_public_inputs.new_commitments; const auto& new_nullifiers = private_call_public_inputs.new_nullifiers; - const auto& is_static_call = private_inputs.private_call.call_stack_item.public_inputs.call_context.is_static_call; + const auto& is_static_call = private_call_public_inputs.call_context.is_static_call; // No state changes are allowed for static calls: is_static_call.must_imply(is_array_empty(new_commitments) == true); is_static_call.must_imply(is_array_empty(new_nullifiers) == true); - const auto& storage_contract_address = - private_inputs.private_call.call_stack_item.public_inputs.call_context.storage_contract_address; + const auto& storage_contract_address = private_call_public_inputs.call_context.storage_contract_address; { // commitments & nullifiers std::array siloed_new_commitments; @@ -91,32 +90,24 @@ void update_end_values(PrivateInputs const& private_inputs, PublicInputs push_array_to_array(siloed_new_nullifiers, public_inputs.end.new_nullifiers); } - { - // TODO: we need to pass in UNPACKED stack data. I.e. the preimages of the call_stack_item hashes, so that data - // in the stack can be validated as being correct. (e.g. call_contexts of calls made by the private_call - // currently being validated). - - // So we'll need to ensure our test_apps return not only a PrivateCircuitPublicInputs object, but also an object - // containing a TONNE of preimage data. Stuff like: - // - Stack item preimages - // - Commitment and nullifier preimages - // - Hash paths and leaf indices - // - Any and all preimage data derived by the circuit or through oracle calls. + { // call stacks + auto& this_private_call_stack = private_call_public_inputs.private_call_stack; + push_array_to_array(this_private_call_stack, public_inputs.end.private_call_stack); } - const auto& portal_contract_address = private_inputs.private_call.portal_contract_address; + // const auto& portal_contract_address = private_inputs.private_call.portal_contract_address; - { - const auto& l1_msg_stack = private_call_public_inputs.l1_msg_stack; - std::array l1_call_stack; + // { + // const auto& l1_msg_stack = private_call_public_inputs.l1_msg_stack; + // std::array l1_call_stack; - for (size_t i = 0; i < l1_msg_stack.size(); ++i) { - l1_call_stack[i] = CT::fr::conditional_assign( - l1_msg_stack[i] == 0, - 0, - CT::compress({ portal_contract_address, l1_msg_stack[i] }, GeneratorIndex::L1_CALL_STACK_ITEM)); - } - } + // for (size_t i = 0; i < l1_msg_stack.size(); ++i) { + // l1_call_stack[i] = CT::fr::conditional_assign( + // l1_msg_stack[i] == 0, + // 0, + // CT::compress({ portal_contract_address, l1_msg_stack[i] }, GeneratorIndex::L1_MSG_STACK_ITEM)); + // } + // } } void validate_this_private_call_hash(PrivateInputs const& private_inputs) @@ -222,7 +213,7 @@ void private_kernel_circuit(Composer& composer, PrivateInputs const& _privat validate_this_private_call_stack(private_inputs); - // update_end_values(private_inputs, public_inputs); + update_end_values(private_inputs, public_inputs); auto aggregation_object = verify_proofs(composer, private_inputs, diff --git a/circuits/src/aztec3/circuits/types/array.hpp b/circuits/src/aztec3/circuits/types/array.hpp index 1df42bd7bb4..a1174d6f83e 100644 --- a/circuits/src/aztec3/circuits/types/array.hpp +++ b/circuits/src/aztec3/circuits/types/array.hpp @@ -133,24 +133,45 @@ void push_array_to_array(std::array::fr, size_1> typedef typename CT::fr fr; typedef typename CT::boolean boolean; + // TODO: inefficient to get length this way within this function. Probably best to inline the checks that we need + // into the below loops directly. fr target_length = array_length(target); - // fr source_length = array_length(source); - + fr source_length = array_length(source); fr target_capacity = fr(target.size()); + const fr overflow_capacity = target_capacity + 1; + // TODO: using safe_fr for an underflow check, do: // remaining_target_capacity = target_capacity.subtract(target_length + source_length); - fr t_i = 0; - fr next_index = target_length; - for (const auto& s : source) { - for (auto& t : target) { - next_index.assert_not_equal(target_capacity, "Target array capacity exceeded"); - boolean at_index = t_i == next_index; - t = fr::conditional_assign(at_index, s, t); - next_index = fr::conditional_assign(at_index, next_index + 1, next_index); - ++t_i; + ASSERT(target_capacity.get_value() + 1 > target_length.get_value() + source_length.get_value()); + + info("source: ", source); + info("target before: ", target); + + fr j_ct = 0; // circuit-type index for the inner loop + fr next_target_index = target_length; + for (size_t i = 0; i < source.size(); ++i) { + auto& s = source[i]; + + // Triangular loop: + for (size_t j = i; j < target.size() - source.size() + i + 1; ++j) { + auto& t = target[j]; + + boolean at_next_index = j_ct == next_target_index; + + t = fr::conditional_assign(at_next_index, s, t); + + j_ct++; } + + next_target_index++; + + next_target_index.assert_not_equal(overflow_capacity, "Target array capacity exceeded"); + + j_ct = i + 1; } + + info("target after: ", target); } } // namespace aztec3::circuits::types \ No newline at end of file diff --git a/circuits/src/aztec3/constants.hpp b/circuits/src/aztec3/constants.hpp index ed17a672101..4485f6b49d0 100644 --- a/circuits/src/aztec3/constants.hpp +++ b/circuits/src/aztec3/constants.hpp @@ -46,8 +46,7 @@ enum GeneratorIndex { CALL_CONTEXT, CALL_STACK_ITEM, CALL_STACK_ITEM_2, // see function where it's used for explanation - PARTIAL_L1_CALL_STACK_ITEM, - L1_CALL_STACK_ITEM, + L1_MSG_STACK_ITEM, PRIVATE_CIRCUIT_PUBLIC_INPUTS, PUBLIC_CIRCUIT_PUBLIC_INPUTS, }; From 034e4e646c4c5c745cdf3071b6772299d540ce61 Mon Sep 17 00:00:00 2001 From: Suyash Bagad Date: Mon, 13 Feb 2023 11:07:07 +0000 Subject: [PATCH 034/166] Add barretenberg submodule. Change to `aztec3` branch. Compilation fixes 1. Fixes 2. More fixes. More fixes. Some more fixes. --- circuits/.clang-format | 28 +++ circuits/.gitignore | 11 ++ circuits/.gitmodules | 4 + circuits/CMakeLists.txt | 54 ++++++ circuits/barretenberg | 1 + circuits/bootstrap.sh | 57 ++++++ circuits/cmake/arch.cmake | 10 + circuits/cmake/barretenberg.cmake | 57 ++++++ circuits/cmake/benchmark.cmake | 20 ++ circuits/cmake/build.cmake | 9 + circuits/cmake/gtest.cmake | 32 ++++ circuits/cmake/module.cmake | 179 ++++++++++++++++++ circuits/cmake/threading.cmake | 38 ++++ circuits/cmake/toolchain.cmake | 10 + .../cmake/toolchains/arm-apple-clang.cmake | 4 + .../cmake/toolchains/arm64-linux-gcc.cmake | 21 ++ .../cmake/toolchains/i386-linux-clang.cmake | 13 ++ .../cmake/toolchains/wasm-linux-clang.cmake | 35 ++++ .../cmake/toolchains/x86_64-apple-clang.cmake | 3 + .../cmake/toolchains/x86_64-linux-clang.cmake | 2 + .../cmake/toolchains/x86_64-linux-gcc.cmake | 5 + .../cmake/toolchains/x86_64-linux-gcc10.cmake | 5 + circuits/format.sh | 21 ++ circuits/src/CMakeLists.txt | 32 ++++ circuits/src/aztec3/circuits/abis/.test.cpp | 22 +-- .../src/aztec3/circuits/abis/call_context.hpp | 3 +- .../abis/contract_deployment_data.hpp | 2 +- .../circuits/abis/function_signature.hpp | 3 +- .../abis/private_circuit_public_inputs.hpp | 2 +- .../src/aztec3/circuits/abis/tx_context.hpp | 2 +- circuits/src/aztec3/circuits/apps/.test.cpp | 6 +- .../apps/function_execution_context.hpp | 4 +- .../apps/notes/default_private_note/note.tpp | 4 +- .../default_private_note/note_preimage.hpp | 4 +- .../nullifier_preimage.hpp | 4 +- .../default_singleton_private_note/note.tpp | 4 +- .../note_preimage.hpp | 4 +- .../nullifier_preimage.hpp | 4 +- .../circuits/apps/private_state.test.cpp | 6 +- .../apps/state_vars/mapping_state_var.tpp | 4 +- .../apps/state_vars/state_var_base.tpp | 6 +- .../circuits/apps/test_apps/escrow/.test.cpp | 26 +-- .../circuits/apps/test_apps/escrow/init.hpp | 4 +- .../.test.cpp | 8 +- .../private_to_private_function_call/init.hpp | 4 +- .../aztec3/circuits/kernel/private/.test.cpp | 10 +- .../aztec3/circuits/kernel/private/init.hpp | 6 +- .../kernel/private/private_kernel_circuit.cpp | 10 +- .../circuits/mock/mock_kernel_circuit.hpp | 6 +- .../aztec3/circuits/recursion/aggregator.hpp | 8 +- .../aztec3/circuits/recursion/play.test.cpp | 32 ++-- .../circuits/recursion/play_app_circuit.hpp | 4 +- .../recursion/play_recursive_circuit.hpp | 14 +- .../src/aztec3/circuits/types/address.hpp | 153 --------------- circuits/src/aztec3/circuits/types/array.hpp | 177 ----------------- 55 files changed, 760 insertions(+), 437 deletions(-) create mode 100644 circuits/.clang-format create mode 100644 circuits/.gitignore create mode 100644 circuits/.gitmodules create mode 100644 circuits/CMakeLists.txt create mode 160000 circuits/barretenberg create mode 100755 circuits/bootstrap.sh create mode 100644 circuits/cmake/arch.cmake create mode 100644 circuits/cmake/barretenberg.cmake create mode 100644 circuits/cmake/benchmark.cmake create mode 100644 circuits/cmake/build.cmake create mode 100644 circuits/cmake/gtest.cmake create mode 100644 circuits/cmake/module.cmake create mode 100644 circuits/cmake/threading.cmake create mode 100644 circuits/cmake/toolchain.cmake create mode 100644 circuits/cmake/toolchains/arm-apple-clang.cmake create mode 100644 circuits/cmake/toolchains/arm64-linux-gcc.cmake create mode 100644 circuits/cmake/toolchains/i386-linux-clang.cmake create mode 100644 circuits/cmake/toolchains/wasm-linux-clang.cmake create mode 100644 circuits/cmake/toolchains/x86_64-apple-clang.cmake create mode 100644 circuits/cmake/toolchains/x86_64-linux-clang.cmake create mode 100644 circuits/cmake/toolchains/x86_64-linux-gcc.cmake create mode 100644 circuits/cmake/toolchains/x86_64-linux-gcc10.cmake create mode 100755 circuits/format.sh create mode 100644 circuits/src/CMakeLists.txt delete mode 100644 circuits/src/aztec3/circuits/types/address.hpp delete mode 100644 circuits/src/aztec3/circuits/types/array.hpp diff --git a/circuits/.clang-format b/circuits/.clang-format new file mode 100644 index 00000000000..bcd87ae23b2 --- /dev/null +++ b/circuits/.clang-format @@ -0,0 +1,28 @@ +PointerAlignment: Left +ColumnLimit: 120 +BreakBeforeBraces: Allman +IndentWidth: 4 +BinPackArguments: false +BinPackParameters: false +AllowShortFunctionsOnASingleLine: None +Cpp11BracedListStyle: false +AlwaysBreakAfterReturnType: None +AlwaysBreakAfterDefinitionReturnType: None +PenaltyReturnTypeOnItsOwnLine: 1000000 +BreakConstructorInitializers: BeforeComma +BreakBeforeBraces: Custom +BraceWrapping: + AfterClass: false + AfterEnum: false + AfterFunction: true + AfterNamespace: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + SplitEmptyFunction: false + SplitEmptyRecord: false + SplitEmptyNamespace: false +AllowShortFunctionsOnASingleLine : Inline +SortIncludes: false \ No newline at end of file diff --git a/circuits/.gitignore b/circuits/.gitignore new file mode 100644 index 00000000000..3af23ba15cd --- /dev/null +++ b/circuits/.gitignore @@ -0,0 +1,11 @@ +.cache/ +build*/ +src/wasi-sdk-* +src/aztec/proof_system/proving_key/fixtures +src/aztec/rollup/proofs/*/fixtures +srs_db/ignition/transcript* +srs_db/lagrange +srs_db/coset_lagrange +srs_db/modified_lagrange +# to be unignored when we agree on clang-tidy rules +.clangd \ No newline at end of file diff --git a/circuits/.gitmodules b/circuits/.gitmodules new file mode 100644 index 00000000000..079abe5b958 --- /dev/null +++ b/circuits/.gitmodules @@ -0,0 +1,4 @@ +[submodule "barretenberg"] + path = barretenberg + url = git@github.com:AztecProtocol/barretenberg.git + branch = aztec3 diff --git a/circuits/CMakeLists.txt b/circuits/CMakeLists.txt new file mode 100644 index 00000000000..4930ba0321a --- /dev/null +++ b/circuits/CMakeLists.txt @@ -0,0 +1,54 @@ +# aztec-connect-cpp +# copyright 2019 Spilsbury Holdings Ltd + +cmake_minimum_required(VERSION 3.16) + +# Get the full path to barretenberg. This is helpful because the required +# relative path changes based on where in cmake the path is used. +# `BBERG_DIR` must be set before toolchain.cmake is imported because +# `BBERG_DIR` is used in toolchain.cmake to determine `WASI_SDK_PREFIX` +get_filename_component(BBERG_DIR ../barretenberg/cpp + REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") + +include(cmake/toolchain.cmake) + +set(PROJECT_VERSION 0.1.0) +project(Aztec3Circuits + DESCRIPTION "Project containing Aztec3 Circuits Infrastucture in C++." + LANGUAGES CXX C) + +# include barretenberg as ExternalProject +include(cmake/barretenberg.cmake) + +option(DISABLE_ASM "Disable custom assembly" OFF) +option(DISABLE_ADX "Disable ADX assembly variant" OFF) +option(MULTITHREADING "Enable multi-threading" ON) +option(TESTING "Build tests" ON) + +if(ARM) + message(STATUS "Compiling for ARM.") + set(DISABLE_ASM ON) + set(DISABLE_ADX ON) + set(RUN_HAVE_STD_REGEX 0) + set(RUN_HAVE_POSIX_REGEX 0) +endif() + +if(WASM) + message(STATUS "Compiling for WebAssembly.") + set(DISABLE_ASM ON) + set(MULTITHREADING OFF) +endif() + +set(CMAKE_C_STANDARD 11) +set(CMAKE_C_EXTENSIONS ON) +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED TRUE) +set(CMAKE_CXX_EXTENSIONS ON) + +include(cmake/build.cmake) +include(cmake/arch.cmake) +include(cmake/threading.cmake) +include(cmake/gtest.cmake) +include(cmake/module.cmake) + +add_subdirectory(src) \ No newline at end of file diff --git a/circuits/barretenberg b/circuits/barretenberg new file mode 160000 index 00000000000..e98e16cf9cf --- /dev/null +++ b/circuits/barretenberg @@ -0,0 +1 @@ +Subproject commit e98e16cf9cfdc8e5d7a8dc1fa64befdea746517d diff --git a/circuits/bootstrap.sh b/circuits/bootstrap.sh new file mode 100755 index 00000000000..94609d44d72 --- /dev/null +++ b/circuits/bootstrap.sh @@ -0,0 +1,57 @@ +#!/bin/bash +set -e + +# Update the submodule +git submodule update --init --recursive --remote + +# Clean. +rm -rf ./build +rm -rf ./build-wasm +rm -rf ./src/wasi-sdk-* + +# Clean barretenberg. +rm -rf ../barretenberg/cpp/build +rm -rf ../barretenberg/cpp/build-wasm +rm -rf ../barretenberg/cpp/src/wasi-sdk-* + +# Install formatting git hook. +HOOKS_DIR=$(git rev-parse --git-path hooks) +echo "cd \$(git rev-parse --show-toplevel) && ./format.sh staged" > $HOOKS_DIR/pre-commit +chmod +x $HOOKS_DIR/pre-commit + +# Determine system. +if [[ "$OSTYPE" == "darwin"* ]]; then + OS=macos +elif [[ "$OSTYPE" == "linux-gnu" ]]; then + OS=linux +else + echo "Unknown OS: $OSTYPE" + exit 1 +fi + +# Download ignition transcripts. +(cd barretenberg/cpp/srs_db && ./download_ignition.sh 3) + +# Pick native toolchain file. +if [ "$OS" == "macos" ]; then + export BREW_PREFIX=$(brew --prefix) + # Ensure we have toolchain. + if [ ! "$?" -eq 0 ] || [ ! -f "$BREW_PREFIX/opt/llvm/bin/clang++" ]; then + echo "Default clang not sufficient. Install homebrew, and then: brew install llvm libomp clang-format" + exit 1 + fi + ARCH=$(uname -m) + if [ "$ARCH" = "arm64" ]; then + TOOLCHAIN=arm-apple-clang + else + TOOLCHAIN=x86_64-apple-clang + fi +else + TOOLCHAIN=x86_64-linux-clang +fi + +# Build native. +mkdir -p build && cd build +cmake -DCMAKE_BUILD_TYPE=RelWithAssert -DTOOLCHAIN=$TOOLCHAIN .. +cmake --build . --parallel ${@/#/--target } +cd .. \ No newline at end of file diff --git a/circuits/cmake/arch.cmake b/circuits/cmake/arch.cmake new file mode 100644 index 00000000000..084c0b67df8 --- /dev/null +++ b/circuits/cmake/arch.cmake @@ -0,0 +1,10 @@ +if(WASM) + # Disable SLP vectorization on WASM as it's brokenly slow. To give an idea, with this off it still takes + # 2m:18s to compile scalar_multiplication.cpp, and with it on I estimate it's 50-100 times longer. I never + # had the patience to wait it out... + add_compile_options(-fno-exceptions -fno-slp-vectorize) +endif() + +if(NOT WASM AND NOT APPLE) + add_compile_options(-march=skylake-avx512) +endif() diff --git a/circuits/cmake/barretenberg.cmake b/circuits/cmake/barretenberg.cmake new file mode 100644 index 00000000000..70854c4458e --- /dev/null +++ b/circuits/cmake/barretenberg.cmake @@ -0,0 +1,57 @@ +# Here we Set up barretenberg as an ExternalProject +# - Point to its source and build directories +# - Construct its `configure` and `build` command lines +# - include its `src/` in `search path for includes +# - Depend on specific libraries from barretenberg +# +# If barretenberg's cmake files change, its configure and build are triggered +# If barretenberg's source files change, build is triggered + +include(ExternalProject) + +if (WASM) + set(BBERG_BUILD_DIR ${BBERG_DIR}/build-wasm) +else() + set(BBERG_BUILD_DIR ${BBERG_DIR}/build) +endif() + +# If the OpenMP library is included via this option, propogate to ExternalProject configure +if (OpenMP_omp_LIBRARY) + set(LIB_OMP_OPTION -DOpenMP_omp_LIBRARY=${OpenMP_omp_LIBRARY}) +endif() + +# Make sure barretenberg doesn't set its own WASI_SDK_PREFIX +if (WASI_SDK_PREFIX) + set(WASI_SDK_OPTION -DWASI_SDK_PREFIX=${WASI_SDK_PREFIX}) +endif() + +# cmake configure cli args for ExternalProject +set(BBERG_CONFIGURE_ARGS -DTOOLCHAIN=${TOOLCHAIN} ${WASI_SDK_OPTION} ${LIB_OMP_OPTION} -DCI=${CI}) + +# Naming: Project: Barretenberg, Libraries: barretenberg, env +# Need BUILD_ALWAYS to ensure that barretenberg is automatically reconfigured when its CMake files change +# "Enabling this option forces the build step to always be run. This can be the easiest way to robustly +# ensure that the external project's own build dependencies are evaluated rather than relying on the +# default success timestamp-based method." - https://cmake.org/cmake/help/latest/module/ExternalProject.html +ExternalProject_Add(Barretenberg + SOURCE_DIR ${BBERG_DIR} + BINARY_DIR ${BBERG_BUILD_DIR} # build directory + BUILD_ALWAYS TRUE + UPDATE_COMMAND "" + INSTALL_COMMAND "" + CONFIGURE_COMMAND ${CMAKE_COMMAND} ${BBERG_CONFIGURE_ARGS} .. + BUILD_COMMAND ${CMAKE_COMMAND} --build . --parallel --target barretenberg --target env) + +include_directories(${BBERG_DIR}/src/aztec) + +# Add the imported barretenberg and env libraries, point to their library archives, +# and add a dependency of these libraries on the imported project +add_library(barretenberg STATIC IMPORTED) +set_target_properties(barretenberg PROPERTIES IMPORTED_LOCATION ${BBERG_BUILD_DIR}/lib/libbarretenberg.a) +add_dependencies(barretenberg Barretenberg) + +# env is needed for logstr in native executables and wasm tests +# It is otherwise omitted from wasm to prevent use of C++ logstr instead of imported/Typescript +add_library(env STATIC IMPORTED) +set_target_properties(env PROPERTIES IMPORTED_LOCATION ${BBERG_BUILD_DIR}/lib/libenv.a) +add_dependencies(env Barretenberg) \ No newline at end of file diff --git a/circuits/cmake/benchmark.cmake b/circuits/cmake/benchmark.cmake new file mode 100644 index 00000000000..889ddbbee0a --- /dev/null +++ b/circuits/cmake/benchmark.cmake @@ -0,0 +1,20 @@ +if(NOT TESTING) + set(BENCHMARKS OFF) +endif() + +if(BENCHMARKS) + include(FetchContent) + + FetchContent_Declare( + benchmark + GIT_REPOSITORY https://github.com/google/benchmark + GIT_TAG v1.6.1 + ) + + FetchContent_GetProperties(benchmark) + if(NOT benchmark_POPULATED) + fetchcontent_populate(benchmark) + set(BENCHMARK_ENABLE_TESTING OFF CACHE BOOL "Benchmark tests off") + add_subdirectory(${benchmark_SOURCE_DIR} ${benchmark_BINARY_DIR} EXCLUDE_FROM_ALL) + endif() +endif() diff --git a/circuits/cmake/build.cmake b/circuits/cmake/build.cmake new file mode 100644 index 00000000000..3eb2eddd060 --- /dev/null +++ b/circuits/cmake/build.cmake @@ -0,0 +1,9 @@ +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build." FORCE) +endif() +message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") + +if(CMAKE_BUILD_TYPE STREQUAL "RelWithAssert") + add_compile_options(-O3) + remove_definitions(-DNDEBUG) +endif() \ No newline at end of file diff --git a/circuits/cmake/gtest.cmake b/circuits/cmake/gtest.cmake new file mode 100644 index 00000000000..4ba7cf66b70 --- /dev/null +++ b/circuits/cmake/gtest.cmake @@ -0,0 +1,32 @@ +if(TESTING) + include(GoogleTest) + include(FetchContent) + + FetchContent_Declare( + googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG release-1.10.0 + ) + + FetchContent_GetProperties(googletest) + if(NOT googletest_POPULATED) + FetchContent_Populate(googletest) + add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR} EXCLUDE_FROM_ALL) + endif() + + if(WASM) + target_compile_definitions( + gtest + PRIVATE + -DGTEST_HAS_EXCEPTIONS=0 + -DGTEST_HAS_STREAM_REDIRECTION=0) + endif() + + mark_as_advanced( + BUILD_GMOCK BUILD_GTEST BUILD_SHARED_LIBS + gmock_build_tests gtest_build_samples gtest_build_tests + gtest_disable_pthreads gtest_force_shared_crt gtest_hide_internal_symbols + ) + + enable_testing() +endif() diff --git a/circuits/cmake/module.cmake b/circuits/cmake/module.cmake new file mode 100644 index 00000000000..5be976d4e44 --- /dev/null +++ b/circuits/cmake/module.cmake @@ -0,0 +1,179 @@ +# copyright 2019 Spilsbury Holdings +# +# usage: barretenberg_module(module_name [dependencies ...]) +# +# Scans for all .cpp files in a subdirectory, and creates a library named . +# Scans for all .test.cpp files in a subdirectory, and creates a gtest binary named _tests. +# Scans for all .bench.cpp files in a subdirectory, and creates a benchmark binary named _bench. +# +# We have to get a bit complicated here, due to the fact CMake will not parallelise the building of object files +# between dependent targets, due to the potential of post-build code generation steps etc. +# To work around this, we create "object libraries" containing the object files. +# Then we declare executables/libraries that are to be built from these object files. +# These assets will only be linked as their dependencies complete, but we can parallelise the compilation at least. + +function(barretenberg_module MODULE_NAME) + file(GLOB_RECURSE SOURCE_FILES *.cpp) + file(GLOB_RECURSE HEADER_FILES *.hpp) + list(FILTER SOURCE_FILES EXCLUDE REGEX ".*\.(fuzzer|test|bench).cpp$") + + if(SOURCE_FILES) + add_library( + ${MODULE_NAME}_objects + OBJECT + ${SOURCE_FILES} + ) + + add_library( + ${MODULE_NAME} + STATIC + $ + ) + + target_link_libraries( + ${MODULE_NAME} + PUBLIC + ${ARGN} + barretenberg + ${TBB_IMPORTED_TARGETS} + ) + + set(MODULE_LINK_NAME ${MODULE_NAME}) + endif() + + file(GLOB_RECURSE TEST_SOURCE_FILES *.test.cpp) + if(TESTING AND TEST_SOURCE_FILES) + add_library( + ${MODULE_NAME}_test_objects + OBJECT + ${TEST_SOURCE_FILES} + ) + + target_link_libraries( + ${MODULE_NAME}_test_objects + PRIVATE + gtest + barretenberg + env + ${TBB_IMPORTED_TARGETS} + ) + + add_executable( + ${MODULE_NAME}_tests + $ + ) + + if(WASM) + target_link_options( + ${MODULE_NAME}_tests + PRIVATE + -Wl,-z,stack-size=8388608 + ) + endif() + + if(CI) + target_compile_definitions( + ${MODULE_NAME}_test_objects + PRIVATE + -DCI=1 + ) + endif() + + if(DISABLE_HEAVY_TESTS) + target_compile_definitions( + ${MODULE_NAME}_test_objects + PRIVATE + -DDISABLE_HEAVY_TESTS=1 + ) + endif() + + target_link_libraries( + ${MODULE_NAME}_tests + PRIVATE + ${MODULE_LINK_NAME} + ${ARGN} + gtest + gtest_main + barretenberg + env + ${TBB_IMPORTED_TARGETS} + ) + + if(NOT WASM AND NOT CI) + # Currently haven't found a way to easily wrap the calls in wasmtime when run from ctest. + gtest_discover_tests(${MODULE_NAME}_tests WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) + endif() + + add_custom_target( + run_${MODULE_NAME}_tests + COMMAND ${MODULE_NAME}_tests + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + ) + endif() + + file(GLOB_RECURSE FUZZERS_SOURCE_FILES *.fuzzer.cpp) + if(FUZZING AND FUZZERS_SOURCE_FILES) + foreach(FUZZER_SOURCE_FILE ${FUZZERS_SOURCE_FILES}) + get_filename_component(FUZZER_NAME_STEM ${FUZZER_SOURCE_FILE} NAME_WE) + add_executable( + ${MODULE_NAME}_${FUZZER_NAME_STEM}_fuzzer + ${FUZZER_SOURCE_FILE} + ) + + target_link_options( + ${MODULE_NAME}_${FUZZER_NAME_STEM}_fuzzer + PRIVATE + "-fsanitize=fuzzer" + ${SANITIZER_OPTIONS} + ) + + target_link_libraries( + ${MODULE_NAME}_${FUZZER_NAME_STEM}_fuzzer + PRIVATE + ${MODULE_LINK_NAME} + barretenberg + env + ) + endforeach() + endif() + + file(GLOB_RECURSE BENCH_SOURCE_FILES *.bench.cpp) + if(BENCHMARKS AND BENCH_SOURCE_FILES) + add_library( + ${MODULE_NAME}_bench_objects + OBJECT + ${BENCH_SOURCE_FILES} + ) + + target_link_libraries( + ${MODULE_NAME}_bench_objects + PRIVATE + benchmark + barretenberg + env + ${TBB_IMPORTED_TARGETS} + ) + + add_executable( + ${MODULE_NAME}_bench + $ + ) + + target_link_libraries( + ${MODULE_NAME}_bench + PRIVATE + ${MODULE_LINK_NAME} + ${ARGN} + benchmark + barretenberg + env + ${TBB_IMPORTED_TARGETS} + ) + + add_custom_target( + run_${MODULE_NAME}_bench + COMMAND ${MODULE_NAME}_bench + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + ) + endif() +endfunction() \ No newline at end of file diff --git a/circuits/cmake/threading.cmake b/circuits/cmake/threading.cmake new file mode 100644 index 00000000000..f91b86b3853 --- /dev/null +++ b/circuits/cmake/threading.cmake @@ -0,0 +1,38 @@ +if(APPLE) + if(CMAKE_C_COMPILER_ID MATCHES "Clang") + set(OpenMP_C_FLAGS "-fopenmp") + set(OpenMP_C_FLAGS_WORK "-fopenmp") + set(OpenMP_C_LIB_NAMES "libomp") + set(OpenMP_C_LIB_NAMES_WORK "libomp") + set(OpenMP_libomp_LIBRARY "$ENV{BREW_PREFIX}/opt/libomp/lib/libomp.dylib") + endif() + if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + set(OpenMP_CXX_FLAGS "-fopenmp") + set(OpenMP_CXX_FLAGS_WORK "-fopenmp") + set(OpenMP_CXX_LIB_NAMES "libomp") + set(OpenMP_CXX_LIB_NAMES_WORK "libomp") + set(OpenMP_libomp_LIBRARY "$ENV{BREW_PREFIX}/opt/libomp/lib/libomp.dylib") + endif() +endif() + +if(MULTITHREADING) + find_package(OpenMP REQUIRED) + message(STATUS "Multithreading is enabled.") + link_libraries(OpenMP::OpenMP_CXX) +else() + message(STATUS "Multithreading is disabled.") + add_definitions(-DNO_MULTITHREADING -DBOOST_SP_NO_ATOMIC_ACCESS) +endif() + +if(DISABLE_TBB) + message(STATUS "Intel Thread Building Blocks is disabled.") + add_definitions(-DNO_TBB) +else() + find_package(TBB REQUIRED tbb) + if(${TBB_FOUND}) + message(STATUS "Intel Thread Building Blocks is enabled.") + else() + message(STATUS "Could not locate TBB.") + add_definitions(-DNO_TBB) + endif() +endif() diff --git a/circuits/cmake/toolchain.cmake b/circuits/cmake/toolchain.cmake new file mode 100644 index 00000000000..4de860fac49 --- /dev/null +++ b/circuits/cmake/toolchain.cmake @@ -0,0 +1,10 @@ +if (CMAKE_C_COMPILER AND CMAKE_CXX_COMPILER) + message(STATUS "Toolchain: manually chosen ${CMAKE_C_COMPILER} and ${CMAKE_CXX_COMPILER}") +else() + if(NOT TOOLCHAIN) + set(TOOLCHAIN "x86_64-linux-clang" CACHE STRING "Build toolchain." FORCE) + endif() + message(STATUS "Toolchain: ${TOOLCHAIN}") + + include("./cmake/toolchains/${TOOLCHAIN}.cmake") +endif() \ No newline at end of file diff --git a/circuits/cmake/toolchains/arm-apple-clang.cmake b/circuits/cmake/toolchains/arm-apple-clang.cmake new file mode 100644 index 00000000000..1b451ab08d5 --- /dev/null +++ b/circuits/cmake/toolchains/arm-apple-clang.cmake @@ -0,0 +1,4 @@ +set(APPLE ON) +set(ARM ON) +set(CMAKE_CXX_COMPILER "$ENV{BREW_PREFIX}/opt/llvm/bin/clang++") +set(CMAKE_C_COMPILER "$ENV{BREW_PREFIX}/opt/llvm/bin/clang") \ No newline at end of file diff --git a/circuits/cmake/toolchains/arm64-linux-gcc.cmake b/circuits/cmake/toolchains/arm64-linux-gcc.cmake new file mode 100644 index 00000000000..bc8bd0b8028 --- /dev/null +++ b/circuits/cmake/toolchains/arm64-linux-gcc.cmake @@ -0,0 +1,21 @@ +set(ARM ON) +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_VERSION 1) +set(CMAKE_SYSTEM_PROCESSOR aarch64) + +set(cross_triple "aarch64-unknown-linux-gnu") +set(cross_root /usr/xcc/${cross_triple}) + +set(CMAKE_C_COMPILER $ENV{CC}) +set(CMAKE_CXX_COMPILER $ENV{CXX}) +set(CMAKE_Fortran_COMPILER $ENV{FC}) + +set(CMAKE_CXX_FLAGS "-I ${cross_root}/include/") + +set(CMAKE_FIND_ROOT_PATH ${cross_root} ${cross_root}/${cross_triple}) +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH) +set(CMAKE_SYSROOT ${cross_root}/${cross_triple}/sysroot) + +set(CMAKE_CROSSCOMPILING_EMULATOR /usr/bin/qemu-aarch64) \ No newline at end of file diff --git a/circuits/cmake/toolchains/i386-linux-clang.cmake b/circuits/cmake/toolchains/i386-linux-clang.cmake new file mode 100644 index 00000000000..acbdb3d47e1 --- /dev/null +++ b/circuits/cmake/toolchains/i386-linux-clang.cmake @@ -0,0 +1,13 @@ +# Sometimes we need to set compilers manually, for example for fuzzing +if(NOT CMAKE_C_COMPILER) + set(CMAKE_C_COMPILER "clang") +endif() + +if(NOT CMAKE_CXX_COMPILER) + set(CMAKE_CXX_COMPILER "clang++") +endif() + +add_compile_options("-m32") +add_link_options("-m32") +set(MULTITHREADING OFF) +add_definitions(-DDISABLE_SHENANIGANS=1) \ No newline at end of file diff --git a/circuits/cmake/toolchains/wasm-linux-clang.cmake b/circuits/cmake/toolchains/wasm-linux-clang.cmake new file mode 100644 index 00000000000..f8e7796ff57 --- /dev/null +++ b/circuits/cmake/toolchains/wasm-linux-clang.cmake @@ -0,0 +1,35 @@ +# Cmake toolchain description file for the Makefile + +# This is arbitrary, AFAIK, for now. +cmake_minimum_required(VERSION 3.4.0) + +set(WASM ON) +set(CMAKE_SYSTEM_NAME Generic) +set(CMAKE_SYSTEM_VERSION 1) +set(CMAKE_SYSTEM_PROCESSOR wasm32) +set(triple wasm32-wasi) + +set(WASI_SDK_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/src/wasi-sdk-12.0") +set(CMAKE_C_COMPILER ${WASI_SDK_PREFIX}/bin/clang) +set(CMAKE_CXX_COMPILER ${WASI_SDK_PREFIX}/bin/clang++) +set(CMAKE_AR ${WASI_SDK_PREFIX}/bin/llvm-ar CACHE STRING "wasi-sdk build") +set(CMAKE_RANLIB ${WASI_SDK_PREFIX}/bin/llvm-ranlib CACHE STRING "wasi-sdk build") +set(CMAKE_C_COMPILER_TARGET ${triple} CACHE STRING "wasi-sdk build") +set(CMAKE_CXX_COMPILER_TARGET ${triple} CACHE STRING "wasi-sdk build") +#set(CMAKE_EXE_LINKER_FLAGS "-Wl,--no-threads" CACHE STRING "wasi-sdk build") + +set(CMAKE_SYSROOT ${WASI_SDK_PREFIX}/share/wasi-sysroot CACHE STRING "wasi-sdk build") +set(CMAKE_STAGING_PREFIX ${WASI_SDK_PREFIX}/share/wasi-sysroot CACHE STRING "wasi-sdk build") + +# Don't look in the sysroot for executables to run during the build +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +# Only look in the sysroot (not in the host paths) for the rest +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + +# Some other hacks +set(CMAKE_C_COMPILER_WORKS ON) +set(CMAKE_CXX_COMPILER_WORKS ON) + +add_definitions(-D_WASI_EMULATED_PROCESS_CLOCKS=1) \ No newline at end of file diff --git a/circuits/cmake/toolchains/x86_64-apple-clang.cmake b/circuits/cmake/toolchains/x86_64-apple-clang.cmake new file mode 100644 index 00000000000..35440991b94 --- /dev/null +++ b/circuits/cmake/toolchains/x86_64-apple-clang.cmake @@ -0,0 +1,3 @@ +set(APPLE ON) +set(CMAKE_CXX_COMPILER "$ENV{BREW_PREFIX}/opt/llvm/bin/clang++") +set(CMAKE_C_COMPILER "$ENV{BREW_PREFIX}/opt/llvm/bin/clang") \ No newline at end of file diff --git a/circuits/cmake/toolchains/x86_64-linux-clang.cmake b/circuits/cmake/toolchains/x86_64-linux-clang.cmake new file mode 100644 index 00000000000..7df84b7c037 --- /dev/null +++ b/circuits/cmake/toolchains/x86_64-linux-clang.cmake @@ -0,0 +1,2 @@ +set(CMAKE_C_COMPILER "clang") +set(CMAKE_CXX_COMPILER "clang++") \ No newline at end of file diff --git a/circuits/cmake/toolchains/x86_64-linux-gcc.cmake b/circuits/cmake/toolchains/x86_64-linux-gcc.cmake new file mode 100644 index 00000000000..9cd8af83f78 --- /dev/null +++ b/circuits/cmake/toolchains/x86_64-linux-gcc.cmake @@ -0,0 +1,5 @@ +set(CMAKE_C_COMPILER "gcc") +set(CMAKE_CXX_COMPILER "g++") +# TODO(Cody): git rid of this when Adrian's work goes in +add_compile_options(-Wno-uninitialized) +add_compile_options(-Wno-maybe-uninitialized) \ No newline at end of file diff --git a/circuits/cmake/toolchains/x86_64-linux-gcc10.cmake b/circuits/cmake/toolchains/x86_64-linux-gcc10.cmake new file mode 100644 index 00000000000..36fdcfacc85 --- /dev/null +++ b/circuits/cmake/toolchains/x86_64-linux-gcc10.cmake @@ -0,0 +1,5 @@ +set(CMAKE_C_COMPILER "gcc-10") +set(CMAKE_CXX_COMPILER "g++-10") +# TODO(Cody): git rid of this when Adrian's work goes in +add_compile_options(-Wno-uninitialized) +add_compile_options(-Wno-maybe-uninitialized) \ No newline at end of file diff --git a/circuits/format.sh b/circuits/format.sh new file mode 100755 index 00000000000..0b6ce3b9215 --- /dev/null +++ b/circuits/format.sh @@ -0,0 +1,21 @@ +#!/bin/bash +set -e + +if [ "$1" == "staged" ]; then + echo Formatting staged files... + for FILE in $(git diff-index --diff-filter=d --relative --cached --name-only HEAD | grep -e '\.\(cpp\|hpp\|tcc\)$'); do + clang-format -i $FILE + sed -i.bak 's/\r$//' $FILE && rm ${FILE}.bak + git add $FILE + done +elif [ -n "$1" ]; then + for FILE in $(git diff-index --relative --name-only $1 | grep -e '\.\(cpp\|hpp\|tcc\)$'); do + clang-format -i $FILE + sed -i.bak 's/\r$//' $FILE && rm ${FILE}.bak + done +else + for FILE in $(find ./src -iname *.hpp -o -iname *.cpp -o -iname *.tcc | grep -v src/boost); do + clang-format -i $FILE + sed -i.bak 's/\r$//' $FILE && rm ${FILE}.bak + done +fi \ No newline at end of file diff --git a/circuits/src/CMakeLists.txt b/circuits/src/CMakeLists.txt new file mode 100644 index 00000000000..a694ab8909a --- /dev/null +++ b/circuits/src/CMakeLists.txt @@ -0,0 +1,32 @@ +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + +add_compile_options(-Werror -Wall -Wextra -Wconversion -Wsign-conversion -Wno-deprecated -Wno-tautological-compare -Wfatal-errors) + +if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + add_compile_options(-Wno-unguarded-availability-new -Wno-c99-extensions -fconstexpr-steps=100000000) + if(MEMORY_CHECKS) + message(STATUS "Compiling with memory checks.") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address") + endif() +endif() + +if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") + add_compile_options(-Wno-deprecated-copy -fconstexpr-ops-limit=100000000) +endif() + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) + +# I feel this should be limited to ecc, however it's currently used in headers that go across libraries, +# and there currently isn't an easy way to inherit the DDISABLE_SHENANIGANS parameter. +if(DISABLE_ASM) + message(STATUS "Using fallback non-assembly methods for field multiplications.") + add_definitions(-DDISABLE_SHENANIGANS=1) +else() + message(STATUS "Using optimized assembly for field arithmetic.") +endif() + +add_subdirectory(aztec3) + +if(BENCHMARKS) + add_subdirectory(benchmark) +endif() \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/abis/.test.cpp b/circuits/src/aztec3/circuits/abis/.test.cpp index beefe7d42cd..3f72992f962 100644 --- a/circuits/src/aztec3/circuits/abis/.test.cpp +++ b/circuits/src/aztec3/circuits/abis/.test.cpp @@ -3,12 +3,12 @@ #include // #include #include "index.hpp" -#include +#include namespace aztec3::circuits::abis { -using TurboComposer = plonk::stdlib::types::turbo::Composer; -using CT = plonk::stdlib::types::CircuitTypes; +using Composer = plonk::stdlib::types::Composer; +using CT = plonk::stdlib::types::CircuitTypes; using NT = plonk::stdlib::types::NativeTypes; class abi_tests : public ::testing::Test {}; @@ -39,8 +39,8 @@ TEST(abi_tests, test_native_to_circuit_function_signature) info("function signature: ", native_function_signature); - TurboComposer turbo_composer; - FunctionSignature circuit_function_signature = native_function_signature.to_circuit_type(turbo_composer); + Composer composer; + FunctionSignature circuit_function_signature = native_function_signature.to_circuit_type(composer); info("function signature: ", circuit_function_signature); } @@ -70,8 +70,8 @@ TEST(abi_tests, test_native_to_circuit_call_context) info("call context: ", native_call_context); - TurboComposer turbo_composer; - CallContext circuit_call_context = native_call_context.to_circuit_type(turbo_composer); + Composer composer; + CallContext circuit_call_context = native_call_context.to_circuit_type(composer); info("call context: ", circuit_call_context); } @@ -109,8 +109,8 @@ TEST(abi_tests, test_native_to_circuit_call_context) // info("public_circuit_public_inputs: ", native_public_inputs); -// TurboComposer turbo_composer; -// PublicCircuitPublicInputs circuit_public_inputs = native_public_inputs.to_circuit_type(turbo_composer); +// Composer composer; +// PublicCircuitPublicInputs circuit_public_inputs = native_public_inputs.to_circuit_type(composer); // info("public_circuit_public_inputs: ", circuit_public_inputs); // } @@ -180,9 +180,9 @@ TEST(abi_tests, test_native_to_circuit_call_context) // info("call stack item: ", native_call_stack_item); -// TurboComposer turbo_composer; +// Composer composer; // CallStackItem circuit_call_stack_item = -// native_call_stack_item.to_circuit_type(turbo_composer); +// native_call_stack_item.to_circuit_type(composer); // info("call stack item: ", circuit_call_stack_item); // } diff --git a/circuits/src/aztec3/circuits/abis/call_context.hpp b/circuits/src/aztec3/circuits/abis/call_context.hpp index f6ac5031eeb..2fb2a3c9f73 100644 --- a/circuits/src/aztec3/circuits/abis/call_context.hpp +++ b/circuits/src/aztec3/circuits/abis/call_context.hpp @@ -1,11 +1,12 @@ #pragma once -#include +#include #include #include #include #include #include +#include namespace aztec3::circuits::abis { diff --git a/circuits/src/aztec3/circuits/abis/contract_deployment_data.hpp b/circuits/src/aztec3/circuits/abis/contract_deployment_data.hpp index 990bbac885b..852defd81aa 100644 --- a/circuits/src/aztec3/circuits/abis/contract_deployment_data.hpp +++ b/circuits/src/aztec3/circuits/abis/contract_deployment_data.hpp @@ -1,5 +1,5 @@ #pragma once -#include +#include #include #include #include diff --git a/circuits/src/aztec3/circuits/abis/function_signature.hpp b/circuits/src/aztec3/circuits/abis/function_signature.hpp index 069f9eda68a..08e2300c817 100644 --- a/circuits/src/aztec3/circuits/abis/function_signature.hpp +++ b/circuits/src/aztec3/circuits/abis/function_signature.hpp @@ -1,10 +1,11 @@ #pragma once -#include +#include #include #include #include #include #include +#include namespace aztec3::circuits::abis { diff --git a/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp b/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp index b90eeb09e31..1ff8d1f24ad 100644 --- a/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp +++ b/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp @@ -5,7 +5,7 @@ #include #include -#include +#include #include #include #include diff --git a/circuits/src/aztec3/circuits/abis/tx_context.hpp b/circuits/src/aztec3/circuits/abis/tx_context.hpp index 6a65bbd9206..cc8b3630dcd 100644 --- a/circuits/src/aztec3/circuits/abis/tx_context.hpp +++ b/circuits/src/aztec3/circuits/abis/tx_context.hpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include namespace aztec3::circuits::abis { diff --git a/circuits/src/aztec3/circuits/apps/.test.cpp b/circuits/src/aztec3/circuits/apps/.test.cpp index 894a202c34f..cfeb5ef3d08 100644 --- a/circuits/src/aztec3/circuits/apps/.test.cpp +++ b/circuits/src/aztec3/circuits/apps/.test.cpp @@ -1,6 +1,6 @@ // #include -// #include +// #include // #include #include @@ -31,11 +31,11 @@ #include #include #include -#include +#include namespace { // Composer -using C = plonk::stdlib::types::turbo::Composer; +using C = plonk::stdlib::types::Composer; // Types using CT = plonk::stdlib::types::CircuitTypes; diff --git a/circuits/src/aztec3/circuits/apps/function_execution_context.hpp b/circuits/src/aztec3/circuits/apps/function_execution_context.hpp index 9ba270bfd5f..276eff1087a 100644 --- a/circuits/src/aztec3/circuits/apps/function_execution_context.hpp +++ b/circuits/src/aztec3/circuits/apps/function_execution_context.hpp @@ -13,7 +13,7 @@ #include #include -#include +#include #include @@ -30,7 +30,7 @@ using aztec3::circuits::abis::PrivateCircuitPublicInputs; using aztec3::circuits::apps::notes::NoteInterface; using aztec3::circuits::apps::opcodes::Opcodes; -using aztec3::circuits::types::array_push; +using plonk::stdlib::array_push; using plonk::stdlib::witness_t; using plonk::stdlib::types::CircuitTypes; diff --git a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.tpp b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.tpp index 15910a85b58..3c614eb9cdd 100644 --- a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.tpp +++ b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.tpp @@ -8,7 +8,7 @@ #include "../../state_vars/state_var_base.hpp" -#include +#include #include @@ -28,7 +28,7 @@ namespace aztec3::circuits::apps::notes { using aztec3::GeneratorIndex; -using crypto::pedersen::generator_index_t; +using crypto::generators::generator_index_t; using plonk::stdlib::witness_t; using plonk::stdlib::types::CircuitTypes; diff --git a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note_preimage.hpp b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note_preimage.hpp index 80ba1e87951..519bf02dc00 100644 --- a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note_preimage.hpp +++ b/circuits/src/aztec3/circuits/apps/notes/default_private_note/note_preimage.hpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include @@ -11,7 +11,7 @@ namespace aztec3::circuits::apps::notes { -using crypto::pedersen::generator_index_t; +using crypto::generators::generator_index_t; using plonk::stdlib::types::CircuitTypes; using plonk::stdlib::types::NativeTypes; diff --git a/circuits/src/aztec3/circuits/apps/notes/default_private_note/nullifier_preimage.hpp b/circuits/src/aztec3/circuits/apps/notes/default_private_note/nullifier_preimage.hpp index fac86d2e520..e40478c2faf 100644 --- a/circuits/src/aztec3/circuits/apps/notes/default_private_note/nullifier_preimage.hpp +++ b/circuits/src/aztec3/circuits/apps/notes/default_private_note/nullifier_preimage.hpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include @@ -10,7 +10,7 @@ namespace aztec3::circuits::apps::notes { -using crypto::pedersen::generator_index_t; +using crypto::generators::generator_index_t; using plonk::stdlib::types::CircuitTypes; using plonk::stdlib::types::NativeTypes; diff --git a/circuits/src/aztec3/circuits/apps/notes/default_singleton_private_note/note.tpp b/circuits/src/aztec3/circuits/apps/notes/default_singleton_private_note/note.tpp index d7dc68447dc..6d93efa868a 100644 --- a/circuits/src/aztec3/circuits/apps/notes/default_singleton_private_note/note.tpp +++ b/circuits/src/aztec3/circuits/apps/notes/default_singleton_private_note/note.tpp @@ -8,7 +8,7 @@ #include "../../state_vars/state_var_base.hpp" -#include +#include #include @@ -28,7 +28,7 @@ namespace aztec3::circuits::apps::notes { using aztec3::GeneratorIndex; -using crypto::pedersen::generator_index_t; +using crypto::generators::generator_index_t; using plonk::stdlib::witness_t; using plonk::stdlib::types::CircuitTypes; diff --git a/circuits/src/aztec3/circuits/apps/notes/default_singleton_private_note/note_preimage.hpp b/circuits/src/aztec3/circuits/apps/notes/default_singleton_private_note/note_preimage.hpp index 5811654565c..884adffb96f 100644 --- a/circuits/src/aztec3/circuits/apps/notes/default_singleton_private_note/note_preimage.hpp +++ b/circuits/src/aztec3/circuits/apps/notes/default_singleton_private_note/note_preimage.hpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include @@ -11,7 +11,7 @@ namespace aztec3::circuits::apps::notes { -using crypto::pedersen::generator_index_t; +using crypto::generators::generator_index_t; using plonk::stdlib::types::CircuitTypes; using plonk::stdlib::types::NativeTypes; diff --git a/circuits/src/aztec3/circuits/apps/notes/default_singleton_private_note/nullifier_preimage.hpp b/circuits/src/aztec3/circuits/apps/notes/default_singleton_private_note/nullifier_preimage.hpp index 64c5be51c2d..89de5176b70 100644 --- a/circuits/src/aztec3/circuits/apps/notes/default_singleton_private_note/nullifier_preimage.hpp +++ b/circuits/src/aztec3/circuits/apps/notes/default_singleton_private_note/nullifier_preimage.hpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include @@ -10,7 +10,7 @@ namespace aztec3::circuits::apps::notes { -using crypto::pedersen::generator_index_t; +using crypto::generators::generator_index_t; using plonk::stdlib::types::CircuitTypes; using plonk::stdlib::types::NativeTypes; diff --git a/circuits/src/aztec3/circuits/apps/private_state.test.cpp b/circuits/src/aztec3/circuits/apps/private_state.test.cpp index 7d8859991ea..e54251ad79b 100644 --- a/circuits/src/aztec3/circuits/apps/private_state.test.cpp +++ b/circuits/src/aztec3/circuits/apps/private_state.test.cpp @@ -4,7 +4,7 @@ // #include // #include // // #include -// #include +// #include // // #include // // #include // // #include @@ -12,8 +12,8 @@ // namespace aztec3::circuits::apps { // namespace { -// using TurboComposer = plonk::stdlib::types::turbo::Composer; -// using CT = plonk::stdlib::types::CircuitTypes; +// using Composer = plonk::stdlib::types::Composer; +// using CT = plonk::stdlib::types::CircuitTypes; // using NT = plonk::stdlib::types::NativeTypes; // // using plonk::stdlib::pedersen; // } // namespace diff --git a/circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.tpp b/circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.tpp index 0f596cf4f69..f60a29bd020 100644 --- a/circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.tpp +++ b/circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.tpp @@ -11,7 +11,7 @@ #include #include -#include +#include #include #include #include @@ -23,7 +23,7 @@ using aztec3::circuits::apps::FunctionExecutionContext; namespace aztec3::circuits::apps::state_vars { -using crypto::pedersen::generator_index_t; +using crypto::generators::generator_index_t; using plonk::stdlib::types::CircuitTypes; using plonk::stdlib::types::NativeTypes; diff --git a/circuits/src/aztec3/circuits/apps/state_vars/state_var_base.tpp b/circuits/src/aztec3/circuits/apps/state_vars/state_var_base.tpp index 14bd20dcc8e..d6db3ec3076 100644 --- a/circuits/src/aztec3/circuits/apps/state_vars/state_var_base.tpp +++ b/circuits/src/aztec3/circuits/apps/state_vars/state_var_base.tpp @@ -4,7 +4,7 @@ #include -#include +#include #include #include @@ -15,7 +15,7 @@ using aztec3::circuits::apps::FunctionExecutionContext; namespace aztec3::circuits::apps::state_vars { -using crypto::pedersen::generator_index_t; +using crypto::generators::generator_index_t; using plonk::stdlib::types::CircuitTypes; template @@ -33,6 +33,6 @@ template typename CircuitTypes::grumpkin_point Sta return CT::commit({ start_slot }, { StorageSlotGeneratorIndex::BASE_SLOT }); } -// template class PrivateStateVar; +// template class PrivateStateVar; }; // namespace aztec3::circuits::apps::state_vars diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp index ec2cc6520f0..3b7f290d210 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp @@ -9,7 +9,7 @@ #include #include // #include -// #include +// #include // #include namespace aztec3::circuits::apps::test_apps::escrow { @@ -63,12 +63,12 @@ TEST_F(escrow_tests, test_deposit) info("result: ", result); info("computed witness: ", composer.computed_witness); - info("witness: ", composer.witness); + // info("witness: ", composer.witness); // info("constant variables: ", composer.constant_variables); // info("variables: ", composer.variables); - info("failed?: ", composer.failed); - info("err: ", composer.err); - info("n: ", composer.n); + info("failed?: ", composer.failed()); + info("err: ", composer.err()); + info("n: ", composer.num_gates); } TEST_F(escrow_tests, test_transfer) @@ -89,12 +89,12 @@ TEST_F(escrow_tests, test_transfer) transfer(exec_ctx, amount, to, asset_id, memo, reveal_msg_sender_to_recipient, fee); info("computed witness: ", composer.computed_witness); - info("witness: ", composer.witness); + // info("witness: ", composer.witness); // info("constant variables: ", composer.constant_variables); // info("variables: ", composer.variables); - info("failed?: ", composer.failed); - info("err: ", composer.err); - info("n: ", composer.n); + info("failed?: ", composer.failed()); + info("err: ", composer.err()); + info("n: ", composer.num_gates); } TEST_F(escrow_tests, test_withdraw) @@ -114,12 +114,12 @@ TEST_F(escrow_tests, test_withdraw) withdraw(exec_ctx, amount, asset_id, memo, l1_withdrawal_address, fee); info("computed witness: ", composer.computed_witness); - info("witness: ", composer.witness); + // info("witness: ", composer.witness); // info("constant variables: ", composer.constant_variables); // info("variables: ", composer.variables); - info("failed?: ", composer.failed); - info("err: ", composer.err); - info("n: ", composer.n); + info("failed?: ", composer.failed()); + info("err: ", composer.err()); + info("n: ", composer.num_gates); } } // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/init.hpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/init.hpp index be7748cee22..8f7542d9c15 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/init.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/init.hpp @@ -9,14 +9,14 @@ #include #include -#include +#include #include #include #include namespace aztec3::circuits::apps::test_apps::escrow { -using C = plonk::stdlib::types::turbo::Composer; +using C = plonk::stdlib::types::Composer; using CT = plonk::stdlib::types::CircuitTypes; using NT = plonk::stdlib::types::NativeTypes; diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp index c855ea4c5bb..4ce15538b60 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp @@ -56,12 +56,12 @@ TEST(private_to_private_function_call_tests, test_private_to_private_function_ca info("function_1_1_public_inputs: ", function_1_1_public_inputs); info("computed witness: ", fn1_composer.computed_witness); - info("witness: ", fn1_composer.witness); + // info("witness: ", fn1_composer.witness); // info("constant variables: ", fn1_composer.constant_variables); // info("variables: ", fn1_composer.variables); - info("failed?: ", fn1_composer.failed); - info("err: ", fn1_composer.err); - info("n: ", fn1_composer.n); + info("failed?: ", fn1_composer.failed()); + info("err: ", fn1_composer.err()); + info("n: ", fn1_composer.num_gates); } } // namespace aztec3::circuits::apps::test_apps::private_to_private_function_call \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/init.hpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/init.hpp index 612ec902ada..348ce4c3e47 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/init.hpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/init.hpp @@ -8,14 +8,14 @@ #include -#include +#include #include #include #include namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { -using C = plonk::stdlib::types::turbo::Composer; +using C = plonk::stdlib::types::Composer; using CT = plonk::stdlib::types::CircuitTypes; using NT = plonk::stdlib::types::NativeTypes; diff --git a/circuits/src/aztec3/circuits/kernel/private/.test.cpp b/circuits/src/aztec3/circuits/kernel/private/.test.cpp index 1a1db3165a4..2d53e4f98ff 100644 --- a/circuits/src/aztec3/circuits/kernel/private/.test.cpp +++ b/circuits/src/aztec3/circuits/kernel/private/.test.cpp @@ -1,5 +1,5 @@ // #include -// #include +// #include // #include // #include // #include @@ -247,15 +247,15 @@ TEST(private_kernel_tests, test_deposit) private_kernel_circuit(private_kernel_composer, private_inputs); info("computed witness: ", private_kernel_composer.computed_witness); - info("witness: ", private_kernel_composer.witness); + // info("witness: ", private_kernel_composer.witness); // info("constant variables: ", private_kernel_composer.constant_variables); // info("variables: ", private_kernel_composer.variables); // TODO: this fails intermittently, with: // bigfield multiply range check failed - info("failed?: ", private_kernel_composer.failed); - info("err: ", private_kernel_composer.err); - info("n: ", private_kernel_composer.n); + info("failed?: ", private_kernel_composer.failed()); + info("err: ", private_kernel_composer.err()); + info("n: ", private_kernel_composer.num_gates); } } // namespace aztec3::circuits::kernel::private_kernel \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/kernel/private/init.hpp b/circuits/src/aztec3/circuits/kernel/private/init.hpp index 0de9fc6ecfd..ddd4e89a5cf 100644 --- a/circuits/src/aztec3/circuits/kernel/private/init.hpp +++ b/circuits/src/aztec3/circuits/kernel/private/init.hpp @@ -7,7 +7,7 @@ #include -#include +#include #include #include #include @@ -15,8 +15,8 @@ namespace aztec3::circuits::kernel::private_kernel { // Turbo specific, at the moment: -using Composer = plonk::stdlib::types::turbo::Composer; -using plonk::stdlib::types::turbo::UnrolledProver; +using Composer = plonk::stdlib::types::Composer; +using plonk::stdlib::types::UnrolledProver; using Aggregator = aztec3::circuits::recursion::TurboAggregator; diff --git a/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp b/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp index 20b89a90fee..26b8eb15b33 100644 --- a/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp +++ b/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp @@ -1,6 +1,6 @@ #include "init.hpp" -#include +#include #include #include @@ -10,10 +10,10 @@ namespace aztec3::circuits::kernel::private_kernel { using aztec3::circuits::abis::private_kernel::PrivateInputs; using aztec3::circuits::abis::private_kernel::PublicInputs; -using aztec3::circuits::types::array_length; -using aztec3::circuits::types::array_pop; -using aztec3::circuits::types::is_array_empty; -using aztec3::circuits::types::push_array_to_array; +using plonk::stdlib::array_length; +using plonk::stdlib::array_pop; +using plonk::stdlib::is_array_empty; +using plonk::stdlib::push_array_to_array; // TODO: NEED TO RECONCILE THE `proof`'s public inputs (which are uint8's) with the // private_call.call_stack_item.public_inputs! diff --git a/circuits/src/aztec3/circuits/mock/mock_kernel_circuit.hpp b/circuits/src/aztec3/circuits/mock/mock_kernel_circuit.hpp index a35698c76b8..4b02cc308d7 100644 --- a/circuits/src/aztec3/circuits/mock/mock_kernel_circuit.hpp +++ b/circuits/src/aztec3/circuits/mock/mock_kernel_circuit.hpp @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include #include #include @@ -12,7 +12,7 @@ namespace aztec3::circuits::mock { using aztec3::circuits::abis::private_kernel::PublicInputs; using NT = plonk::stdlib::types::NativeTypes; -using plonk::stdlib::pedersen; +using plonk::stdlib::pedersen_commitment; using plonk::stdlib::witness_t; using plonk::stdlib::types::CircuitTypes; @@ -36,7 +36,7 @@ template void mock_kernel_circuit(Composer& composer, Public public_inputs.set_public(); - plonk::stdlib::pedersen::compress(fr(witness_t(&composer, 1)), fr(witness_t(&composer, 1))); + plonk::stdlib::pedersen_commitment::compress(fr(witness_t(&composer, 1)), fr(witness_t(&composer, 1))); } } // namespace aztec3::circuits::mock diff --git a/circuits/src/aztec3/circuits/recursion/aggregator.hpp b/circuits/src/aztec3/circuits/recursion/aggregator.hpp index cb4569afbc2..279fe0673a9 100644 --- a/circuits/src/aztec3/circuits/recursion/aggregator.hpp +++ b/circuits/src/aztec3/circuits/recursion/aggregator.hpp @@ -1,9 +1,9 @@ -#include +#include #include #include #include #include -#include +#include namespace aztec3::circuits::recursion { @@ -12,8 +12,8 @@ namespace aztec3::circuits::recursion { using plonk::stdlib::recursion::recursive_turbo_verifier_settings; // using plonk::stdlib::recursion::verification_key; using plonk::stdlib::recursion::verify_proof; -// using plonk::stdlib::types::turbo::bn254; -using plonk::stdlib::types::turbo::Composer; +// using plonk::stdlib::types::bn254; +using plonk::stdlib::types::Composer; using CT = plonk::stdlib::types::CircuitTypes; using NT = plonk::stdlib::types::NativeTypes; using transcript::Manifest; diff --git a/circuits/src/aztec3/circuits/recursion/play.test.cpp b/circuits/src/aztec3/circuits/recursion/play.test.cpp index 2ecf23cee4c..337b21da132 100644 --- a/circuits/src/aztec3/circuits/recursion/play.test.cpp +++ b/circuits/src/aztec3/circuits/recursion/play.test.cpp @@ -1,11 +1,11 @@ #include "index.hpp" #include // #include -#include +#include namespace aztec3::circuits::recursion { -using namespace plonk::stdlib::types::turbo; +using namespace plonk::stdlib::types; using plonk::stdlib::recursion::recursion_output; // namespace { @@ -36,8 +36,8 @@ TEST(play_tests, test_play_app_proof_gen) Composer app_composer; play_app_circuit(app_composer, 100, 200); - if (app_composer.failed) { - info("Play app circuit logic failed: ", app_composer.err); + if (app_composer.failed()) { + info("Play app circuit logic failed: ", app_composer.err()); } UnrolledProver app_prover = app_composer.create_unrolled_prover(); @@ -50,8 +50,8 @@ TEST(play_tests, test_play_recursive_proof_gen) Composer app_composer; play_app_circuit(app_composer, 1, 2); - if (app_composer.failed) { - info("Play app circuit logic failed: ", app_composer.err); + if (app_composer.failed()) { + info("Play app circuit logic failed: ", app_composer.err()); } UnrolledProver app_prover = app_composer.create_unrolled_prover(); @@ -63,8 +63,8 @@ TEST(play_tests, test_play_recursive_proof_gen) Composer recursive_composer; recursion_output recursion_output = play_recursive_circuit(recursive_composer, app_vk, app_proof); - if (recursive_composer.failed) { - info("Play recursive circuit logic failed: ", recursive_composer.err); + if (recursive_composer.failed()) { + info("Play recursive circuit logic failed: ", recursive_composer.err()); } } @@ -73,8 +73,8 @@ TEST(play_tests, test_play_recursive_2_proof_gen) Composer app_composer; play_app_circuit(app_composer, 1, 2); - if (app_composer.failed) { - info("Play app circuit logic failed: ", app_composer.err); + if (app_composer.failed()) { + info("Play app circuit logic failed: ", app_composer.err()); } UnrolledProver app_prover = app_composer.create_unrolled_prover(); @@ -86,8 +86,8 @@ TEST(play_tests, test_play_recursive_2_proof_gen) Composer dummy_circuit_composer; dummy_circuit(dummy_circuit_composer, 1, 2); - if (dummy_circuit_composer.failed) { - info("dummy_circuit logic failed: ", dummy_circuit_composer.err); + if (dummy_circuit_composer.failed()) { + info("dummy_circuit logic failed: ", dummy_circuit_composer.err()); } UnrolledProver dummy_circuit_prover = dummy_circuit_composer.create_unrolled_prover(); @@ -100,8 +100,8 @@ TEST(play_tests, test_play_recursive_2_proof_gen) recursion_output recursion_1_output = play_recursive_circuit_2(recursion_1_composer, app_vk, app_proof, dummy_circuit_vk, dummy_circuit_proof); - if (recursion_1_composer.failed) { - info("recursion_1 circuit logic failed: ", recursion_1_composer.err); + if (recursion_1_composer.failed()) { + info("recursion_1 circuit logic failed: ", recursion_1_composer.err()); } UnrolledProver recursion_1_prover = recursion_1_composer.create_unrolled_prover(); @@ -116,8 +116,8 @@ TEST(play_tests, test_play_recursive_2_proof_gen) // recursion_output recursion_2_output = play_recursive_circuit_2( // recursion_2_composer, app_vk, app_proof, recursion_1_vk, recursion_1_proof); - // if (recursion_2_composer.failed) { - // info("recursion_2 circuit logic failed: ", recursion_2_composer.err); + // if (recursion_2_composer.failed()) { + // info("recursion_2 circuit logic failed: ", recursion_2_composer.err()); // } // UnrolledProver recursion_2_prover = recursion_2_composer.create_unrolled_prover(); diff --git a/circuits/src/aztec3/circuits/recursion/play_app_circuit.hpp b/circuits/src/aztec3/circuits/recursion/play_app_circuit.hpp index b8108266da9..0c3446d6286 100644 --- a/circuits/src/aztec3/circuits/recursion/play_app_circuit.hpp +++ b/circuits/src/aztec3/circuits/recursion/play_app_circuit.hpp @@ -1,8 +1,8 @@ -#include +#include namespace aztec3::circuits::recursion { -using namespace plonk::stdlib::types::turbo; +using namespace plonk::stdlib::types; // using plonk::stdlib::recursion::recursion_output; void play_app_circuit(Composer& composer, barretenberg::fr const& a_in, barretenberg::fr const& b_in) diff --git a/circuits/src/aztec3/circuits/recursion/play_recursive_circuit.hpp b/circuits/src/aztec3/circuits/recursion/play_recursive_circuit.hpp index 6dfc80f88e1..fb56e903433 100644 --- a/circuits/src/aztec3/circuits/recursion/play_recursive_circuit.hpp +++ b/circuits/src/aztec3/circuits/recursion/play_recursive_circuit.hpp @@ -1,4 +1,4 @@ -// #include +// #include // #include // #include // #include @@ -6,7 +6,7 @@ namespace aztec3::circuits::recursion { using Aggregator = TurboAggregator; -using plonk::stdlib::types::turbo::Composer; +using plonk::stdlib::types::Composer; using CT = plonk::stdlib::types::CircuitTypes; using NT = plonk::stdlib::types::NativeTypes; @@ -43,27 +43,27 @@ CT::AggregationObject play_recursive_circuit_2(Composer& composer, std::shared_ptr app_vk_ct = CT::VK::from_witness(&composer, app_vk); std::shared_ptr prev_recursive_vk_ct = CT::VK::from_witness(&composer, prev_recursive_vk); - info("composer failed 1? ", composer.failed); + info("composer failed 1? ", composer.failed()); CT::AggregationObject aggregation_object = Aggregator::aggregate( &composer, prev_recursive_vk_ct, prev_recursive_proof, prev_recursive_vk->num_public_inputs); - info("composer failed 2? ", composer.failed); + info("composer failed 2? ", composer.failed()); info("\npublic inputs before: ", composer.public_inputs.size()); aggregation_object = Aggregator::aggregate(&composer, app_vk_ct, app_proof, app_vk->num_public_inputs, aggregation_object); info("\npublic inputs after: ", composer.public_inputs.size()); - info("composer failed 3? ", composer.failed); + info("composer failed 3? ", composer.failed()); aggregation_object.add_proof_outputs_as_public_inputs(); - info("composer failed 4? ", composer.failed); + info("composer failed 4? ", composer.failed()); info("\npublic inputs after after: ", composer.public_inputs.size()); - info("composer failed 5? ", composer.failed); + info("composer failed 5? ", composer.failed()); return aggregation_object; }; diff --git a/circuits/src/aztec3/circuits/types/address.hpp b/circuits/src/aztec3/circuits/types/address.hpp deleted file mode 100644 index 26f734b2d6d..00000000000 --- a/circuits/src/aztec3/circuits/types/address.hpp +++ /dev/null @@ -1,153 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include "../../constants.hpp" - -namespace aztec3::circuits::types { - -using barretenberg::fr; -using numeric::uint256_t; -using plonk::stdlib::bool_t; -using plonk::stdlib::field_t; -using plonk::stdlib::group; -using plonk::stdlib::pedersen; -using plonk::stdlib::point; -using plonk::stdlib::witness_t; - -// Native type -class address { - public: - fr address_; - - address() noexcept { address_ = fr(); } - - address(address const& other) - : address_(other.address_){}; - - address(fr const& address) - : address_(address){}; - - address(uint256_t const& address) - : address_(address){}; - - address(int const& address) - : address_(fr(address)){}; - - operator fr() { return address_; } - - operator fr() const { return address_; } - - constexpr bool operator==(address const& other) const { return this->address_ == other.address_; } - - friend std::ostream& operator<<(std::ostream& os, address const& v) { return os << v.address_; } - - fr to_field() const { return address_; } -}; - -template void read(B& it, address& addr) -{ - using serialize::read; - fr address_field; - read(it, address_field); - addr = address_field; -} - -template void write(B& buf, address const& addr) -{ - using serialize::write; - write(buf, addr.address_); -} - -// Circuit type -template class address_t { - public: - field_t address_; - Composer* context_; - - address_t() = default; - - address_t(address_t const& other) - : address_(other.address_) - , context_(other.context_){}; - - address_t(field_t const& address) - : address_(address) - , context_(address.context){}; - - address_t(uint256_t const& address) - : address_(address) - , context_(nullptr){}; - - address_t(int const& address) - : address_(address) - , context_(nullptr){}; - - address_t(witness_t const& witness) - { - address_ = field_t(witness); - context_ = witness.context; - } - - address_t& operator=(const address_t& other) - { - address_ = other.address_; - context_ = other.context_; - return *this; - } - - bool_t operator==(const address_t& other) const { return this->to_field() == other.to_field(); } - - field_t to_field() const { return address_; } - - fr get_value() const { return address_.get_value(); }; - - void assert_equal(const address_t& rhs, std::string const& msg = "address_t::assert_equal") const - { - address_.assert_equal(rhs.address_, msg); - }; - - void assert_is_in_set(const std::vector& set, - std::string const& msg = "address_t::assert_is_in_set") const - { - std::vector> field_set; - for (const auto& e : set) { - field_set.push_back(e.address_); - } - address_.assert_is_in_set(field_set, msg); - } - - static address_t conditional_assign(const bool_t& predicate, const address_t& lhs, const address_t& rhs) - { - return field_t::conditional_assign(predicate, lhs.address_, rhs.address_); - }; - - static address_t derive_from_private_key(field_t const& private_key) - { - // TODO: Dummy logic, for now. Proper derivation undecided. - point public_key = group::template fixed_base_scalar_mul_g1<254>(private_key); - return address_t(public_key.x); - } - - static address_t derive_contract_address(address_t const& deployer_address, - field_t const& salt, - field_t const& vk_root, - field_t const& constructor_hash) - { - std::vector> preimage{ - deployer_address.to_field(), - salt, - vk_root, - constructor_hash, - }; - return address_ct(pedersen::compress(preimage, true, GeneratorIndex::CONTRACT_ADDRESS)); - } - - friend std::ostream& operator<<(std::ostream& os, address_t const& v) { return os << v.address_; } -}; - -} // namespace aztec3::circuits::types \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/types/array.hpp b/circuits/src/aztec3/circuits/types/array.hpp deleted file mode 100644 index a1174d6f83e..00000000000 --- a/circuits/src/aztec3/circuits/types/array.hpp +++ /dev/null @@ -1,177 +0,0 @@ -#pragma once - -#include - -namespace aztec3::circuits::types { - -using plonk::stdlib::types::CircuitTypes; - -/** - * Gets the number of contiguous nonzero values of an array. - * Note: this assumes `0` always means 'not used', so be careful. If you actually want `0` to be counted, you'll need - * something else. - */ -// TODO: move to own file of helper functions. -template -typename CircuitTypes::fr array_length(std::array::fr, SIZE> const& arr) -{ - typedef CircuitTypes CT; - typedef typename CT::fr fr; - typedef typename CT::boolean boolean; - - fr length = 0; - boolean hit_zero = false; - for (const auto& e : arr) { - hit_zero |= e == 0; - const fr increment = !hit_zero; - length += increment; - } - return length; -}; - -/** - * Note: doesn't remove the last element from the array; only returns it! - * Note: this assumes `0` always means 'not used', so be careful. If you actually want `0` to be counted, you'll need - * something else. - * If it returns `0`, the array is considered 'empty'. - */ -template -typename CircuitTypes::fr array_pop(std::array::fr, SIZE> const& arr) -{ - typedef CircuitTypes CT; - typedef typename CT::fr fr; - typedef typename CT::boolean boolean; - - fr popped_value; - boolean already_popped = false; - for (size_t i = arr.size() - 1; i != (size_t)-1; i--) { - boolean is_non_zero = arr[i] != 0; - popped_value = fr::conditional_assign(!already_popped && is_non_zero, arr[i], popped_value); - - already_popped |= is_non_zero; - } - already_popped.assert_equal(true, "Cannot pop from an empty array"); - - return popped_value; -}; - -/** - * Note: this assumes `0` always means 'not used', so be careful. If you actually want `0` to be counted, you'll need - * something else. - */ -template -void array_push(std::array::fr, SIZE>& arr, - typename CircuitTypes::fr const& value) -{ - typedef CircuitTypes CT; - typedef typename CT::fr fr; - typedef typename CT::boolean boolean; - - boolean already_pushed = false; - for (size_t i = 0; i < arr.size(); ++i) { - boolean is_zero = arr[i] == 0; - arr[i] = fr::conditional_assign(!already_pushed && is_zero, value, arr[i]); - - already_pushed |= is_zero; - } - already_pushed.assert_equal(true, "Cannot push to a full array"); -}; - -template -inline size_t array_push(std::array::fr>, SIZE>& arr, - typename CircuitTypes::fr const& value) -{ - for (size_t i = 0; i < arr.size(); ++i) { - if (arr[i] == std::nullopt) { - arr[i] = value; - return i; - } - } - throw_or_abort("Cannot push to a full array"); -}; - -template -inline size_t array_push(std::array, SIZE>& arr, std::shared_ptr const& value) -{ - for (size_t i = 0; i < arr.size(); ++i) { - if (arr[i] == nullptr) { - arr[i] = value; - return i; - } - } - throw_or_abort("Cannot push to a full array"); -}; - -/** - * Note: this assumes `0` always means 'not used', so be careful. If you actually want `0` to be counted, you'll need - * something else. - */ -template -typename CircuitTypes::boolean is_array_empty( - std::array::fr, SIZE> const& arr) -{ - typedef CircuitTypes CT; - typedef typename CT::boolean boolean; - - boolean nonzero_found = false; - for (size_t i = arr.size() - 1; i != (size_t)-1; i--) { - boolean is_non_zero = arr[i] != 0; - nonzero_found |= is_non_zero; - } - return !nonzero_found; -}; - -/** - * Inserts the `source` array at the first zero-valued index of the `target` array. - * Fails if the `source` array is too large vs the remaining capacity of the `target` array. - */ -template -void push_array_to_array(std::array::fr, size_1> const& source, - std::array::fr, size_2>& target) -{ - typedef CircuitTypes CT; - typedef typename CT::fr fr; - typedef typename CT::boolean boolean; - - // TODO: inefficient to get length this way within this function. Probably best to inline the checks that we need - // into the below loops directly. - fr target_length = array_length(target); - fr source_length = array_length(source); - fr target_capacity = fr(target.size()); - const fr overflow_capacity = target_capacity + 1; - - // TODO: using safe_fr for an underflow check, do: - // remaining_target_capacity = target_capacity.subtract(target_length + source_length); - - ASSERT(target_capacity.get_value() + 1 > target_length.get_value() + source_length.get_value()); - - info("source: ", source); - info("target before: ", target); - - fr j_ct = 0; // circuit-type index for the inner loop - fr next_target_index = target_length; - for (size_t i = 0; i < source.size(); ++i) { - auto& s = source[i]; - - // Triangular loop: - for (size_t j = i; j < target.size() - source.size() + i + 1; ++j) { - auto& t = target[j]; - - boolean at_next_index = j_ct == next_target_index; - - t = fr::conditional_assign(at_next_index, s, t); - - j_ct++; - } - - next_target_index++; - - next_target_index.assert_not_equal(overflow_capacity, "Target array capacity exceeded"); - - j_ct = i + 1; - } - - info("target after: ", target); -} - -} // namespace aztec3::circuits::types \ No newline at end of file From 7171574eb0189b6c8141bd2c13c8d25051888f79 Mon Sep 17 00:00:00 2001 From: David Banks <47112877+dbanks12@users.noreply.github.com> Date: Tue, 14 Feb 2023 19:30:35 -0500 Subject: [PATCH 035/166] contract deployment data generator (#2) --- circuits/src/aztec3/circuits/abis/contract_deployment_data.hpp | 2 +- circuits/src/aztec3/constants.hpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/circuits/src/aztec3/circuits/abis/contract_deployment_data.hpp b/circuits/src/aztec3/circuits/abis/contract_deployment_data.hpp index 852defd81aa..67174306552 100644 --- a/circuits/src/aztec3/circuits/abis/contract_deployment_data.hpp +++ b/circuits/src/aztec3/circuits/abis/contract_deployment_data.hpp @@ -84,7 +84,7 @@ template struct ContractDeploymentData { contract_data_hash, function_tree_root, constructor_hash, contract_address_salt, portal_contract_address, }; - return NCT::compress(inputs, GeneratorIndex::FUNCTION_SIGNATURE); + return NCT::compress(inputs, GeneratorIndex::CONTRACT_DEPLOYMENT_DATA); } }; diff --git a/circuits/src/aztec3/constants.hpp b/circuits/src/aztec3/constants.hpp index 4485f6b49d0..f62580dae6e 100644 --- a/circuits/src/aztec3/constants.hpp +++ b/circuits/src/aztec3/constants.hpp @@ -49,6 +49,7 @@ enum GeneratorIndex { L1_MSG_STACK_ITEM, PRIVATE_CIRCUIT_PUBLIC_INPUTS, PUBLIC_CIRCUIT_PUBLIC_INPUTS, + CONTRACT_DEPLOYMENT_DATA, }; enum StorageSlotGeneratorIndex { From 9d255bcc9efc2bbf4e79994e408df9e65eebb393 Mon Sep 17 00:00:00 2001 From: Suyash Bagad Date: Fri, 17 Feb 2023 07:51:48 +0530 Subject: [PATCH 036/166] Link All to Barretenberg (David's work) (#11) * link all to barreteneberg * Point to latest bb commit. --------- Co-authored-by: dbanks12 --- circuits/barretenberg | 2 +- circuits/src/aztec3/circuits/abis/CMakeLists.txt | 3 +-- circuits/src/aztec3/circuits/apps/CMakeLists.txt | 6 +----- circuits/src/aztec3/circuits/kernel/CMakeLists.txt | 5 +---- circuits/src/aztec3/circuits/recursion/CMakeLists.txt | 7 +------ circuits/src/aztec3/circuits/rollup/CMakeLists.txt | 7 +------ circuits/src/aztec3/dbs/CMakeLists.txt | 5 +---- circuits/src/aztec3/oracle/CMakeLists.txt | 5 +---- 8 files changed, 8 insertions(+), 32 deletions(-) diff --git a/circuits/barretenberg b/circuits/barretenberg index e98e16cf9cf..3f7dda65b58 160000 --- a/circuits/barretenberg +++ b/circuits/barretenberg @@ -1 +1 @@ -Subproject commit e98e16cf9cfdc8e5d7a8dc1fa64befdea746517d +Subproject commit 3f7dda65b587afe34496bbe9abc29c6523125e64 diff --git a/circuits/src/aztec3/circuits/abis/CMakeLists.txt b/circuits/src/aztec3/circuits/abis/CMakeLists.txt index 45ff2652ca1..d261be7372c 100644 --- a/circuits/src/aztec3/circuits/abis/CMakeLists.txt +++ b/circuits/src/aztec3/circuits/abis/CMakeLists.txt @@ -1,5 +1,4 @@ barretenberg_module( aztec3_circuits_abis - stdlib_primitives - stdlib_pedersen + barretenberg ) \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/apps/CMakeLists.txt b/circuits/src/aztec3/circuits/apps/CMakeLists.txt index b2167c79207..91afc83b650 100644 --- a/circuits/src/aztec3/circuits/apps/CMakeLists.txt +++ b/circuits/src/aztec3/circuits/apps/CMakeLists.txt @@ -1,8 +1,4 @@ barretenberg_module( aztec3_circuits_apps - # ecc - crypto_pedersen - stdlib_primitives - stdlib_pedersen - stdlib_blake2s + barretenberg ) \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/kernel/CMakeLists.txt b/circuits/src/aztec3/circuits/kernel/CMakeLists.txt index 8eacdf51540..960adcf4854 100644 --- a/circuits/src/aztec3/circuits/kernel/CMakeLists.txt +++ b/circuits/src/aztec3/circuits/kernel/CMakeLists.txt @@ -5,8 +5,5 @@ barretenberg_module( # aztec3_circuits_abis aztec3_circuits_apps - # stdlib_recursion - stdlib_primitives - stdlib_pedersen - stdlib_blake3s + barretenberg ) \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/recursion/CMakeLists.txt b/circuits/src/aztec3/circuits/recursion/CMakeLists.txt index 36d5fa3a10e..f9586745db8 100644 --- a/circuits/src/aztec3/circuits/recursion/CMakeLists.txt +++ b/circuits/src/aztec3/circuits/recursion/CMakeLists.txt @@ -1,9 +1,4 @@ barretenberg_module( aztec3_circuits_recursion - # Question: why can't I link to these barretenberg modules? - # aztec3_circuits_abis - # stdlib_recursion - stdlib_primitives - stdlib_pedersen - stdlib_blake3s + barretenberg ) \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/rollup/CMakeLists.txt b/circuits/src/aztec3/circuits/rollup/CMakeLists.txt index 94089cca0e0..fb099fb3e10 100644 --- a/circuits/src/aztec3/circuits/rollup/CMakeLists.txt +++ b/circuits/src/aztec3/circuits/rollup/CMakeLists.txt @@ -1,9 +1,4 @@ barretenberg_module( aztec3_circuits_rollup - # Question: why can't I link to these barretenberg modules? - # aztec3_circuits_abis - # stdlib_recursion - stdlib_primitives - stdlib_pedersen - stdlib_blake3s + barretenberg ) \ No newline at end of file diff --git a/circuits/src/aztec3/dbs/CMakeLists.txt b/circuits/src/aztec3/dbs/CMakeLists.txt index 3138d0baa38..b51bfec1c3a 100644 --- a/circuits/src/aztec3/dbs/CMakeLists.txt +++ b/circuits/src/aztec3/dbs/CMakeLists.txt @@ -29,8 +29,5 @@ endif() barretenberg_module( aztec3_dbs - stdlib_merkle_tree # for the general db logic - stdlib_primitives - stdlib_pedersen - crypto_pedersen + barretenberg ) \ No newline at end of file diff --git a/circuits/src/aztec3/oracle/CMakeLists.txt b/circuits/src/aztec3/oracle/CMakeLists.txt index 9619b0f5475..6acd78ed5e6 100644 --- a/circuits/src/aztec3/oracle/CMakeLists.txt +++ b/circuits/src/aztec3/oracle/CMakeLists.txt @@ -1,8 +1,5 @@ barretenberg_module( aztec3_oracle aztec3_circuits_apps - crypto_pedersen - stdlib_primitives - stdlib_pedersen - stdlib_blake2s + barretenberg ) \ No newline at end of file From 694160325641cf643e99122dccbc117b595bb5ba Mon Sep 17 00:00:00 2001 From: David Banks <47112877+dbanks12@users.noreply.github.com> Date: Thu, 16 Feb 2023 21:29:51 -0500 Subject: [PATCH 037/166] add build-system and all relevant CI (#9) --- circuits/.circleci/config.yml | 188 ++++++++++++++++++ circuits/.dockerignore | 18 ++ circuits/.gitignore | 3 +- circuits/.gitmodules | 3 + circuits/bootstrap_docker.sh | 50 +++++ circuits/build-system | 1 + circuits/build_manifest.json | 26 +++ circuits/build_manifest.sh | 14 ++ .../dockerfiles/Dockerfile.arm64-linux-gcc | 6 + circuits/dockerfiles/Dockerfile.crosstool-ng | 14 ++ .../dockerfiles/Dockerfile.crosstool-ng-arm64 | 26 +++ .../dockerfiles/Dockerfile.wasm-linux-clang | 14 ++ .../dockerfiles/Dockerfile.x86_64-linux-clang | 21 ++ .../Dockerfile.x86_64-linux-clang-assert | 22 ++ .../dockerfiles/Dockerfile.x86_64-linux-gcc | 16 ++ circuits/scripts/a3-tests | 4 + circuits/scripts/run_tests | 25 +++ 17 files changed, 450 insertions(+), 1 deletion(-) create mode 100644 circuits/.circleci/config.yml create mode 100644 circuits/.dockerignore create mode 100755 circuits/bootstrap_docker.sh create mode 160000 circuits/build-system create mode 100644 circuits/build_manifest.json create mode 100644 circuits/build_manifest.sh create mode 100644 circuits/dockerfiles/Dockerfile.arm64-linux-gcc create mode 100644 circuits/dockerfiles/Dockerfile.crosstool-ng create mode 100644 circuits/dockerfiles/Dockerfile.crosstool-ng-arm64 create mode 100644 circuits/dockerfiles/Dockerfile.wasm-linux-clang create mode 100644 circuits/dockerfiles/Dockerfile.x86_64-linux-clang create mode 100644 circuits/dockerfiles/Dockerfile.x86_64-linux-clang-assert create mode 100644 circuits/dockerfiles/Dockerfile.x86_64-linux-gcc create mode 100644 circuits/scripts/a3-tests create mode 100755 circuits/scripts/run_tests diff --git a/circuits/.circleci/config.yml b/circuits/.circleci/config.yml new file mode 100644 index 00000000000..b7b6cb81713 --- /dev/null +++ b/circuits/.circleci/config.yml @@ -0,0 +1,188 @@ +# This config consists of currently 1 workflow. +# - system: The main Aztec 3 circuits and C++ +# +# The default workflow is system. To trigger the other workflows, trigger a workflow from CCI +# setting a string variable called `workflow` to another name. +# +# This file uses YAML anchors and aliases to prevent repetition of blocks of config: +# https://support.atlassian.com/bitbucket-cloud/docs/yaml-anchors/ +# +# Two primary anchors are checkout and setup_env, called as the first step of almost all jobs: +# - checkout: A custom checkout step to reduce the amount of data downloaded to improve speed. +# - setup_env: Sets up the common environment used by all build steps. +# +# Two CCI executors are used: +# - docker (small): Used only to launch external EC2 instances for big workloads. It's the cheapest option. +# - machine (large): Used for building in CCI itself. 4cpus, 15GB has the optimal power/cost ratio. +# +# The docker executor uses a custom image build in `build_image`. It's specifically streamlined for fast download +# with just enough tools to execute the build system, and launch EC2 instances etc. +# +# There are some `join` steps that are just noops. They are just used to produce cleaner graph rendering in CCI. + +version: 2.1 + +# This build step checks out the code from the repository. It has a hardcoded readonly key to allow the checkout. +# Initially it just fetches the repo metadata for the current commit hash to a depth of 50 commits. +# We need historical commit hashes to calculate diffs between previous and current commits. +# It then checks out the fetched head to actually download the data. +checkout: &checkout + run: + name: 'Checkout code' + command: | + cd $HOME + mkdir -p .ssh + chmod 0700 .ssh + ssh-keyscan -t rsa github.com >> .ssh/known_hosts + + # A read only key for cloning the repository. + echo $GIT_CHECKOUT_KEY | base64 -d > .ssh/id_rsa + + chmod 0600 .ssh/id_rsa + + # IF YOU'RE CHANGING THIS, YOU ALSO WANT TO CHANGE: build-system/remote_build/remote_build + # Shallow checkout this commit. + mkdir -p project + cd project + git init + git remote add origin $CIRCLE_REPOSITORY_URL + # Only download metadata when fetching. + git fetch --depth 50 --filter=blob:none origin $CIRCLE_SHA1 + git checkout FETCH_HEAD + # Pull in build-system submodule. + git submodule update --init build-system + +# This build step checks out the code from the benchmark-archive repository. +# The key is saved in CircleCi environment in base64 format. +# Initially it just fetches the latest version. +benchmark_add_keys: &benchmark_add_keys + run: + name: 'Add keys for getting the benchmark archive' + command: | + cd $HOME + mkdir -p .ssh + chmod 0700 .ssh + ssh-keyscan -t rsa github.com >> .ssh/known_hosts + + # A read-write key for updating the repository. + echo "$GITHUB_BENCMARK_REPOSITORY_SSH_KEY" | base64 -d > .ssh/id_ed25519 + + # This allows github to discern wich key to use. + echo "Host github.com + Hostname github.com + IdentityFile=/root/.ssh/id_rsa + + Host github.com-logs + Hostname github.com + IdentityFile=/root/.ssh/id_ed25519" > .ssh/config + + chmod 0600 .ssh/id_ed25519 + ssh-add .ssh/id_ed25519 + +# Called setup_env to setup a bunch of global variables used throughout the rest of the build process. +# It takes the required CCI environment variables as inputs, and gives them normalised names for the rest of +# the build process. This enables easy running of the build system external to CCI, as used for powerful EC2 builds. +setup_env: &setup_env + run: + name: 'Setup environment' + command: ./build-system/scripts/setup_env "$CIRCLE_SHA1" "$CIRCLE_TAG" "$CIRCLE_JOB" "$CIRCLE_REPOSITORY_URL" "$CIRCLE_BRANCH" + +# This step is used to save logs from various barretenberg test to the workspace so that they can be used later to parse benchmark values out of them +save_logs: &save_logs + persist_to_workspace: + root: /tmp/test-logs + paths: + - ./* + +jobs: + wasm-linux-clang: + docker: + - image: aztecprotocol/alpine-build-image + resource_class: small + steps: + - *checkout + - *setup_env + - run: + name: 'Build' + command: cond_spot_run_build aztec3-circuits-wasm-linux-clang 64 + + x86_64-linux-clang: + docker: + - image: aztecprotocol/alpine-build-image + resource_class: small + steps: + - *checkout + - *setup_env + - run: + name: 'Build' + command: cond_spot_run_build aztec3-circuits-x86_64-linux-clang 64 + + x86_64-linux-clang-assert: + docker: + - image: aztecprotocol/alpine-build-image + resource_class: small + steps: + - *checkout + - *setup_env + - run: + name: 'Build' + command: cond_spot_run_build aztec3-circuits-x86_64-linux-clang-assert 64 + + x86_64-linux-gcc: + docker: + - image: aztecprotocol/alpine-build-image + resource_class: small + steps: + - *checkout + - *setup_env + - run: + name: 'Build' + command: cond_spot_run_build aztec3-circuits-x86_64-linux-gcc 64 + + aztec3-circuits-tests: + docker: + - image: aztecprotocol/alpine-build-image + resource_class: small + steps: + - *checkout + - *setup_env + - run: + name: 'Test' + command: cond_spot_run_tests aztec3-circuits-x86_64-linux-clang-assert a3-tests + - *save_logs + + #aztec3-circuits--tests: + # docker: + # - image: aztecprotocol/alpine-build-image + # resource_class: small + # steps: + # - *checkout + # - *setup_env + # - run: + # name: 'Test' + # command: cond_spot_run_tests aztec3-circuits-x86_64-linux-clang-assert + # - *save_logs + +# Repeatable config for defining the workflow below. +tag_regex: &tag_regex /v[0-9]+(\.[0-9]+)*(-[a-zA-Z-]+\.[0-9]+)?/ +tag_filter: &tag_filter + tags: + only: *tag_regex +a3_test: &a3_test + requires: + - x86_64-linux-clang-assert + filters: *tag_filter + +workflows: + system: + jobs: + - wasm-linux-clang: + filters: *tag_filter + - x86_64-linux-clang: + filters: *tag_filter + - x86_64-linux-clang-assert: + filters: *tag_filter + - x86_64-linux-gcc: + filters: *tag_filter + - aztec3-circuits-tests: *a3_test + #- aztec3-circuit--tests: *a3_test \ No newline at end of file diff --git a/circuits/.dockerignore b/circuits/.dockerignore new file mode 100644 index 00000000000..f5fa90f6d5f --- /dev/null +++ b/circuits/.dockerignore @@ -0,0 +1,18 @@ +build +build-wasm +docker* +scripts +.* +src/wasi-sdk* +barretenberg/cpp/build* +barretenberg/cpp/docker* +barretenberg/cpp/scripts +barretenberg/cpp/.* +barretenberg/cpp/src/wasi-sdk* +barretenberg/cpp/src/aztec/rollup/proofs/root_*/fixtures/account +barretenberg/cpp/src/aztec/rollup/proofs/root_*/fixtures/join_split +barretenberg/cpp/src/aztec/rollup/proofs/root_*/fixtures/**/proving_key +barretenberg/cpp/srs_db/ignition/transcript* +barretenberg/cpp/srs_db/lagrange +barretenberg/cpp/srs_db/coset_lagrange +barretenberg/cpp/srs_db/modified_lagrange \ No newline at end of file diff --git a/circuits/.gitignore b/circuits/.gitignore index 3af23ba15cd..37d504a6d67 100644 --- a/circuits/.gitignore +++ b/circuits/.gitignore @@ -1,5 +1,6 @@ .cache/ -build*/ +build/ +build-wasm/ src/wasi-sdk-* src/aztec/proof_system/proving_key/fixtures src/aztec/rollup/proofs/*/fixtures diff --git a/circuits/.gitmodules b/circuits/.gitmodules index 079abe5b958..44d9f4ad174 100644 --- a/circuits/.gitmodules +++ b/circuits/.gitmodules @@ -2,3 +2,6 @@ path = barretenberg url = git@github.com:AztecProtocol/barretenberg.git branch = aztec3 +[submodule "aztec-build-system"] + path = build-system + url = git@github.com:AztecProtocol/build-system.git diff --git a/circuits/bootstrap_docker.sh b/circuits/bootstrap_docker.sh new file mode 100755 index 00000000000..c59b9a61528 --- /dev/null +++ b/circuits/bootstrap_docker.sh @@ -0,0 +1,50 @@ +#!/bin/bash +# This script builds the monorepo projects listed in the build_local script, terminating when it reaches TARGET_PROJECT. +# It performs the build inside a docker image that can launch further docker builds by mapping the users docker daemon +# socket into the container. A kind of simulated "docker-in-docker". +# We copy the monorepo entire working tree into this container, excluding any build output. +# The mechanics of this are, we mount the users repo into the container, then clone it into a directory within the +# container, and also apply modified/untracked/deleted changes to the internal repo. +# The result is we have a fresh copy of the repo, with only the working changes applied, that we can modify as we wish. + +set -e + +TARGET_PROJECT=$1 +REPO=aztec3-circuits +COMMIT_HASH=$(git rev-parse HEAD) + +# If we're calling this script from within a project directory, that's the target project. +if [ -z "$TARGET_PROJECT" ]; then + TARGET_PROJECT=$(git rev-parse --show-prefix) + if [ -n "$TARGET_PROJECT" ]; then + # We are in a project folder. + ONLY_TARGET=true + TARGET_PROJECT=$(basename $TARGET_PROJECT) + cd $(git rev-parse --show-cdup) + fi +fi + +docker build -t $REPO-build - < /dev/null 2>&1; done + +# Setup build environment. +source ./build-system/scripts/setup_env $COMMIT_HASH '' mainframe_$USER /repo + +build_local $TARGET_PROJECT $ONLY_TARGET +" \ No newline at end of file diff --git a/circuits/build-system b/circuits/build-system new file mode 160000 index 00000000000..c85b185d917 --- /dev/null +++ b/circuits/build-system @@ -0,0 +1 @@ +Subproject commit c85b185d917df423586897fd036275400b7159d9 diff --git a/circuits/build_manifest.json b/circuits/build_manifest.json new file mode 100644 index 00000000000..e721bd8769e --- /dev/null +++ b/circuits/build_manifest.json @@ -0,0 +1,26 @@ +{ + "aztec3-circuits-wasm-linux-clang": { + "buildDir": ".", + "dockerfile": "dockerfiles/Dockerfile.wasm-linux-clang", + "rebuildPatterns": ["^./"], + "dependencies": [] + }, + "aztec3-circuits-x86_64-linux-clang": { + "buildDir": ".", + "dockerfile": "dockerfiles/Dockerfile.x86_64-linux-clang", + "rebuildPatterns": ["^./"], + "dependencies": [] + }, + "aztec3-circuits-x86_64-linux-clang-assert": { + "buildDir": ".", + "dockerfile": "dockerfiles/Dockerfile.x86_64-linux-clang-assert", + "rebuildPatterns": ["^./"], + "dependencies": [] + }, + "aztec3-circuits-x86_64-linux-gcc": { + "buildDir": "./", + "dockerfile": "dockerfiles/Dockerfile.x86_64-linux-gcc", + "rebuildPatterns": ["^./"], + "dependencies": [] + } + } \ No newline at end of file diff --git a/circuits/build_manifest.sh b/circuits/build_manifest.sh new file mode 100644 index 00000000000..9040d211944 --- /dev/null +++ b/circuits/build_manifest.sh @@ -0,0 +1,14 @@ +#!/bin/bash +# Source this file to define the PROJECTS variable. +# PROJECT elements have structure PROJECT:WORKING_DIR:DOCKERFILE:REPO. +# +# TODO: Generate this from build_manifest.json + +# Commenting out a few projects, as the main use case is now to build the images needed to run end-to-end tests. +# If wanting to just see if docker images actually build, you can temporarily uncomment required projects. +PROJECTS=( + aztec3-circuits-wasm:./:./dockerfiles/Dockerfile.wasm-linux-clang:aztec3-circuits-wasm-linux-clang + aztec3-circuits-x86_64-clang:./:./dockerfiles/Dockerfile.x86_64-linux-clang:aztec3-circuits-x86_64-linux-clang + aztec3-circuits-x86_64-clang-assert:./:./dockerfiles/Dockerfile.x86_64-linux-clang-assert:aztec3-circuits-x86_64-linux-clang-assert + aztec3-circuits-x86_64-gcc:./:./dockerfiles/Dockerfile.x86_64-linux-gcc:aztec3-circuits-x86_64-linux-gcc +) \ No newline at end of file diff --git a/circuits/dockerfiles/Dockerfile.arm64-linux-gcc b/circuits/dockerfiles/Dockerfile.arm64-linux-gcc new file mode 100644 index 00000000000..c2a508f1698 --- /dev/null +++ b/circuits/dockerfiles/Dockerfile.arm64-linux-gcc @@ -0,0 +1,6 @@ +FROM aztecprotocol/crosstool-ng-arm64:latest +WORKDIR /usr/src/aztec3-circuits +COPY . . +RUN mkdir build && cd build && cmake -DTOOLCHAIN=arm64-linux-gcc .. && cmake --build . --parallel +RUN cd build && for test in ./bin/*_tests; do qemu-aarch64 $test; done +ENTRYPOINT /bin/bash \ No newline at end of file diff --git a/circuits/dockerfiles/Dockerfile.crosstool-ng b/circuits/dockerfiles/Dockerfile.crosstool-ng new file mode 100644 index 00000000000..4fa18b30c4d --- /dev/null +++ b/circuits/dockerfiles/Dockerfile.crosstool-ng @@ -0,0 +1,14 @@ +FROM ubuntu:latest + +RUN apt-get update && apt-get install -y autoconf flex texinfo unzip help2man file gawk libtool-bin ncurses-dev bison python-dev + +# Download and install the "crosstool-ng" source. +ENV REV 1.24.0 +RUN wget https://github.com/crosstool-ng/crosstool-ng/archive/crosstool-ng-${REV}.tar.gz \ + && tar -xf "crosstool-ng-${REV}.tar.gz" \ + && cd crosstool-ng-crosstool-ng-${REV} \ + && ./bootstrap \ + && ./configure --prefix=/usr/local \ + && make -j$(nproc) \ + && make install \ + && rm -rf /crosstool-* \ No newline at end of file diff --git a/circuits/dockerfiles/Dockerfile.crosstool-ng-arm64 b/circuits/dockerfiles/Dockerfile.crosstool-ng-arm64 new file mode 100644 index 00000000000..ed60507121b --- /dev/null +++ b/circuits/dockerfiles/Dockerfile.crosstool-ng-arm64 @@ -0,0 +1,26 @@ +FROM aztecprotocol/crosstool-ng:1.24.0 + +# Build toolchain. +ENV CT_PREFIX /usr/xcc +WORKDIR /usr/src/toolchain +COPY ./crosstool/arm64-linux.config .config +RUN CT_ALLOW_BUILD_AS_ROOT_SURE=1 ct-ng build && cd / && rm -rf /usr/src/toolchain + +# The cross-compiling emulator. +RUN apt-get update \ +&& apt-get install -y \ + qemu-user \ + qemu-user-static \ +&& apt-get clean --yes + +ENV CROSS_TRIPLE aarch64-unknown-linux-gnu +ENV CROSS_ROOT ${CT_PREFIX}/${CROSS_TRIPLE} +ENV AS=${CROSS_ROOT}/bin/${CROSS_TRIPLE}-as \ + AR=${CROSS_ROOT}/bin/${CROSS_TRIPLE}-ar \ + CC=${CROSS_ROOT}/bin/${CROSS_TRIPLE}-gcc \ + CPP=${CROSS_ROOT}/bin/${CROSS_TRIPLE}-cpp \ + CXX=${CROSS_ROOT}/bin/${CROSS_TRIPLE}-g++ \ + LD=${CROSS_ROOT}/bin/${CROSS_TRIPLE}-ld \ + FC=${CROSS_ROOT}/bin/${CROSS_TRIPLE}-gfortran +ENV QEMU_LD_PREFIX "${CROSS_ROOT}/${CROSS_TRIPLE}/sysroot" +ENV QEMU_SET_ENV "LD_LIBRARY_PATH=${CROSS_ROOT}/lib:${QEMU_LD_PREFIX}" \ No newline at end of file diff --git a/circuits/dockerfiles/Dockerfile.wasm-linux-clang b/circuits/dockerfiles/Dockerfile.wasm-linux-clang new file mode 100644 index 00000000000..8316ea97a25 --- /dev/null +++ b/circuits/dockerfiles/Dockerfile.wasm-linux-clang @@ -0,0 +1,14 @@ +FROM ubuntu:kinetic AS builder +RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y build-essential wget git libssl-dev cmake curl binaryen +RUN curl https://wasmtime.dev/install.sh -sSf | bash /dev/stdin --version v3.0.1 +WORKDIR /usr/src/aztec3-circuits/src +RUN curl -s -L https://github.com/CraneStation/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-linux.tar.gz | tar zxfv - +WORKDIR /usr/src/aztec3-circuits +COPY . . +# Build both honk_tests barretenberg.wasm +# This ensures that we aren't using features that would be incompatible with WASM for Honk +RUN mkdir build && cd build && cmake -DTOOLCHAIN=wasm-linux-clang .. && cmake --build . --parallel --target honk_tests --target aztec3.wasm + +FROM alpine:3.17 +COPY --from=builder /usr/src/aztec3-circuits/build/bin/aztec3.wasm /usr/src/aztec3-circuits/build/bin/aztec3.wasm +COPY --from=builder /usr/src/aztec3-circuits/build/bin/*_tests /usr/src/aztec3-circuits/build/bin/ diff --git a/circuits/dockerfiles/Dockerfile.x86_64-linux-clang b/circuits/dockerfiles/Dockerfile.x86_64-linux-clang new file mode 100644 index 00000000000..8c960bead10 --- /dev/null +++ b/circuits/dockerfiles/Dockerfile.x86_64-linux-clang @@ -0,0 +1,21 @@ +FROM alpine:3.17 AS builder +RUN apk update \ + && apk upgrade \ + && apk add --no-cache \ + build-base \ + clang15 \ + openmp-dev \ + cmake \ + git \ + curl \ + perl + +WORKDIR /usr/src/aztec3-circuits + +COPY . . +# Build the entire project, as we want to check everything builds under clang +RUN mkdir build && cd build && cmake .. && cmake --build . --parallel + +FROM alpine:3.17 +RUN apk update && apk add openmp +COPY --from=builder /usr/src/aztec3-circuits/barretenberg/cpp/srs_db /usr/src/aztec3-circuits/barretenberg/cpp/srs_db \ No newline at end of file diff --git a/circuits/dockerfiles/Dockerfile.x86_64-linux-clang-assert b/circuits/dockerfiles/Dockerfile.x86_64-linux-clang-assert new file mode 100644 index 00000000000..70f8cca912d --- /dev/null +++ b/circuits/dockerfiles/Dockerfile.x86_64-linux-clang-assert @@ -0,0 +1,22 @@ +FROM alpine:3.17 AS builder +RUN apk update \ + && apk upgrade \ + && apk add --no-cache \ + build-base \ + clang15 \ + openmp-dev \ + cmake \ + git \ + curl \ + perl + +WORKDIR /usr/src/aztec3-circuits + +COPY . . +# Build everything to ensure everything builds. All tests will be run from the result of this build. +RUN mkdir build && cd build && cmake -DCMAKE_BUILD_TYPE=RelWithAssert -DCI=ON .. && cmake --build . --parallel + +FROM alpine:3.17 +RUN apk update && apk add curl openmp +COPY --from=builder /usr/src/aztec3-circuits/barretenberg/cpp/srs_db /usr/src/aztec3-circuits/barretenberg/cpp/srs_db +COPY --from=builder /usr/src/aztec3-circuits/build/bin/*_tests /usr/src/aztec3-circuits/build/bin/ \ No newline at end of file diff --git a/circuits/dockerfiles/Dockerfile.x86_64-linux-gcc b/circuits/dockerfiles/Dockerfile.x86_64-linux-gcc new file mode 100644 index 00000000000..a6edcc6e51f --- /dev/null +++ b/circuits/dockerfiles/Dockerfile.x86_64-linux-gcc @@ -0,0 +1,16 @@ +FROM alpine:3.17 AS builder +RUN apk update \ + && apk upgrade \ + && apk add --no-cache \ + build-base \ + cmake \ + git \ + curl +WORKDIR /usr/src/aztec3-circuits +COPY . . +# Build the entire project, as we want to check everything builds under gcc. +RUN mkdir build && cd build && cmake -DTOOLCHAIN=x86_64-linux-gcc -DCI=ON .. && cmake --build . --parallel + +FROM alpine:3.17 +RUN apk update && apk add libstdc++ libgomp +COPY --from=builder /usr/src/aztec3-circuits/barretenberg/cpp/srs_db /usr/src/aztec3-circuits/barretenberg/cpp/srs_db diff --git a/circuits/scripts/a3-tests b/circuits/scripts/a3-tests new file mode 100644 index 00000000000..60a97e51a1b --- /dev/null +++ b/circuits/scripts/a3-tests @@ -0,0 +1,4 @@ +aztec3_circuits_abis_tests +aztec3_circuits_apps_tests +aztec3_circuits_kernel_tests +aztec3_circuits_recursion_tests \ No newline at end of file diff --git a/circuits/scripts/run_tests b/circuits/scripts/run_tests new file mode 100755 index 00000000000..6ee356116b3 --- /dev/null +++ b/circuits/scripts/run_tests @@ -0,0 +1,25 @@ +#!/bin/bash +set -e + +NUM_TRANSCRIPTS=$1 +TESTS=$2 +shift +shift + +$(aws ecr get-login --region us-east-2 --no-include-email) 2> /dev/null + +IMAGE_URI=278380418400.dkr.ecr.us-east-2.amazonaws.com/aztec3-circuits-x86_64-linux-clang-assert:cache-$COMMIT_HASH + +docker pull $IMAGE_URI + +if [ -f "$TESTS" ]; then + TESTS=$(cat $TESTS | tr '\n' ' ') +fi + +docker run --rm -t $IMAGE_URI /bin/sh -c "\ + set -e; \ + cd /usr/src/aztec3-circuits/barretenberg/cpp/srs_db; \ + ./download_ignition.sh $NUM_TRANSCRIPTS; \ + ./download_ignition_lagrange.sh 24; \ + cd /usr/src/aztec3-circuits/build; \ + for BIN in $TESTS; do ./bin/\$BIN $@; done" From b2e7d60d827e6845d8e6950becb127e9f99cf9b5 Mon Sep 17 00:00:00 2001 From: Suyash Bagad Date: Fri, 17 Feb 2023 20:48:36 +0530 Subject: [PATCH 038/166] Add PROJECT and VERSION for CI (#12) --- circuits/PROJECT | 1 + circuits/VERSION | 1 + 2 files changed, 2 insertions(+) create mode 100644 circuits/PROJECT create mode 100644 circuits/VERSION diff --git a/circuits/PROJECT b/circuits/PROJECT new file mode 100644 index 00000000000..8767aaf2272 --- /dev/null +++ b/circuits/PROJECT @@ -0,0 +1 @@ +aztec3-circuits \ No newline at end of file diff --git a/circuits/VERSION b/circuits/VERSION new file mode 100644 index 00000000000..aa338688915 --- /dev/null +++ b/circuits/VERSION @@ -0,0 +1 @@ +v0.1 \ No newline at end of file From 3b1237cb5a26d6d24b7c0c135798ef5e0a8d26a1 Mon Sep 17 00:00:00 2001 From: David Banks <47112877+dbanks12@users.noreply.github.com> Date: Fri, 17 Feb 2023 15:06:37 -0500 Subject: [PATCH 039/166] need to specify SRS_PATH in dependent project (#16) --- circuits/src/aztec3/circuits/abis/.test.cpp | 8 ++++---- circuits/src/aztec3/circuits/apps/.test.cpp | 14 +++++++------- .../circuits/apps/function_execution_context.hpp | 2 +- .../circuits/apps/test_apps/escrow/.test.cpp | 6 +++--- .../private_to_private_function_call/.test.cpp | 2 +- .../src/aztec3/circuits/kernel/private/.test.cpp | 6 +++--- .../src/aztec3/circuits/recursion/play.test.cpp | 16 ++++++++-------- 7 files changed, 27 insertions(+), 27 deletions(-) diff --git a/circuits/src/aztec3/circuits/abis/.test.cpp b/circuits/src/aztec3/circuits/abis/.test.cpp index 3f72992f962..6d593035634 100644 --- a/circuits/src/aztec3/circuits/abis/.test.cpp +++ b/circuits/src/aztec3/circuits/abis/.test.cpp @@ -39,7 +39,7 @@ TEST(abi_tests, test_native_to_circuit_function_signature) info("function signature: ", native_function_signature); - Composer composer; + Composer composer = Composer("../barretenberg/cpp/srs_db/ignition"); FunctionSignature circuit_function_signature = native_function_signature.to_circuit_type(composer); info("function signature: ", circuit_function_signature); @@ -70,7 +70,7 @@ TEST(abi_tests, test_native_to_circuit_call_context) info("call context: ", native_call_context); - Composer composer; + Composer composer = Composer("../barretenberg/cpp/srs_db/ignition"); CallContext circuit_call_context = native_call_context.to_circuit_type(composer); info("call context: ", circuit_call_context); @@ -109,7 +109,7 @@ TEST(abi_tests, test_native_to_circuit_call_context) // info("public_circuit_public_inputs: ", native_public_inputs); -// Composer composer; +// Composer composer = Composer("../barretenberg/cpp/srs_db/ignition"); // PublicCircuitPublicInputs circuit_public_inputs = native_public_inputs.to_circuit_type(composer); // info("public_circuit_public_inputs: ", circuit_public_inputs); @@ -180,7 +180,7 @@ TEST(abi_tests, test_native_to_circuit_call_context) // info("call stack item: ", native_call_stack_item); -// Composer composer; +// Composer composer = Composer("../barretenberg/cpp/srs_db/ignition"); // CallStackItem circuit_call_stack_item = // native_call_stack_item.to_circuit_type(composer); diff --git a/circuits/src/aztec3/circuits/apps/.test.cpp b/circuits/src/aztec3/circuits/apps/.test.cpp index cfeb5ef3d08..5f76cd98c44 100644 --- a/circuits/src/aztec3/circuits/apps/.test.cpp +++ b/circuits/src/aztec3/circuits/apps/.test.cpp @@ -121,7 +121,7 @@ TEST_F(state_var_tests, mapping) // contains a reference to earlier-declared classes... so we'd end up with classes containing dangling references, // if all this stuff were to be declared in a setup function's scope. // We could instead store shared_ptrs in every class...? - C composer; + C composer = C("../barretenberg/cpp/srs_db/ignition"); DB db; NativeOracle native_oracle = get_test_native_oracle(db); OracleWrapper oracle_wrapper = OracleWrapper(composer, native_oracle); @@ -153,7 +153,7 @@ TEST_F(state_var_tests, mapping) TEST_F(state_var_tests, mapping_within_mapping) { - C composer; + C composer = C("../barretenberg/cpp/srs_db/ignition"); DB db; NativeOracle native_oracle = get_test_native_oracle(db); OracleWrapper oracle_wrapper = OracleWrapper(composer, native_oracle); @@ -175,7 +175,7 @@ TEST_F(state_var_tests, mapping_within_mapping) TEST_F(state_var_tests, partial_mapping) { - C composer; + C composer = C("../barretenberg/cpp/srs_db/ignition"); DB db; NativeOracle native_oracle = get_test_native_oracle(db); OracleWrapper oracle_wrapper = OracleWrapper(composer, native_oracle); @@ -197,7 +197,7 @@ TEST_F(state_var_tests, partial_mapping) TEST_F(state_var_tests, utxo_of_default_private_note_fr) { - C composer; + C composer = C("../barretenberg/cpp/srs_db/ignition"); DB db; NativeOracle native_oracle = get_test_native_oracle(db); OracleWrapper oracle_wrapper = OracleWrapper(composer, native_oracle); @@ -244,7 +244,7 @@ TEST_F(state_var_tests, utxo_of_default_private_note_fr) TEST_F(state_var_tests, utxo_set_of_default_private_notes_fr) { - C composer; + C composer = C("../barretenberg/cpp/srs_db/ignition"); DB db; NativeOracle native_oracle = get_test_native_oracle(db); OracleWrapper oracle_wrapper = OracleWrapper(composer, native_oracle); @@ -306,7 +306,7 @@ TEST_F(state_var_tests, utxo_set_of_default_private_notes_fr) TEST_F(state_var_tests, initialise_utxo_of_default_singleton_private_note_fr) { - C composer; + C composer = C("../barretenberg/cpp/srs_db/ignition"); DB db; NativeOracle native_oracle = get_test_native_oracle(db); OracleWrapper oracle_wrapper = OracleWrapper(composer, native_oracle); @@ -354,7 +354,7 @@ TEST_F(state_var_tests, initialise_utxo_of_default_singleton_private_note_fr) TEST_F(state_var_tests, modify_utxo_of_default_singleton_private_note_fr) { - C composer; + C composer = C("../barretenberg/cpp/srs_db/ignition"); DB db; NativeOracle native_oracle = get_test_native_oracle(db); OracleWrapper oracle_wrapper = OracleWrapper(composer, native_oracle); diff --git a/circuits/src/aztec3/circuits/apps/function_execution_context.hpp b/circuits/src/aztec3/circuits/apps/function_execution_context.hpp index 276eff1087a..01ebdf4bed2 100644 --- a/circuits/src/aztec3/circuits/apps/function_execution_context.hpp +++ b/circuits/src/aztec3/circuits/apps/function_execution_context.hpp @@ -206,7 +206,7 @@ template class FunctionExecutionContext { // (which cannot own a secret), rather than a human. ); - Composer f_composer; + Composer f_composer = Composer("../barretenberg/cpp/srs_db/ignition"); OracleWrapperInterface f_oracle_wrapper(f_composer, f_oracle); diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp b/circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp index 3b7f290d210..ebc47acca7e 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp @@ -49,7 +49,7 @@ TEST_F(escrow_tests, test_deposit) // contains a reference to earlier-declared classes... so we'd end up with classes containing dangling references, // if all this stuff were to be declared in a setup function's scope. // We could instead store shared_ptrs in every class...? - C composer; + C composer = C("../barretenberg/cpp/srs_db/ignition"); DB db; NativeOracle native_oracle = get_test_native_oracle(db); OracleWrapper oracle_wrapper = OracleWrapper(composer, native_oracle); @@ -73,7 +73,7 @@ TEST_F(escrow_tests, test_deposit) TEST_F(escrow_tests, test_transfer) { - C composer; + C composer = C("../barretenberg/cpp/srs_db/ignition"); DB db; NativeOracle native_oracle = get_test_native_oracle(db); OracleWrapper oracle_wrapper = OracleWrapper(composer, native_oracle); @@ -99,7 +99,7 @@ TEST_F(escrow_tests, test_transfer) TEST_F(escrow_tests, test_withdraw) { - C composer; + C composer = C("../barretenberg/cpp/srs_db/ignition"); DB db; NativeOracle native_oracle = get_test_native_oracle(db); OracleWrapper oracle_wrapper = OracleWrapper(composer, native_oracle); diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp index 4ce15538b60..2267a70a18c 100644 --- a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp +++ b/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp @@ -15,7 +15,7 @@ class private_to_private_function_call_tests : public ::testing::Test {}; TEST(private_to_private_function_call_tests, test_private_to_private_function_call) { - C fn1_composer; + C fn1_composer = C("../barretenberg/cpp/srs_db/ignition"); DB db; const NT::address contract_address = 12345; diff --git a/circuits/src/aztec3/circuits/kernel/private/.test.cpp b/circuits/src/aztec3/circuits/kernel/private/.test.cpp index 2d53e4f98ff..b2b7d2d1b6a 100644 --- a/circuits/src/aztec3/circuits/kernel/private/.test.cpp +++ b/circuits/src/aztec3/circuits/kernel/private/.test.cpp @@ -86,7 +86,7 @@ TEST(private_kernel_tests, test_deposit) NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); const NT::address tx_origin = msg_sender; - Composer deposit_composer; + Composer deposit_composer = Composer("../barretenberg/cpp/srs_db/ignition"); DB db; FunctionSignature function_signature{ @@ -157,7 +157,7 @@ TEST(private_kernel_tests, test_deposit) // kernel circuit expects to verify some previous kernel circuit). //*************************************************************************** - Composer mock_kernel_composer; + Composer mock_kernel_composer = Composer("../barretenberg/cpp/srs_db/ignition"); // TODO: we have a choice to make: // Either the `end` state of the mock kernel's public inputs can be set equal to the public call we _want_ to @@ -215,7 +215,7 @@ TEST(private_kernel_tests, test_deposit) // - mock kernel proof, public inputs, etc. //*************************************************************************** - Composer private_kernel_composer; + Composer private_kernel_composer = Composer("../barretenberg/cpp/srs_db/ignition"); PrivateInputs private_inputs = PrivateInputs{ .signed_tx_object = signed_deposit_tx_object, diff --git a/circuits/src/aztec3/circuits/recursion/play.test.cpp b/circuits/src/aztec3/circuits/recursion/play.test.cpp index 337b21da132..2170ba81d16 100644 --- a/circuits/src/aztec3/circuits/recursion/play.test.cpp +++ b/circuits/src/aztec3/circuits/recursion/play.test.cpp @@ -27,13 +27,13 @@ class play_tests : public ::testing::Test { TEST(play_tests, test_play_app_circuit) { - Composer composer; + Composer composer = Composer("../barretenberg/cpp/srs_db/ignition"); play_app_circuit(composer, 1, 2); } TEST(play_tests, test_play_app_proof_gen) { - Composer app_composer; + Composer app_composer = Composer("../barretenberg/cpp/srs_db/ignition"); play_app_circuit(app_composer, 100, 200); if (app_composer.failed()) { @@ -47,7 +47,7 @@ TEST(play_tests, test_play_app_proof_gen) TEST(play_tests, test_play_recursive_proof_gen) { - Composer app_composer; + Composer app_composer = Composer("../barretenberg/cpp/srs_db/ignition"); play_app_circuit(app_composer, 1, 2); if (app_composer.failed()) { @@ -60,7 +60,7 @@ TEST(play_tests, test_play_recursive_proof_gen) std::shared_ptr app_vk = app_composer.compute_verification_key(); - Composer recursive_composer; + Composer recursive_composer = Composer("../barretenberg/cpp/srs_db/ignition"); recursion_output recursion_output = play_recursive_circuit(recursive_composer, app_vk, app_proof); if (recursive_composer.failed()) { @@ -70,7 +70,7 @@ TEST(play_tests, test_play_recursive_proof_gen) TEST(play_tests, test_play_recursive_2_proof_gen) { - Composer app_composer; + Composer app_composer = Composer("../barretenberg/cpp/srs_db/ignition"); play_app_circuit(app_composer, 1, 2); if (app_composer.failed()) { @@ -83,7 +83,7 @@ TEST(play_tests, test_play_recursive_2_proof_gen) //******************************************************************************* - Composer dummy_circuit_composer; + Composer dummy_circuit_composer = Composer("../barretenberg/cpp/srs_db/ignition"); dummy_circuit(dummy_circuit_composer, 1, 2); if (dummy_circuit_composer.failed()) { @@ -96,7 +96,7 @@ TEST(play_tests, test_play_recursive_2_proof_gen) //******************************************************************************* - Composer recursion_1_composer = Composer("../srs_db/ignition", 0); + Composer recursion_1_composer = Composer("../barretenberg/cpp/srs_db/ignition", 0); recursion_output recursion_1_output = play_recursive_circuit_2(recursion_1_composer, app_vk, app_proof, dummy_circuit_vk, dummy_circuit_proof); @@ -112,7 +112,7 @@ TEST(play_tests, test_play_recursive_2_proof_gen) //******************************************************************************* - // Composer recursion_2_composer; + // Composer recursion_2_composer = Composer("../barretenberg/cpp/srs_db/ignition"); // recursion_output recursion_2_output = play_recursive_circuit_2( // recursion_2_composer, app_vk, app_proof, recursion_1_vk, recursion_1_proof); From 13129e02e4e2ccc72d365e4ebbca2b1afcaf75a8 Mon Sep 17 00:00:00 2001 From: David Banks <47112877+dbanks12@users.noreply.github.com> Date: Sun, 19 Feb 2023 18:15:29 -0500 Subject: [PATCH 040/166] Get CI working (#13) --- circuits/.circleci/config.yml | 17 ++-------- circuits/build_manifest.json | 6 ---- circuits/build_manifest.sh | 1 - circuits/cmake/arch.cmake | 4 +-- circuits/cmake/benchmark.cmake | 2 +- circuits/cmake/gtest.cmake | 10 +++++- circuits/cmake/module.cmake | 32 +++++++++++-------- circuits/cmake/threading.cmake | 19 +---------- .../toolchains/aarch64-linux-clang.cmake | 6 ++++ .../cmake/toolchains/wasm-linux-clang.cmake | 5 ++- .../cmake/toolchains/x86_64-linux-clang.cmake | 11 +++++-- .../cmake/toolchains/x86_64-linux-gcc.cmake | 5 +-- .../cmake/toolchains/x86_64-linux-gcc10.cmake | 5 +-- .../dockerfiles/Dockerfile.wasm-linux-clang | 8 ++--- 14 files changed, 58 insertions(+), 73 deletions(-) create mode 100644 circuits/cmake/toolchains/aarch64-linux-clang.cmake diff --git a/circuits/.circleci/config.yml b/circuits/.circleci/config.yml index b7b6cb81713..41feb3a58c7 100644 --- a/circuits/.circleci/config.yml +++ b/circuits/.circleci/config.yml @@ -128,17 +128,6 @@ jobs: name: 'Build' command: cond_spot_run_build aztec3-circuits-x86_64-linux-clang-assert 64 - x86_64-linux-gcc: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small - steps: - - *checkout - - *setup_env - - run: - name: 'Build' - command: cond_spot_run_build aztec3-circuits-x86_64-linux-gcc 64 - aztec3-circuits-tests: docker: - image: aztecprotocol/alpine-build-image @@ -148,7 +137,7 @@ jobs: - *setup_env - run: name: 'Test' - command: cond_spot_run_tests aztec3-circuits-x86_64-linux-clang-assert a3-tests + command: cond_spot_run_tests aztec3-circuits-x86_64-linux-clang-assert 1 a3-tests - *save_logs #aztec3-circuits--tests: @@ -160,7 +149,7 @@ jobs: # - *setup_env # - run: # name: 'Test' - # command: cond_spot_run_tests aztec3-circuits-x86_64-linux-clang-assert + # command: cond_spot_run_tests aztec3-circuits-x86_64-linux-clang-assert 1 _tests # - *save_logs # Repeatable config for defining the workflow below. @@ -182,7 +171,5 @@ workflows: filters: *tag_filter - x86_64-linux-clang-assert: filters: *tag_filter - - x86_64-linux-gcc: - filters: *tag_filter - aztec3-circuits-tests: *a3_test #- aztec3-circuit--tests: *a3_test \ No newline at end of file diff --git a/circuits/build_manifest.json b/circuits/build_manifest.json index e721bd8769e..939b153f1db 100644 --- a/circuits/build_manifest.json +++ b/circuits/build_manifest.json @@ -16,11 +16,5 @@ "dockerfile": "dockerfiles/Dockerfile.x86_64-linux-clang-assert", "rebuildPatterns": ["^./"], "dependencies": [] - }, - "aztec3-circuits-x86_64-linux-gcc": { - "buildDir": "./", - "dockerfile": "dockerfiles/Dockerfile.x86_64-linux-gcc", - "rebuildPatterns": ["^./"], - "dependencies": [] } } \ No newline at end of file diff --git a/circuits/build_manifest.sh b/circuits/build_manifest.sh index 9040d211944..0a76eb7ab34 100644 --- a/circuits/build_manifest.sh +++ b/circuits/build_manifest.sh @@ -10,5 +10,4 @@ PROJECTS=( aztec3-circuits-wasm:./:./dockerfiles/Dockerfile.wasm-linux-clang:aztec3-circuits-wasm-linux-clang aztec3-circuits-x86_64-clang:./:./dockerfiles/Dockerfile.x86_64-linux-clang:aztec3-circuits-x86_64-linux-clang aztec3-circuits-x86_64-clang-assert:./:./dockerfiles/Dockerfile.x86_64-linux-clang-assert:aztec3-circuits-x86_64-linux-clang-assert - aztec3-circuits-x86_64-gcc:./:./dockerfiles/Dockerfile.x86_64-linux-gcc:aztec3-circuits-x86_64-linux-gcc ) \ No newline at end of file diff --git a/circuits/cmake/arch.cmake b/circuits/cmake/arch.cmake index 084c0b67df8..1812e8eb3ed 100644 --- a/circuits/cmake/arch.cmake +++ b/circuits/cmake/arch.cmake @@ -5,6 +5,6 @@ if(WASM) add_compile_options(-fno-exceptions -fno-slp-vectorize) endif() -if(NOT WASM AND NOT APPLE) - add_compile_options(-march=skylake-avx512) +if(NOT WASM AND NOT APPLE AND NOT ARM) + add_compile_options(-march=skylake) endif() diff --git a/circuits/cmake/benchmark.cmake b/circuits/cmake/benchmark.cmake index 889ddbbee0a..abcdb7875e4 100644 --- a/circuits/cmake/benchmark.cmake +++ b/circuits/cmake/benchmark.cmake @@ -8,7 +8,7 @@ if(BENCHMARKS) FetchContent_Declare( benchmark GIT_REPOSITORY https://github.com/google/benchmark - GIT_TAG v1.6.1 + GIT_TAG v1.7.1 ) FetchContent_GetProperties(benchmark) diff --git a/circuits/cmake/gtest.cmake b/circuits/cmake/gtest.cmake index 4ba7cf66b70..96e88741e9e 100644 --- a/circuits/cmake/gtest.cmake +++ b/circuits/cmake/gtest.cmake @@ -5,7 +5,8 @@ if(TESTING) FetchContent_Declare( googletest GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG release-1.10.0 + # Version 1.12.1 is not compatible with WASI-SDK 12 + GIT_TAG release-1.10.0 ) FetchContent_GetProperties(googletest) @@ -14,6 +15,13 @@ if(TESTING) add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR} EXCLUDE_FROM_ALL) endif() + # Disable all warning when compiling gtest + target_compile_options( + gtest + PRIVATE + -w + ) + if(WASM) target_compile_definitions( gtest diff --git a/circuits/cmake/module.cmake b/circuits/cmake/module.cmake index 5be976d4e44..c6a156e0e59 100644 --- a/circuits/cmake/module.cmake +++ b/circuits/cmake/module.cmake @@ -23,6 +23,7 @@ function(barretenberg_module MODULE_NAME) OBJECT ${SOURCE_FILES} ) + list(APPEND lib_targets ${MODULE_NAME}_objects) add_library( ${MODULE_NAME} @@ -34,9 +35,9 @@ function(barretenberg_module MODULE_NAME) ${MODULE_NAME} PUBLIC ${ARGN} - barretenberg ${TBB_IMPORTED_TARGETS} ) + list(APPEND lib_targets ${MODULE_NAME}) set(MODULE_LINK_NAME ${MODULE_NAME}) endif() @@ -48,12 +49,12 @@ function(barretenberg_module MODULE_NAME) OBJECT ${TEST_SOURCE_FILES} ) + list(APPEND lib_targets ${MODULE_NAME}_test_objects) target_link_libraries( ${MODULE_NAME}_test_objects PRIVATE gtest - barretenberg env ${TBB_IMPORTED_TARGETS} ) @@ -62,6 +63,7 @@ function(barretenberg_module MODULE_NAME) ${MODULE_NAME}_tests $ ) + list(APPEND exe_targets ${MODULE_NAME}_tests) if(WASM) target_link_options( @@ -94,7 +96,6 @@ function(barretenberg_module MODULE_NAME) ${ARGN} gtest gtest_main - barretenberg env ${TBB_IMPORTED_TARGETS} ) @@ -116,24 +117,24 @@ function(barretenberg_module MODULE_NAME) foreach(FUZZER_SOURCE_FILE ${FUZZERS_SOURCE_FILES}) get_filename_component(FUZZER_NAME_STEM ${FUZZER_SOURCE_FILE} NAME_WE) add_executable( - ${MODULE_NAME}_${FUZZER_NAME_STEM}_fuzzer - ${FUZZER_SOURCE_FILE} + ${MODULE_NAME}_${FUZZER_NAME_STEM}_fuzzer + ${FUZZER_SOURCE_FILE} ) + list(APPEND exe_targets ${MODULE_NAME}_${FUZZER_NAME_STEM}_fuzzer) target_link_options( - ${MODULE_NAME}_${FUZZER_NAME_STEM}_fuzzer + ${MODULE_NAME}_${FUZZER_NAME_STEM}_fuzzer PRIVATE "-fsanitize=fuzzer" ${SANITIZER_OPTIONS} - ) + ) target_link_libraries( - ${MODULE_NAME}_${FUZZER_NAME_STEM}_fuzzer - PRIVATE + ${MODULE_NAME}_${FUZZER_NAME_STEM}_fuzzer + PRIVATE ${MODULE_LINK_NAME} - barretenberg env - ) + ) endforeach() endif() @@ -144,12 +145,12 @@ function(barretenberg_module MODULE_NAME) OBJECT ${BENCH_SOURCE_FILES} ) + list(APPEND lib_targets ${MODULE_NAME}_bench_objects) target_link_libraries( ${MODULE_NAME}_bench_objects PRIVATE benchmark - barretenberg env ${TBB_IMPORTED_TARGETS} ) @@ -158,6 +159,7 @@ function(barretenberg_module MODULE_NAME) ${MODULE_NAME}_bench $ ) + list(APPEND exe_targets ${MODULE_NAME}_bench) target_link_libraries( ${MODULE_NAME}_bench @@ -165,7 +167,6 @@ function(barretenberg_module MODULE_NAME) ${MODULE_LINK_NAME} ${ARGN} benchmark - barretenberg env ${TBB_IMPORTED_TARGETS} ) @@ -176,4 +177,7 @@ function(barretenberg_module MODULE_NAME) WORKING_DIRECTORY ${CMAKE_BINARY_DIR} ) endif() -endfunction() \ No newline at end of file + + set(${MODULE_NAME}_lib_targets ${lib_targets} PARENT_SCOPE) + set(${MODULE_NAME}_exe_targets ${exe_targets} PARENT_SCOPE) +endfunction() diff --git a/circuits/cmake/threading.cmake b/circuits/cmake/threading.cmake index f91b86b3853..1f32c83745d 100644 --- a/circuits/cmake/threading.cmake +++ b/circuits/cmake/threading.cmake @@ -1,20 +1,3 @@ -if(APPLE) - if(CMAKE_C_COMPILER_ID MATCHES "Clang") - set(OpenMP_C_FLAGS "-fopenmp") - set(OpenMP_C_FLAGS_WORK "-fopenmp") - set(OpenMP_C_LIB_NAMES "libomp") - set(OpenMP_C_LIB_NAMES_WORK "libomp") - set(OpenMP_libomp_LIBRARY "$ENV{BREW_PREFIX}/opt/libomp/lib/libomp.dylib") - endif() - if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") - set(OpenMP_CXX_FLAGS "-fopenmp") - set(OpenMP_CXX_FLAGS_WORK "-fopenmp") - set(OpenMP_CXX_LIB_NAMES "libomp") - set(OpenMP_CXX_LIB_NAMES_WORK "libomp") - set(OpenMP_libomp_LIBRARY "$ENV{BREW_PREFIX}/opt/libomp/lib/libomp.dylib") - endif() -endif() - if(MULTITHREADING) find_package(OpenMP REQUIRED) message(STATUS "Multithreading is enabled.") @@ -28,7 +11,7 @@ if(DISABLE_TBB) message(STATUS "Intel Thread Building Blocks is disabled.") add_definitions(-DNO_TBB) else() - find_package(TBB REQUIRED tbb) + find_package(TBB QUIET OPTIONAL_COMPONENTS tbb) if(${TBB_FOUND}) message(STATUS "Intel Thread Building Blocks is enabled.") else() diff --git a/circuits/cmake/toolchains/aarch64-linux-clang.cmake b/circuits/cmake/toolchains/aarch64-linux-clang.cmake new file mode 100644 index 00000000000..e876c0c0385 --- /dev/null +++ b/circuits/cmake/toolchains/aarch64-linux-clang.cmake @@ -0,0 +1,6 @@ +set(ARM ON) +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR aarch64) + +set(CMAKE_C_COMPILER "clang") +set(CMAKE_CXX_COMPILER "clang++") diff --git a/circuits/cmake/toolchains/wasm-linux-clang.cmake b/circuits/cmake/toolchains/wasm-linux-clang.cmake index f8e7796ff57..d410e8833f1 100644 --- a/circuits/cmake/toolchains/wasm-linux-clang.cmake +++ b/circuits/cmake/toolchains/wasm-linux-clang.cmake @@ -9,7 +9,10 @@ set(CMAKE_SYSTEM_VERSION 1) set(CMAKE_SYSTEM_PROCESSOR wasm32) set(triple wasm32-wasi) -set(WASI_SDK_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/src/wasi-sdk-12.0") +if (NOT WASI_SDK_PREFIX) + # can be set by a dependent project + set(WASI_SDK_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/src/wasi-sdk-12.0") +endif() set(CMAKE_C_COMPILER ${WASI_SDK_PREFIX}/bin/clang) set(CMAKE_CXX_COMPILER ${WASI_SDK_PREFIX}/bin/clang++) set(CMAKE_AR ${WASI_SDK_PREFIX}/bin/llvm-ar CACHE STRING "wasi-sdk build") diff --git a/circuits/cmake/toolchains/x86_64-linux-clang.cmake b/circuits/cmake/toolchains/x86_64-linux-clang.cmake index 7df84b7c037..529afc02a49 100644 --- a/circuits/cmake/toolchains/x86_64-linux-clang.cmake +++ b/circuits/cmake/toolchains/x86_64-linux-clang.cmake @@ -1,2 +1,9 @@ -set(CMAKE_C_COMPILER "clang") -set(CMAKE_CXX_COMPILER "clang++") \ No newline at end of file +# Specifically use clang 15 binaries if available. Otherwise fallback on default version. +find_program(CLANGXX_15 "clang++-15") +if (CLANGXX_15) + set(CMAKE_C_COMPILER "clang-15") + set(CMAKE_CXX_COMPILER "clang++-15") +else() + set(CMAKE_C_COMPILER "clang") + set(CMAKE_CXX_COMPILER "clang++") +endif() \ No newline at end of file diff --git a/circuits/cmake/toolchains/x86_64-linux-gcc.cmake b/circuits/cmake/toolchains/x86_64-linux-gcc.cmake index 9cd8af83f78..d1b2790e887 100644 --- a/circuits/cmake/toolchains/x86_64-linux-gcc.cmake +++ b/circuits/cmake/toolchains/x86_64-linux-gcc.cmake @@ -1,5 +1,2 @@ set(CMAKE_C_COMPILER "gcc") -set(CMAKE_CXX_COMPILER "g++") -# TODO(Cody): git rid of this when Adrian's work goes in -add_compile_options(-Wno-uninitialized) -add_compile_options(-Wno-maybe-uninitialized) \ No newline at end of file +set(CMAKE_CXX_COMPILER "g++") \ No newline at end of file diff --git a/circuits/cmake/toolchains/x86_64-linux-gcc10.cmake b/circuits/cmake/toolchains/x86_64-linux-gcc10.cmake index 36fdcfacc85..8ce971f493f 100644 --- a/circuits/cmake/toolchains/x86_64-linux-gcc10.cmake +++ b/circuits/cmake/toolchains/x86_64-linux-gcc10.cmake @@ -1,5 +1,2 @@ set(CMAKE_C_COMPILER "gcc-10") -set(CMAKE_CXX_COMPILER "g++-10") -# TODO(Cody): git rid of this when Adrian's work goes in -add_compile_options(-Wno-uninitialized) -add_compile_options(-Wno-maybe-uninitialized) \ No newline at end of file +set(CMAKE_CXX_COMPILER "g++-10") \ No newline at end of file diff --git a/circuits/dockerfiles/Dockerfile.wasm-linux-clang b/circuits/dockerfiles/Dockerfile.wasm-linux-clang index 8316ea97a25..d4acbe4a283 100644 --- a/circuits/dockerfiles/Dockerfile.wasm-linux-clang +++ b/circuits/dockerfiles/Dockerfile.wasm-linux-clang @@ -7,8 +7,8 @@ WORKDIR /usr/src/aztec3-circuits COPY . . # Build both honk_tests barretenberg.wasm # This ensures that we aren't using features that would be incompatible with WASM for Honk -RUN mkdir build && cd build && cmake -DTOOLCHAIN=wasm-linux-clang .. && cmake --build . --parallel --target honk_tests --target aztec3.wasm +# TODO Add wasm target when ready: --target aztec3.wasm +RUN mkdir build && cd build && cmake -DTOOLCHAIN=wasm-linux-clang .. && cmake --build . --parallel -FROM alpine:3.17 -COPY --from=builder /usr/src/aztec3-circuits/build/bin/aztec3.wasm /usr/src/aztec3-circuits/build/bin/aztec3.wasm -COPY --from=builder /usr/src/aztec3-circuits/build/bin/*_tests /usr/src/aztec3-circuits/build/bin/ +#FROM alpine:3.17 +#COPY --from=builder /usr/src/aztec3-circuits/build/bin/aztec3.wasm /usr/src/aztec3-circuits/build/bin/aztec3.wasm From 4428c0139b0f1825bffe99af9ef9acb78e9d5bad Mon Sep 17 00:00:00 2001 From: Michael Connor Date: Mon, 20 Feb 2023 09:12:11 +0000 Subject: [PATCH 041/166] fix: partal commitment syntax check (#18) --- .../src/aztec3/circuits/apps/state_vars/mapping_state_var.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.hpp b/circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.hpp index 551538a6671..0f3916345b9 100644 --- a/circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.hpp +++ b/circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.hpp @@ -58,7 +58,7 @@ template class MappingStateVar : public StateVar V& operator[](std::optional const& key) { return this->at(key); }; V& operator[](std::string const& question_mark) { - ASSERT(question_mark != "?"); + ASSERT(question_mark == "?"); return this->at(std::nullopt); }; From 4ed940fc25a4ed090e25727536979a0fb262f46b Mon Sep 17 00:00:00 2001 From: David Banks <47112877+dbanks12@users.noreply.github.com> Date: Tue, 21 Feb 2023 08:49:17 -0500 Subject: [PATCH 042/166] Run wasm tests ci (#14) * added wasm-assert dockerfile and updated CI to run wasmtime tests * build manifests include wasm-assert for CI testing * add separate build and test jobs for wasm assert / tests in CI --- circuits/.circleci/config.yml | 30 +++++++++++++++++++ circuits/build_manifest.json | 6 ++++ circuits/build_manifest.sh | 1 + .../Dockerfile.wasm-linux-clang-assert | 13 ++++++++ circuits/scripts/run_tests | 10 ++++++- 5 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 circuits/dockerfiles/Dockerfile.wasm-linux-clang-assert diff --git a/circuits/.circleci/config.yml b/circuits/.circleci/config.yml index 41feb3a58c7..7a47092bf20 100644 --- a/circuits/.circleci/config.yml +++ b/circuits/.circleci/config.yml @@ -106,6 +106,17 @@ jobs: name: 'Build' command: cond_spot_run_build aztec3-circuits-wasm-linux-clang 64 + wasm-linux-clang-assert: + docker: + - image: aztecprotocol/alpine-build-image + resource_class: small + steps: + - *checkout + - *setup_env + - run: + name: 'Build' + command: cond_spot_run_build aztec3-circuits-wasm-linux-clang-assert 64 + x86_64-linux-clang: docker: - image: aztecprotocol/alpine-build-image @@ -128,6 +139,18 @@ jobs: name: 'Build' command: cond_spot_run_build aztec3-circuits-x86_64-linux-clang-assert 64 + aztec3-circuits-wasm-tests: + docker: + - image: aztecprotocol/alpine-build-image + resource_class: small + steps: + - *checkout + - *setup_env + - run: + name: 'Test' + command: cond_spot_run_tests aztec3-circuits-wasm-linux-clang-assert 1 a3-tests USE_WASM_TIME + - *save_logs + aztec3-circuits-tests: docker: - image: aztecprotocol/alpine-build-image @@ -157,6 +180,10 @@ tag_regex: &tag_regex /v[0-9]+(\.[0-9]+)*(-[a-zA-Z-]+\.[0-9]+)?/ tag_filter: &tag_filter tags: only: *tag_regex +a3_wasm_test: &a3_wasm_test + requires: + - wasm-linux-clang-assert + filters: *tag_filter a3_test: &a3_test requires: - x86_64-linux-clang-assert @@ -167,9 +194,12 @@ workflows: jobs: - wasm-linux-clang: filters: *tag_filter + - wasm-linux-clang-assert: + filters: *tag_filter - x86_64-linux-clang: filters: *tag_filter - x86_64-linux-clang-assert: filters: *tag_filter + - aztec3-circuits-wasm-tests: *a3_wasm_test - aztec3-circuits-tests: *a3_test #- aztec3-circuit--tests: *a3_test \ No newline at end of file diff --git a/circuits/build_manifest.json b/circuits/build_manifest.json index 939b153f1db..7a1c4ddac50 100644 --- a/circuits/build_manifest.json +++ b/circuits/build_manifest.json @@ -5,6 +5,12 @@ "rebuildPatterns": ["^./"], "dependencies": [] }, + "aztec3-circuits-wasm-linux-clang-assert": { + "buildDir": ".", + "dockerfile": "dockerfiles/Dockerfile.wasm-linux-clang-assert", + "rebuildPatterns": ["^./"], + "dependencies": [] + }, "aztec3-circuits-x86_64-linux-clang": { "buildDir": ".", "dockerfile": "dockerfiles/Dockerfile.x86_64-linux-clang", diff --git a/circuits/build_manifest.sh b/circuits/build_manifest.sh index 0a76eb7ab34..609e769ee9f 100644 --- a/circuits/build_manifest.sh +++ b/circuits/build_manifest.sh @@ -8,6 +8,7 @@ # If wanting to just see if docker images actually build, you can temporarily uncomment required projects. PROJECTS=( aztec3-circuits-wasm:./:./dockerfiles/Dockerfile.wasm-linux-clang:aztec3-circuits-wasm-linux-clang + aztec3-circuits-wasm-assert:./:./dockerfiles/Dockerfile.wasm-linux-clang-assert:aztec3-circuits-wasm-linux-clang-assert aztec3-circuits-x86_64-clang:./:./dockerfiles/Dockerfile.x86_64-linux-clang:aztec3-circuits-x86_64-linux-clang aztec3-circuits-x86_64-clang-assert:./:./dockerfiles/Dockerfile.x86_64-linux-clang-assert:aztec3-circuits-x86_64-linux-clang-assert ) \ No newline at end of file diff --git a/circuits/dockerfiles/Dockerfile.wasm-linux-clang-assert b/circuits/dockerfiles/Dockerfile.wasm-linux-clang-assert new file mode 100644 index 00000000000..a0ec976eb84 --- /dev/null +++ b/circuits/dockerfiles/Dockerfile.wasm-linux-clang-assert @@ -0,0 +1,13 @@ +FROM ubuntu:kinetic AS builder +RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y build-essential wget git libssl-dev cmake curl binaryen +RUN curl https://wasmtime.dev/install.sh -sSf | bash /dev/stdin --version v3.0.1 +WORKDIR /usr/src/aztec3-circuits/src +RUN curl -s -L https://github.com/CraneStation/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-linux.tar.gz | tar zxfv - +WORKDIR /usr/src/aztec3-circuits +COPY . . +# Build both honk_tests barretenberg.wasm +# This ensures that we aren't using features that would be incompatible with WASM for Honk +RUN mkdir build && cd build && cmake -DTOOLCHAIN=wasm-linux-clang .. && cmake --build . --parallel + +#FROM alpine:3.17 +#COPY --from=builder /usr/src/aztec3-circuits/build/bin/*_tests /usr/src/aztec3-circuits/build/bin/ diff --git a/circuits/scripts/run_tests b/circuits/scripts/run_tests index 6ee356116b3..1baea9cc2de 100755 --- a/circuits/scripts/run_tests +++ b/circuits/scripts/run_tests @@ -3,6 +3,8 @@ set -e NUM_TRANSCRIPTS=$1 TESTS=$2 +WASM_MODE=$3 +shift shift shift @@ -16,10 +18,16 @@ if [ -f "$TESTS" ]; then TESTS=$(cat $TESTS | tr '\n' ' ') fi +if [ -z "$WASM_MODE" ]; then + TEST_CMD="./bin/\$BIN $@" +else + TEST_CMD="wasmtime --dir .. bin/\$BIN $@" +fi + docker run --rm -t $IMAGE_URI /bin/sh -c "\ set -e; \ cd /usr/src/aztec3-circuits/barretenberg/cpp/srs_db; \ ./download_ignition.sh $NUM_TRANSCRIPTS; \ ./download_ignition_lagrange.sh 24; \ cd /usr/src/aztec3-circuits/build; \ - for BIN in $TESTS; do ./bin/\$BIN $@; done" + for BIN in $TESTS; do $TEST_CMD; done" From b7eb097bf05e6221dbb0fb8e9cc819a7810ab561 Mon Sep 17 00:00:00 2001 From: David Banks <47112877+dbanks12@users.noreply.github.com> Date: Tue, 21 Feb 2023 08:49:40 -0500 Subject: [PATCH 043/166] Add wasm to bootstrap (#15) --- circuits/bootstrap.sh | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/circuits/bootstrap.sh b/circuits/bootstrap.sh index 94609d44d72..c06c00db95f 100755 --- a/circuits/bootstrap.sh +++ b/circuits/bootstrap.sh @@ -54,4 +54,16 @@ fi mkdir -p build && cd build cmake -DCMAKE_BUILD_TYPE=RelWithAssert -DTOOLCHAIN=$TOOLCHAIN .. cmake --build . --parallel ${@/#/--target } +cd .. + +# Install the webassembly toolchain. +WASI_VERSION=12 +cd ./src +curl -s -L https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-$WASI_VERSION/wasi-sdk-$WASI_VERSION.0-$OS.tar.gz | tar zxfv - +cd .. + +# Build WASM. +mkdir -p build-wasm && cd build-wasm +cmake -DTOOLCHAIN=wasm-linux-clang .. +cmake --build . --parallel # --target aztec3.wasm cd .. \ No newline at end of file From 280af31f3cd90cebe0d74041d4cb5f59878a4c61 Mon Sep 17 00:00:00 2001 From: Michael Connor Date: Tue, 21 Feb 2023 13:52:00 +0000 Subject: [PATCH 044/166] add .vscode to gitignore (#17) --- circuits/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/circuits/.gitignore b/circuits/.gitignore index 37d504a6d67..cedb78bc7ec 100644 --- a/circuits/.gitignore +++ b/circuits/.gitignore @@ -1,4 +1,5 @@ .cache/ +.vscode/ build/ build-wasm/ src/wasi-sdk-* From f6d654b4a723ef6deb7e4496c1145b2dd8cd776d Mon Sep 17 00:00:00 2001 From: Michael Connor Date: Tue, 21 Feb 2023 13:52:20 +0000 Subject: [PATCH 045/166] Create LICENSE (#8) --- circuits/LICENSE | 201 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 circuits/LICENSE diff --git a/circuits/LICENSE b/circuits/LICENSE new file mode 100644 index 00000000000..261eeb9e9f8 --- /dev/null +++ b/circuits/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. From d49fddfa14478f6f402018b00c692dff6785ed5a Mon Sep 17 00:00:00 2001 From: Suyash Bagad Date: Wed, 22 Feb 2023 15:44:02 +0530 Subject: [PATCH 046/166] Correction in Submodule Update in `bootstrap.sh` (#22) * Remove `--remote` flag. * Update submodule. --- circuits/barretenberg | 2 +- circuits/bootstrap.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/circuits/barretenberg b/circuits/barretenberg index 3f7dda65b58..5629aeeeaa1 160000 --- a/circuits/barretenberg +++ b/circuits/barretenberg @@ -1 +1 @@ -Subproject commit 3f7dda65b587afe34496bbe9abc29c6523125e64 +Subproject commit 5629aeeeaa11aad77cfa6fc5c0bc46d751983986 diff --git a/circuits/bootstrap.sh b/circuits/bootstrap.sh index c06c00db95f..b2084f13ebb 100755 --- a/circuits/bootstrap.sh +++ b/circuits/bootstrap.sh @@ -2,7 +2,7 @@ set -e # Update the submodule -git submodule update --init --recursive --remote +git submodule update --init --recursive # Clean. rm -rf ./build From 52c15fc121ff5985edf5ec250f25a484bed110bb Mon Sep 17 00:00:00 2001 From: Suyash Bagad Date: Wed, 22 Feb 2023 15:44:48 +0530 Subject: [PATCH 047/166] Make aggregator composer-agnostic. (#21) Fix. --- circuits/src/aztec3/circuits/kernel/private/init.hpp | 2 +- circuits/src/aztec3/circuits/recursion/aggregator.hpp | 10 +++++----- .../circuits/recursion/play_recursive_circuit.hpp | 1 - 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/circuits/src/aztec3/circuits/kernel/private/init.hpp b/circuits/src/aztec3/circuits/kernel/private/init.hpp index ddd4e89a5cf..c15272db478 100644 --- a/circuits/src/aztec3/circuits/kernel/private/init.hpp +++ b/circuits/src/aztec3/circuits/kernel/private/init.hpp @@ -18,7 +18,7 @@ namespace aztec3::circuits::kernel::private_kernel { using Composer = plonk::stdlib::types::Composer; using plonk::stdlib::types::UnrolledProver; -using Aggregator = aztec3::circuits::recursion::TurboAggregator; +using Aggregator = aztec3::circuits::recursion::Aggregator; // Generic: using CT = plonk::stdlib::types::CircuitTypes; diff --git a/circuits/src/aztec3/circuits/recursion/aggregator.hpp b/circuits/src/aztec3/circuits/recursion/aggregator.hpp index 279fe0673a9..1cb98367012 100644 --- a/circuits/src/aztec3/circuits/recursion/aggregator.hpp +++ b/circuits/src/aztec3/circuits/recursion/aggregator.hpp @@ -9,7 +9,7 @@ namespace aztec3::circuits::recursion { // These are all Circuit Types! // using plonk::stdlib::recursion::recursion_output; -using plonk::stdlib::recursion::recursive_turbo_verifier_settings; +using plonk::stdlib::types::recursive_inner_verifier_settings; // using plonk::stdlib::recursion::verification_key; using plonk::stdlib::recursion::verify_proof; // using plonk::stdlib::types::bn254; @@ -18,7 +18,7 @@ using CT = plonk::stdlib::types::CircuitTypes; using NT = plonk::stdlib::types::NativeTypes; using transcript::Manifest; -// class TurboAggregator { +// class Aggregator { // public: // // Circuit Types: // using AggregationObject = recursion_output; @@ -35,14 +35,14 @@ using transcript::Manifest; // std::shared_ptr> recursive_vk = verification_key::from_witness(composer, vk); // const transcript::Manifest recursive_manifest = Composer::create_unrolled_manifest(vk->num_public_inputs); -// AggregationObject result = verify_proof>( +// AggregationObject result = verify_proof>( // composer, recursive_vk, recursive_manifest, proof, recursion_output); // return result; // } // }; -class TurboAggregator { +class Aggregator { public: static CT::AggregationObject aggregate(Composer* composer, const std::shared_ptr& vk, @@ -52,7 +52,7 @@ class TurboAggregator { { const Manifest recursive_manifest = Composer::create_unrolled_manifest(num_public_inputs); - CT::AggregationObject result = verify_proof>( + CT::AggregationObject result = verify_proof( composer, vk, recursive_manifest, proof, recursion_output); return result; diff --git a/circuits/src/aztec3/circuits/recursion/play_recursive_circuit.hpp b/circuits/src/aztec3/circuits/recursion/play_recursive_circuit.hpp index fb56e903433..f43b0455899 100644 --- a/circuits/src/aztec3/circuits/recursion/play_recursive_circuit.hpp +++ b/circuits/src/aztec3/circuits/recursion/play_recursive_circuit.hpp @@ -5,7 +5,6 @@ namespace aztec3::circuits::recursion { -using Aggregator = TurboAggregator; using plonk::stdlib::types::Composer; using CT = plonk::stdlib::types::CircuitTypes; using NT = plonk::stdlib::types::NativeTypes; From 2bfcdf4d70e5584e9946cc0d8de7614f6a654177 Mon Sep 17 00:00:00 2001 From: David Banks <47112877+dbanks12@users.noreply.github.com> Date: Wed, 22 Feb 2023 10:53:18 -0500 Subject: [PATCH 048/166] Final fixes to CI (#20) * wasm assert image uses ubuntu in final layer as I couldnt get wasmtime to work in alpine * build manifest rebuildpattern '^./' does not work, but '^.' does * only only bash shift wasm arg to ./run_tests when that arg exists --- circuits/build_manifest.json | 8 ++++---- .../dockerfiles/Dockerfile.wasm-linux-clang-assert | 10 ++++++---- circuits/scripts/run_tests | 6 ++++-- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/circuits/build_manifest.json b/circuits/build_manifest.json index 7a1c4ddac50..1a574840014 100644 --- a/circuits/build_manifest.json +++ b/circuits/build_manifest.json @@ -2,25 +2,25 @@ "aztec3-circuits-wasm-linux-clang": { "buildDir": ".", "dockerfile": "dockerfiles/Dockerfile.wasm-linux-clang", - "rebuildPatterns": ["^./"], + "rebuildPatterns": ["^."], "dependencies": [] }, "aztec3-circuits-wasm-linux-clang-assert": { "buildDir": ".", "dockerfile": "dockerfiles/Dockerfile.wasm-linux-clang-assert", - "rebuildPatterns": ["^./"], + "rebuildPatterns": ["^."], "dependencies": [] }, "aztec3-circuits-x86_64-linux-clang": { "buildDir": ".", "dockerfile": "dockerfiles/Dockerfile.x86_64-linux-clang", - "rebuildPatterns": ["^./"], + "rebuildPatterns": ["^."], "dependencies": [] }, "aztec3-circuits-x86_64-linux-clang-assert": { "buildDir": ".", "dockerfile": "dockerfiles/Dockerfile.x86_64-linux-clang-assert", - "rebuildPatterns": ["^./"], + "rebuildPatterns": ["^."], "dependencies": [] } } \ No newline at end of file diff --git a/circuits/dockerfiles/Dockerfile.wasm-linux-clang-assert b/circuits/dockerfiles/Dockerfile.wasm-linux-clang-assert index a0ec976eb84..24e3cfd8833 100644 --- a/circuits/dockerfiles/Dockerfile.wasm-linux-clang-assert +++ b/circuits/dockerfiles/Dockerfile.wasm-linux-clang-assert @@ -1,6 +1,5 @@ FROM ubuntu:kinetic AS builder -RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y build-essential wget git libssl-dev cmake curl binaryen -RUN curl https://wasmtime.dev/install.sh -sSf | bash /dev/stdin --version v3.0.1 +RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y build-essential git libssl-dev cmake curl binaryen WORKDIR /usr/src/aztec3-circuits/src RUN curl -s -L https://github.com/CraneStation/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-linux.tar.gz | tar zxfv - WORKDIR /usr/src/aztec3-circuits @@ -9,5 +8,8 @@ COPY . . # This ensures that we aren't using features that would be incompatible with WASM for Honk RUN mkdir build && cd build && cmake -DTOOLCHAIN=wasm-linux-clang .. && cmake --build . --parallel -#FROM alpine:3.17 -#COPY --from=builder /usr/src/aztec3-circuits/build/bin/*_tests /usr/src/aztec3-circuits/build/bin/ +FROM ubuntu:kinetic +RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y xz-utils curl +RUN curl https://wasmtime.dev/install.sh -sSf | bash /dev/stdin --version v3.0.1 +COPY --from=builder /usr/src/aztec3-circuits/barretenberg/cpp/srs_db /usr/src/aztec3-circuits/barretenberg/cpp/srs_db +COPY --from=builder /usr/src/aztec3-circuits/build/bin/*_tests /usr/src/aztec3-circuits/build/bin/ diff --git a/circuits/scripts/run_tests b/circuits/scripts/run_tests index 1baea9cc2de..53c625425b8 100755 --- a/circuits/scripts/run_tests +++ b/circuits/scripts/run_tests @@ -3,10 +3,12 @@ set -e NUM_TRANSCRIPTS=$1 TESTS=$2 -WASM_MODE=$3 -shift shift shift +if [ -n "$3" ]; then + WASM_MODE=$3 + shift +fi $(aws ecr get-login --region us-east-2 --no-include-email) 2> /dev/null From df2359af2a5ea956dcc32586f856092697d6cf88 Mon Sep 17 00:00:00 2001 From: David Banks <47112877+dbanks12@users.noreply.github.com> Date: Wed, 22 Feb 2023 10:53:43 -0500 Subject: [PATCH 049/166] rename tx_object -> tx_request (same for signed_) (#1) * rename tx_object -> tx_request * signed tx object -> signed tx request --- .../architecture/contracts/transactions.md | 8 +-- .../kernel-circuits/private-kernel.md | 4 +- .../abis/private_kernel/private_inputs.hpp | 6 +- ...ed_tx_object.hpp => signed_tx_request.hpp} | 26 ++++----- .../abis/{tx_object.hpp => tx_request.hpp} | 56 +++++++++---------- .../aztec3/circuits/kernel/private/.test.cpp | 28 +++++----- 6 files changed, 64 insertions(+), 64 deletions(-) rename circuits/src/aztec3/circuits/abis/{signed_tx_object.hpp => signed_tx_request.hpp} (56%) rename circuits/src/aztec3/circuits/abis/{tx_object.hpp => tx_request.hpp} (53%) diff --git a/circuits/specs/src/architecture/contracts/transactions.md b/circuits/specs/src/architecture/contracts/transactions.md index 0cd7ab1dc40..71e407611a6 100644 --- a/circuits/specs/src/architecture/contracts/transactions.md +++ b/circuits/specs/src/architecture/contracts/transactions.md @@ -9,7 +9,7 @@ Contracts can be deployed with a special type of call (a contractDeploymentCall) [^1]: Most transactions will likely begin with _two_ callstack items: one for the actual call, and one to pay the rollup provider a fee (by invoking some payment circuit). [Fee payments](../fees/fees.md) still need to be spec'd out. -## `TxObject` +## `TxRequest` | Value | Description | | --- | --- | @@ -57,7 +57,7 @@ Currently, the fee model is inspired by EIP-1559. | `payFeeFromPublicL2`: `Bool` | Provides a way of paying for private L2 function execution from a public L2 circuit. This input being `true` will cause the rollup provider to look for an `isFeePayment` tx in the _public_ callStack. | | `feeAmount`: `Field` | | | `feeStandardId`: `Field` | | -| `signedFeePaymentTxHash`: `Field` | Hash of a [SignedTxObject](#signedtxobject) | +| `signedFeePaymentTxHash`: `Field` | Hash of a [SignedTxRequest](#signedTxRequest) | ## `TxContext` @@ -73,11 +73,11 @@ Currently, the fee model is inspired by EIP-1559. | `referenceRollupNum`: `Field` | The rollup number which should be used if referring to any historic tree values. Useful if the proof needs to use a particular tree state snapshot of a particular historic rollup. | -## `SignedTxObject` +## `SignedTxRequest` | Value | Description | | --- | --- | -| `txObject`: [`TxObject`](#txobject) | The TxObject being signed over. | +| `TxRequest`: [`TxRequest`](#TxRequest) | The TxRequest being signed over. | | r, s, v | The usual ecdsa signature values. | --- diff --git a/circuits/specs/src/architecture/kernel-circuits/private-kernel.md b/circuits/specs/src/architecture/kernel-circuits/private-kernel.md index beabbeb33fc..538dda27980 100644 --- a/circuits/specs/src/architecture/kernel-circuits/private-kernel.md +++ b/circuits/specs/src/architecture/kernel-circuits/private-kernel.md @@ -30,7 +30,7 @@ | Value | Description | | -------- | -------- | -| `signedTxObject`: [`SignedTxObject`](../contracts/transactions.md#signedtxobject) | Only required to validate permissions for the first call in the callstack. TODO: generalise for account abstraction. | +| `signedTxRequest`: [`SignedTxRequest`](../contracts/transactions.md#signedTxRequest) | Only required to validate permissions for the first call in the callstack. TODO: generalise for account abstraction. | | `previousKernel`: [`PreviousKernelData`](#previouskerneldata) | Previous kernel data (empty if this is the first iteration). | | `privateCall`: [`PrivateCallData`](#privatecalldata) | Details about the next call which will be popped of the callstack during this kernel recursion. | @@ -138,7 +138,7 @@ Base case: - Set `constants.recursionContext.isConstructor := true` - This public input will percolate to -- and be checked by -- the Contract Deployment Kernel Circuit which calls this constructor. This check is required to prevent a person from circumventing the ECDSA signature check by simply setting `isConstructor = true` when making a private call. If this aggregated kernel snark reaches the rollup circuit without this flag being reset to `false` by the Contract Deployment Kernel Circuit (to say "yes, this kernel was indeed a constructor for a Contract Deployment Kernel Circuit"), then the entire tx will be rejected by the rollup circuit. - Else: - Set `constants.recursionContext.isConstructor := false` - - Verify the ECDSA signature contained in `signedTxObject`. + - Verify the ECDSA signature contained in `signedTxRequest`. - Validate the `callContext`. Usually the correctness of a callContext is checked between the `privateCall` and all the new calls it makes (see later in this logic). That means for this 'Base case', those checks haven't been done for this `privateCall` (since there was no prior iteration of this kernel circuit to make those checks). - If `privateCall.isDelegateCall == true || privateCall.isStaticCall == true`: - Revert - a user cannot make a delegateCall or staticCall. diff --git a/circuits/src/aztec3/circuits/abis/private_kernel/private_inputs.hpp b/circuits/src/aztec3/circuits/abis/private_kernel/private_inputs.hpp index b7eff761d6d..3a4e696f7da 100644 --- a/circuits/src/aztec3/circuits/abis/private_kernel/private_inputs.hpp +++ b/circuits/src/aztec3/circuits/abis/private_kernel/private_inputs.hpp @@ -3,7 +3,7 @@ #include "accumulated_data.hpp" #include "previous_kernel_data.hpp" #include "private_call_data.hpp" -#include "../signed_tx_object.hpp" +#include "../signed_tx_request.hpp" #include #include @@ -21,7 +21,7 @@ template struct PrivateInputs { typedef typename NCT::fr fr; // typedef typename NCT::signature Signature; - SignedTxObject signed_tx_object; + SignedTxRequest signed_tx_request; PreviousKernelData previous_kernel; PrivateCallData private_call; @@ -31,7 +31,7 @@ template struct PrivateInputs { PrivateInputs> private_inputs = { // plonk::stdlib::schnorr::convert_signature(&composer, signature), - signed_tx_object.to_circuit_type(composer), + signed_tx_request.to_circuit_type(composer), previous_kernel.to_circuit_type(composer), private_call.to_circuit_type(composer), }; diff --git a/circuits/src/aztec3/circuits/abis/signed_tx_object.hpp b/circuits/src/aztec3/circuits/abis/signed_tx_request.hpp similarity index 56% rename from circuits/src/aztec3/circuits/abis/signed_tx_object.hpp rename to circuits/src/aztec3/circuits/abis/signed_tx_request.hpp index 2c7047a7d8f..1be3f6b4f8f 100644 --- a/circuits/src/aztec3/circuits/abis/signed_tx_object.hpp +++ b/circuits/src/aztec3/circuits/abis/signed_tx_request.hpp @@ -1,6 +1,6 @@ #pragma once -#include "tx_object.hpp" +#include "tx_request.hpp" #include #include @@ -13,11 +13,11 @@ using plonk::stdlib::witness_t; using plonk::stdlib::types::CircuitTypes; using plonk::stdlib::types::NativeTypes; -template struct SignedTxObject { - TxObject tx_object; +template struct SignedTxRequest { + TxRequest tx_request; // Signature signature; // TODO: import some kind of signature - template SignedTxObject> to_circuit_type(Composer& composer) const + template SignedTxRequest> to_circuit_type(Composer& composer) const { static_assert((std::is_same::value)); @@ -25,31 +25,31 @@ template struct SignedTxObject { // auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; auto to_circuit_type = [&](auto& e) { return e.to_circuit_type(composer); }; - SignedTxObject> signed_tx_object = { - to_circuit_type(tx_object), + SignedTxRequest> signed_tx_request = { + to_circuit_type(tx_request), }; - return signed_tx_object; + return signed_tx_request; }; }; -template void read(uint8_t const*& it, SignedTxObject& signed_tx_object) +template void read(uint8_t const*& it, SignedTxRequest& signed_tx_request) { using serialize::read; - read(it, signed_tx_object.tx_object); + read(it, signed_tx_request.tx_request); }; -template void write(std::vector& buf, SignedTxObject const& signed_tx_object) +template void write(std::vector& buf, SignedTxRequest const& signed_tx_request) { using serialize::write; - write(buf, signed_tx_object.tx_object); + write(buf, signed_tx_request.tx_request); }; -template std::ostream& operator<<(std::ostream& os, SignedTxObject const& signed_tx_object) +template std::ostream& operator<<(std::ostream& os, SignedTxRequest const& signed_tx_request) { - return os << "tx_object: " << signed_tx_object.tx_object << "\n"; + return os << "tx_request: " << signed_tx_request.tx_request << "\n"; } } // namespace aztec3::circuits::abis \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/abis/tx_object.hpp b/circuits/src/aztec3/circuits/abis/tx_request.hpp similarity index 53% rename from circuits/src/aztec3/circuits/abis/tx_object.hpp rename to circuits/src/aztec3/circuits/abis/tx_request.hpp index 4ecc886d4fb..245dce466c8 100644 --- a/circuits/src/aztec3/circuits/abis/tx_object.hpp +++ b/circuits/src/aztec3/circuits/abis/tx_request.hpp @@ -12,7 +12,7 @@ using plonk::stdlib::witness_t; using plonk::stdlib::types::CircuitTypes; using plonk::stdlib::types::NativeTypes; -template struct TxObject { +template struct TxRequest { typedef typename NCT::address address; // typedef typename NCT::grumpkin_point grumpkin_point; typedef typename NCT::fr fr; @@ -26,7 +26,7 @@ template struct TxObject { TxContext tx_context; fr chain_id; - template TxObject> to_circuit_type(Composer& composer) const + template TxRequest> to_circuit_type(Composer& composer) const { static_assert((std::is_same::value)); @@ -34,51 +34,51 @@ template struct TxObject { auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; auto to_circuit_type = [&](auto& e) { return e.to_circuit_type(composer); }; - TxObject> tx_object = { + TxRequest> tx_request = { to_ct(from), to_ct(to), to_circuit_type(function_signature), to_ct(args), to_ct(nonce), to_circuit_type(tx_context), to_ct(chain_id), }; - return tx_object; + return tx_request; }; }; -template void read(uint8_t const*& it, TxObject& tx_object) +template void read(uint8_t const*& it, TxRequest& tx_request) { using serialize::read; - read(it, tx_object.from); - read(it, tx_object.to); - read(it, tx_object.function_signature); - read(it, tx_object.args); - read(it, tx_object.nonce); - read(it, tx_object.tx_context); - read(it, tx_object.chain_id); + read(it, tx_request.from); + read(it, tx_request.to); + read(it, tx_request.function_signature); + read(it, tx_request.args); + read(it, tx_request.nonce); + read(it, tx_request.tx_context); + read(it, tx_request.chain_id); }; -template void write(std::vector& buf, TxObject const& tx_object) +template void write(std::vector& buf, TxRequest const& tx_request) { using serialize::write; - write(buf, tx_object.from); - write(buf, tx_object.to); - write(buf, tx_object.function_signature); - write(buf, tx_object.args); - write(buf, tx_object.nonce); - write(buf, tx_object.tx_context); - write(buf, tx_object.chain_id); + write(buf, tx_request.from); + write(buf, tx_request.to); + write(buf, tx_request.function_signature); + write(buf, tx_request.args); + write(buf, tx_request.nonce); + write(buf, tx_request.tx_context); + write(buf, tx_request.chain_id); }; -template std::ostream& operator<<(std::ostream& os, TxObject const& tx_object) +template std::ostream& operator<<(std::ostream& os, TxRequest const& tx_request) { - return os << "from: " << tx_object.from << "\n" - << "to: " << tx_object.to << "\n" - << "function_signature: " << tx_object.function_signature << "\n" - << "args: " << tx_object.args << "\n" - << "nonce: " << tx_object.nonce << "\n" - << "tx_context: " << tx_object.tx_context << "\n" - << "chain_id: " << tx_object.chain_id << "\n"; + return os << "from: " << tx_request.from << "\n" + << "to: " << tx_request.to << "\n" + << "function_signature: " << tx_request.function_signature << "\n" + << "args: " << tx_request.args << "\n" + << "nonce: " << tx_request.nonce << "\n" + << "tx_context: " << tx_request.tx_context << "\n" + << "chain_id: " << tx_request.chain_id << "\n"; } } // namespace aztec3::circuits::abis \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/kernel/private/.test.cpp b/circuits/src/aztec3/circuits/kernel/private/.test.cpp index b2b7d2d1b6a..d198182c319 100644 --- a/circuits/src/aztec3/circuits/kernel/private/.test.cpp +++ b/circuits/src/aztec3/circuits/kernel/private/.test.cpp @@ -12,9 +12,9 @@ #include #include #include -#include +#include #include -#include +#include #include #include #include @@ -47,9 +47,9 @@ using aztec3::circuits::abis::ContractDeploymentData; using aztec3::circuits::abis::FunctionSignature; using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; using aztec3::circuits::abis::PrivateCircuitPublicInputs; -using aztec3::circuits::abis::SignedTxObject; +using aztec3::circuits::abis::SignedTxRequest; using aztec3::circuits::abis::TxContext; -using aztec3::circuits::abis::TxObject; +using aztec3::circuits::abis::TxRequest; using aztec3::circuits::abis::private_kernel::AccumulatedData; using aztec3::circuits::abis::private_kernel::ConstantData; @@ -125,11 +125,11 @@ TEST(private_kernel_tests, test_deposit) std::shared_ptr deposit_vk = deposit_composer.compute_verification_key(); //*************************************************************************** - // We can create a TxObject from some of the above data. Users must sign a TxObject in order to give permission for - // a tx to take place - creating a SignedTxObject. + // We can create a TxRequest from some of the above data. Users must sign a TxRequest in order to give permission + // for a tx to take place - creating a SignedTxRequest. //*************************************************************************** - TxObject deposit_tx_object = TxObject{ + TxRequest deposit_tx_request = TxRequest{ .from = tx_origin, .to = escrow_contract_address, .function_signature = function_signature, @@ -146,10 +146,10 @@ TEST(private_kernel_tests, test_deposit) .chain_id = 1, }; - SignedTxObject signed_deposit_tx_object = SignedTxObject{ - .tx_object = deposit_tx_object, + SignedTxRequest signed_deposit_tx_request = SignedTxRequest{ + .tx_request = deposit_tx_request, - // .signature = TODO: need a method for signing a TxObject. + // .signature = TODO: need a method for signing a TxRequest. }; //*************************************************************************** @@ -165,9 +165,9 @@ TEST(private_kernel_tests, test_deposit) // certain checks if we're handling the 'base case' of the recursion. // I've chosen the former, for now. const CallStackItem deposit_call_stack_item{ - .contract_address = deposit_tx_object.to, + .contract_address = deposit_tx_request.to, - .function_signature = deposit_tx_object.function_signature, + .function_signature = deposit_tx_request.function_signature, .public_inputs = deposit_public_inputs, }; @@ -193,7 +193,7 @@ TEST(private_kernel_tests, test_deposit) // .contract_tree_root = // .private_kernel_vk_tree_root = }, - .tx_context = deposit_tx_object.tx_context, + .tx_context = deposit_tx_request.tx_context, }, .is_private = true, @@ -218,7 +218,7 @@ TEST(private_kernel_tests, test_deposit) Composer private_kernel_composer = Composer("../barretenberg/cpp/srs_db/ignition"); PrivateInputs private_inputs = PrivateInputs{ - .signed_tx_object = signed_deposit_tx_object, + .signed_tx_request = signed_deposit_tx_request, .previous_kernel = PreviousKernelData{ From 142bb5a16e7fcdf523d390431d57b4bab4893eb9 Mon Sep 17 00:00:00 2001 From: David Banks <47112877+dbanks12@users.noreply.github.com> Date: Wed, 22 Feb 2023 11:39:01 -0500 Subject: [PATCH 050/166] `TxContext.hash()` (#3) * tx context hash using proper generator * implement TxContext.hash() --- circuits/src/aztec3/circuits/abis/tx_context.hpp | 10 ++++++++++ circuits/src/aztec3/constants.hpp | 1 + 2 files changed, 11 insertions(+) diff --git a/circuits/src/aztec3/circuits/abis/tx_context.hpp b/circuits/src/aztec3/circuits/abis/tx_context.hpp index cc8b3630dcd..be34867c1b3 100644 --- a/circuits/src/aztec3/circuits/abis/tx_context.hpp +++ b/circuits/src/aztec3/circuits/abis/tx_context.hpp @@ -55,6 +55,16 @@ template struct TxContext { contract_deployment_data.set_public(); reference_block_num.set_public(); } + + fr hash() const + { + std::vector inputs = { + fr(is_fee_payment_tx), fr(is_rebate_payment_tx), fr(is_contract_deployment_tx), + contract_deployment_data.hash(), reference_block_num, + }; + + return NCT::compress(inputs, GeneratorIndex::TX_CONTEXT); + } }; template void read(uint8_t const*& it, TxContext& tx_context) diff --git a/circuits/src/aztec3/constants.hpp b/circuits/src/aztec3/constants.hpp index f62580dae6e..a835497b42a 100644 --- a/circuits/src/aztec3/constants.hpp +++ b/circuits/src/aztec3/constants.hpp @@ -50,6 +50,7 @@ enum GeneratorIndex { PRIVATE_CIRCUIT_PUBLIC_INPUTS, PUBLIC_CIRCUIT_PUBLIC_INPUTS, CONTRACT_DEPLOYMENT_DATA, + TX_CONTEXT, }; enum StorageSlotGeneratorIndex { From 73365230a163d22ca929cec9a633dd4e4c7aaa6b Mon Sep 17 00:00:00 2001 From: David Banks <47112877+dbanks12@users.noreply.github.com> Date: Wed, 22 Feb 2023 11:52:31 -0500 Subject: [PATCH 051/166] tx request hash (#4) --- circuits/src/aztec3/circuits/abis/tx_request.hpp | 14 ++++++++++++++ circuits/src/aztec3/constants.hpp | 1 + 2 files changed, 15 insertions(+) diff --git a/circuits/src/aztec3/circuits/abis/tx_request.hpp b/circuits/src/aztec3/circuits/abis/tx_request.hpp index 245dce466c8..95be65d0607 100644 --- a/circuits/src/aztec3/circuits/abis/tx_request.hpp +++ b/circuits/src/aztec3/circuits/abis/tx_request.hpp @@ -42,6 +42,20 @@ template struct TxRequest { return tx_request; }; + + fr hash() const + { + std::vector inputs; + inputs.push_back(fr(from)); + inputs.push_back(fr(to)); + inputs.push_back(function_signature.hash()); + spread_arr_into_vec(args, inputs); + inputs.push_back(nonce); + inputs.push_back(tx_context.hash()); + inputs.push_back(chain_id); + + return NCT::compress(inputs, GeneratorIndex::TX_REQUEST); + } }; template void read(uint8_t const*& it, TxRequest& tx_request) diff --git a/circuits/src/aztec3/constants.hpp b/circuits/src/aztec3/constants.hpp index a835497b42a..61706b24829 100644 --- a/circuits/src/aztec3/constants.hpp +++ b/circuits/src/aztec3/constants.hpp @@ -51,6 +51,7 @@ enum GeneratorIndex { PUBLIC_CIRCUIT_PUBLIC_INPUTS, CONTRACT_DEPLOYMENT_DATA, TX_CONTEXT, + TX_REQUEST, }; enum StorageSlotGeneratorIndex { From f8f53e4c1089777e20b533594420f6ec492c5df1 Mon Sep 17 00:00:00 2001 From: Suyash Bagad Date: Wed, 22 Feb 2023 22:46:22 +0530 Subject: [PATCH 052/166] update bb/aztec3 (#24) --- circuits/barretenberg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circuits/barretenberg b/circuits/barretenberg index 5629aeeeaa1..e8281300ed0 160000 --- a/circuits/barretenberg +++ b/circuits/barretenberg @@ -1 +1 @@ -Subproject commit 5629aeeeaa11aad77cfa6fc5c0bc46d751983986 +Subproject commit e8281300ed033d2d893e753e5510bed7286a699d From 71a351fadfa3fec946e0625282ed7d9f626ee9fe Mon Sep 17 00:00:00 2001 From: David Banks <47112877+dbanks12@users.noreply.github.com> Date: Wed, 22 Feb 2023 15:19:24 -0500 Subject: [PATCH 053/166] add spread_arr_into_vec to tx_request (#25) --- circuits/src/aztec3/circuits/abis/tx_request.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/circuits/src/aztec3/circuits/abis/tx_request.hpp b/circuits/src/aztec3/circuits/abis/tx_request.hpp index 95be65d0607..99943cf51ae 100644 --- a/circuits/src/aztec3/circuits/abis/tx_request.hpp +++ b/circuits/src/aztec3/circuits/abis/tx_request.hpp @@ -56,6 +56,11 @@ template struct TxRequest { return NCT::compress(inputs, GeneratorIndex::TX_REQUEST); } + template void spread_arr_into_vec(std::array const& arr, std::vector& vec) const + { + const auto arr_size = sizeof(arr) / sizeof(fr); + vec.insert(vec.end(), &arr[0], &arr[0] + arr_size); + } }; template void read(uint8_t const*& it, TxRequest& tx_request) From bd08542e92800d916dbc6ebf259890367deb8fc5 Mon Sep 17 00:00:00 2001 From: Suyash Bagad Date: Thu, 23 Feb 2023 16:29:32 +0530 Subject: [PATCH 054/166] Create pull_request_template.md --- circuits/.github/pull_request_template.md | 33 +++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 circuits/.github/pull_request_template.md diff --git a/circuits/.github/pull_request_template.md b/circuits/.github/pull_request_template.md new file mode 100644 index 00000000000..b3ed4e76e3e --- /dev/null +++ b/circuits/.github/pull_request_template.md @@ -0,0 +1,33 @@ +# Description + +Please provide a paragraph or two giving a summary of the change, including relevant motivation and context. + +# Checklist: + +- [ ] I have reviewed my diff in github, line by line. +- [ ] Every change is related to the PR description. +- [ ] I have [linked](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue) this pull request to the issue(s) that it resolves. +- [ ] There are no unexpected formatting changes, superfluous debug logs, or commented-out code. +- [ ] There are no circuit changes, OR specifications in `/specs` have been updated. +- [ ] There are no circuit changes, OR a cryptographer has been assigned for review. +- [ ] I've updated any terraform that needs updating (e.g. environment variables) for deployment. +- [ ] The branch has been rebased against the head of its merge target. +- [ ] I'm happy for the PR to be merged at the reviewer's next convenience. +- [ ] New functions, classes, etc. have been documented according to the doxygen comment format. Classes and structs must have `@brief` describing the intended functionality. +- [ ] If existing code has been modified, such documentation has been added or updated. + +> **Note** +> If you are updating the submodule, please make sure you do it in its own _special_ PR and avoid making changes to the submodule as a part of other PRs. +> To update a submodule, you can run the following commands: +> ```console +> $ git submodule update --recursive +> ``` +> Alternatively, you can select a particular commit in `barretenberg/aztec3` that you wish to point to: +> ```console +> $ cd barretenberg +> $ git pull origin aztec3 # This will point to the latest commit in `barretenberg/aztec3` +> $ git checkout # Use this if you wish to point to a particular commit. +> $ cd .. +> $ git add . && git commit -m +> $ git push +> ``` From 640fc0e8dbafc2d74b42248a2cd1b569244885b9 Mon Sep 17 00:00:00 2001 From: Michael Connor Date: Thu, 23 Feb 2023 10:59:58 +0000 Subject: [PATCH 055/166] add missing to_nt conversions (#19) --- .../abis/optionally_revealed_data.hpp | 17 ++ .../abis/private_kernel/accumulated_data.hpp | 30 +++ .../abis/private_kernel/constant_data.hpp | 26 ++- .../abis/private_kernel/old_tree_roots.hpp | 15 ++ .../private_kernel/previous_kernel_data.hpp | 4 +- .../abis/private_kernel/public_inputs.hpp | 22 +- .../src/aztec3/circuits/abis/tx_context.hpp | 15 ++ .../apps/function_execution_context.cpp | 205 ------------------ 8 files changed, 110 insertions(+), 224 deletions(-) delete mode 100644 circuits/src/aztec3/circuits/apps/function_execution_context.cpp diff --git a/circuits/src/aztec3/circuits/abis/optionally_revealed_data.hpp b/circuits/src/aztec3/circuits/abis/optionally_revealed_data.hpp index 79c36b86989..be82da31608 100644 --- a/circuits/src/aztec3/circuits/abis/optionally_revealed_data.hpp +++ b/circuits/src/aztec3/circuits/abis/optionally_revealed_data.hpp @@ -43,6 +43,23 @@ template struct OptionallyRevealedData { return data; }; + template OptionallyRevealedData to_native_type() const + { + static_assert(std::is_same, NCT>::value); + auto to_nt = [&](auto& e) { return plonk::stdlib::types::to_nt(e); }; + auto to_native_type = [](T& e) { return e.template to_native_type(); }; + + OptionallyRevealedData data = { + to_nt(call_stack_item_hash), to_native_type(function_signature), + to_nt(emitted_events), to_nt(vk_hash), + to_nt(portal_contract_address), to_nt(pay_fee_from_l1), + to_nt(pay_fee_from_public_l2), to_nt(called_from_l1), + to_nt(called_from_public_l2), + }; + + return data; + }; + void set_public() { static_assert(!(std::is_same::value)); diff --git a/circuits/src/aztec3/circuits/abis/private_kernel/accumulated_data.hpp b/circuits/src/aztec3/circuits/abis/private_kernel/accumulated_data.hpp index 1cca37b1dde..ca3d05b8da9 100644 --- a/circuits/src/aztec3/circuits/abis/private_kernel/accumulated_data.hpp +++ b/circuits/src/aztec3/circuits/abis/private_kernel/accumulated_data.hpp @@ -63,6 +63,36 @@ template struct AccumulatedData { return acc_data; }; + template AccumulatedData to_native_type() const + { + static_assert(std::is_same, NCT>::value); + auto to_nt = [&](auto& e) { return plonk::stdlib::types::to_nt(e); }; + auto to_native_type = [](T& e) { return e.template to_native_type(); }; + + AccumulatedData acc_data = { + typename NativeTypes::AggregationObject{ + to_nt(aggregation_object.P0), + to_nt(aggregation_object.P1), + to_nt(aggregation_object.public_inputs), + aggregation_object.proof_witness_indices, + aggregation_object.has_data, + }, + + to_nt(private_call_count), + + to_nt(new_commitments), + to_nt(new_nullifiers), + + to_nt(private_call_stack), + to_nt(public_call_stack), + to_nt(l1_msg_stack), + + map(optionally_revealed_data, to_native_type), + }; + + return acc_data; + }; + void set_public() { static_assert(!(std::is_same::value)); diff --git a/circuits/src/aztec3/circuits/abis/private_kernel/constant_data.hpp b/circuits/src/aztec3/circuits/abis/private_kernel/constant_data.hpp index d627f1f370a..06f7b9e25ef 100644 --- a/circuits/src/aztec3/circuits/abis/private_kernel/constant_data.hpp +++ b/circuits/src/aztec3/circuits/abis/private_kernel/constant_data.hpp @@ -1,5 +1,5 @@ #pragma once -// #include "globals.hpp" + #include "old_tree_roots.hpp" #include "../tx_context.hpp" @@ -21,15 +21,11 @@ template struct ConstantData { OldTreeRoots old_tree_roots; TxContext tx_context; - // Globals globals; template ConstantData> to_circuit_type(Composer& composer) const { static_assert((std::is_same::value)); - // Capture the composer: - // auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; - ConstantData> constant_data = { old_tree_roots.to_circuit_type(composer), tx_context.to_circuit_type(composer), @@ -38,6 +34,20 @@ template struct ConstantData { return constant_data; }; + template ConstantData to_native_type() const + { + static_assert(std::is_same, NCT>::value); + + auto to_native_type = [](T& e) { return e.template to_native_type(); }; + + ConstantData constant_data = { + to_native_type(old_tree_roots), + to_native_type(tx_context), + }; + + return constant_data; + }; + void set_public() { static_assert(!(std::is_same::value)); @@ -45,12 +55,6 @@ template struct ConstantData { old_tree_roots.set_public(); tx_context.set_public(); } - - // template void set_private_data_tree_root(typename CircuitTypes::fr const& value) - // { - // old_tree_roots.private_data_tree_root.assert_equal(0, "Cannot edit a nonzero constant."); - // old_tree_roots.private_data_tree_root = value; - // } }; } // namespace aztec3::circuits::abis::private_kernel \ No newline at end of file diff --git a/circuits/src/aztec3/circuits/abis/private_kernel/old_tree_roots.hpp b/circuits/src/aztec3/circuits/abis/private_kernel/old_tree_roots.hpp index a71fbeecbc2..c53a227e2ef 100644 --- a/circuits/src/aztec3/circuits/abis/private_kernel/old_tree_roots.hpp +++ b/circuits/src/aztec3/circuits/abis/private_kernel/old_tree_roots.hpp @@ -36,6 +36,21 @@ template struct OldTreeRoots { return data; }; + template OldTreeRoots to_native_type() const + { + static_assert(std::is_same, NCT>::value); + auto to_nt = [&](auto& e) { return plonk::stdlib::types::to_nt(e); }; + + OldTreeRoots data = { + to_nt(private_data_tree_root), + to_nt(nullifier_tree_root), + to_nt(contract_tree_root), + to_nt(private_kernel_vk_tree_root), + }; + + return data; + }; + void set_public() { static_assert(!(std::is_same::value)); diff --git a/circuits/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp b/circuits/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp index 1165c202142..42c6af2ac7d 100644 --- a/circuits/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp +++ b/circuits/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp @@ -20,8 +20,8 @@ template struct PreviousKernelData { NativeTypes::Proof proof; // TODO: how to express proof as native/circuit type when it gets used as a buffer? std::shared_ptr vk; - // TODO: this index and path are meant to be those of a tree of _kernel circuit_ vks; not the tree of functions - // within the contract tree. + // TODO: this index and path are meant to be those of a leaf within the tree of _kernel circuit_ vks; not the tree + // of functions within the contract tree. fr vk_index; std::array vk_path; diff --git a/circuits/src/aztec3/circuits/abis/private_kernel/public_inputs.hpp b/circuits/src/aztec3/circuits/abis/private_kernel/public_inputs.hpp index 09d7a7422dc..6e3a85ae248 100644 --- a/circuits/src/aztec3/circuits/abis/private_kernel/public_inputs.hpp +++ b/circuits/src/aztec3/circuits/abis/private_kernel/public_inputs.hpp @@ -21,8 +21,6 @@ template struct PublicInputs { ConstantData constants; boolean is_private = true; // TODO: might need to instantiate from witness! - boolean is_public = false; - boolean is_contract_deployment = false; template PublicInputs> to_circuit_type(Composer& composer) const { @@ -36,13 +34,27 @@ template struct PublicInputs { constants.to_circuit_type(composer), to_ct(is_private), - to_ct(is_public), - to_ct(is_contract_deployment), }; return private_inputs; }; + template PublicInputs to_native_type() const + { + static_assert(std::is_same, NCT>::value); + auto to_nt = [&](auto& e) { return plonk::stdlib::types::to_nt(e); }; + auto to_native_type = [](T& e) { return e.template to_native_type(); }; + + PublicInputs pis = { + to_native_type(end), + to_native_type(constants), + + to_nt(is_private), + }; + + return pis; + }; + void set_public() { static_assert(!(std::is_same::value)); @@ -51,8 +63,6 @@ template struct PublicInputs { constants.set_public(); fr(is_private).set_public(); - fr(is_public).set_public(); - fr(is_contract_deployment).set_public(); } }; diff --git a/circuits/src/aztec3/circuits/abis/tx_context.hpp b/circuits/src/aztec3/circuits/abis/tx_context.hpp index be34867c1b3..2823f659fc6 100644 --- a/circuits/src/aztec3/circuits/abis/tx_context.hpp +++ b/circuits/src/aztec3/circuits/abis/tx_context.hpp @@ -45,6 +45,21 @@ template struct TxContext { return tx_context; }; + template TxContext to_native_type() const + { + static_assert(std::is_same, NCT>::value); + auto to_nt = [&](auto& e) { return plonk::stdlib::types::to_nt(e); }; + auto to_native_type = [](T& e) { return e.template to_native_type(); }; + + TxContext tx_context = { + to_nt(is_fee_payment_tx), to_nt(is_rebate_payment_tx), + to_nt(is_contract_deployment_tx), to_native_type(contract_deployment_data), + to_nt(reference_block_num), + }; + + return tx_context; + }; + void set_public() { static_assert(!(std::is_same::value)); diff --git a/circuits/src/aztec3/circuits/apps/function_execution_context.cpp b/circuits/src/aztec3/circuits/apps/function_execution_context.cpp deleted file mode 100644 index 3421c75733b..00000000000 --- a/circuits/src/aztec3/circuits/apps/function_execution_context.cpp +++ /dev/null @@ -1,205 +0,0 @@ -// #include "function_execution_context.hpp" - -// #include "contract.hpp" -// #include "oracle_wrapper.hpp" - -// #include "notes/note_interface.hpp" - -// #include "opcodes/opcodes.hpp" - -// #include - -// #include -// #include -// #include - -// #include - -// #include - -// #include - -// namespace aztec3::circuits::apps { - -// using aztec3::circuits::abis::CallStackItem; -// using aztec3::circuits::abis::CallType; -// using aztec3::circuits::abis::FunctionSignature; -// using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; -// using aztec3::circuits::abis::PrivateCircuitPublicInputs; - -// using aztec3::circuits::apps::notes::NoteInterface; -// using aztec3::circuits::apps::opcodes::Opcodes; - -// using aztec3::circuits::types::array_push; - -// using plonk::stdlib::witness_t; -// using plonk::stdlib::types::CircuitTypes; -// using NT = plonk::stdlib::types::NativeTypes; -// using plonk::stdlib::types::to_nt; - -// template -// CallStackItem FunctionExecutionContext::get_call_stack_item() -// { -// const NT::address& actual_contract_address = oracle.native_oracle.get_actual_contract_address(); -// const FunctionSignature& function_signature = oracle.native_oracle.get_function_signature(); - -// return CallStackItem{ -// .contract_address = actual_contract_address, -// .function_signature = function_signature, -// .public_inputs = get_final_private_circuit_public_inputs(), -// }; -// } - -// template -// std::array, PRIVATE_CALL_STACK_LENGTH> FunctionExecutionContext< -// Composer>::get_private_call_stack_items() -// { -// std::array, PRIVATE_CALL_STACK_LENGTH> result; - -// for (size_t i = 0; i < result.size(); ++i) { -// auto& nested_exec_ctx = nested_private_call_exec_ctxs[i]; -// if (nested_exec_ctx != nullptr) { -// const NT::address& actual_contract_address = -// nested_exec_ctx->oracle.native_oracle.get_actual_contract_address(); -// const FunctionSignature& function_signature = -// nested_exec_ctx->oracle.native_oracle.get_function_signature(); - -// result[i] = CallStackItem{ -// .contract_address = actual_contract_address, -// .function_signature = function_signature, -// .public_inputs = nested_exec_ctx->get_final_private_circuit_public_inputs(), -// }; -// } -// } - -// // TODO: do we need to instantiate-with-zeros the structs at the unused indices of `result`? - -// return result; -// } - -// template -// std::array::fr, RETURN_VALUES_LENGTH> FunctionExecutionContext::call( -// typename CircuitTypes::address const& external_contract_address, -// std::string const& external_function_name, -// std::function&, std::array)> f, -// std::array::fr, ARGS_LENGTH> const& args) -// { - -// Composer f_composer; - -// // Convert function name to bytes and use the first 4 bytes as the function encoding, for now: -// std::vector f_name_bytes(external_function_name.begin(), external_function_name.end()); -// std::vector f_encoding_bytes(f_name_bytes.begin(), f_name_bytes.begin() + 4); -// uint32_t f_encoding; -// memcpy(&f_encoding, f_encoding_bytes.data(), sizeof(f_encoding)); - -// const FunctionSignature f_function_signature{ -// .function_encoding = f_encoding, -// .is_private = true, -// .is_constructor = false, -// }; - -// const CallContext f_call_context{ -// .msg_sender = oracle.get_this_contract_address(), // the sender is `this` contract! -// .storage_contract_address = external_contract_address, -// .tx_origin = oracle.get_tx_origin(), -// .is_delegate_call = false, -// .is_static_call = false, -// .is_contract_deployment = false, -// .reference_block_num = 0, -// }; - -// NativeOracle f_oracle(oracle.oracle.db, -// external_contract_address.get_value(), -// f_function_signature, -// f_call_context, -// oracle.get_msg_sender_private_key() -// .get_value() // TODO: consider whether a nested function should even be able to access -// a -// // private key, given that the call is now coming from a contract (which -// // cannot own a secret), rather than a human. -// ); -// OracleWrapperInterface f_oracle_wrapper(f_composer, f_oracle); - -// // We need an exec_ctx reference which won't go out of scope, so we store a shared_ptr to the newly created -// // exec_ctx in `this` exec_ctx. -// auto f_exec_ctx = std::make_shared>(f_composer, f_oracle_wrapper); - -// array_push(nested_private_call_exec_ctxs, f_exec_ctx); - -// auto native_args = to_nt(args); - -// // This calls the function `f`, passing the arguments shown. -// // The f_exec_ctx will be populated with all the information about that function's execution. -// std::apply(f, std::forward_as_tuple(*f_exec_ctx, native_args)); - -// // Remember: the data held in the f_exec_ctc was built with a different composer than that -// // of `this` exec_ctx. So we only allow ourselves to get the native types, so that we can consciously declare -// // circuit types for `this` exec_ctx using `this->composer`. -// auto& f_public_inputs_nt = f_exec_ctx->final_private_circuit_public_inputs; - -// // Since we've made a call to another function, we now need to push a call_stack_item_hash to `this` function's -// // private call stack. -// // Note: we need to constrain some of `this` circuit's variables against f's public inputs: -// // - args -// // - return_values -// // - call_context (TODO: maybe this only needs to be done in the kernel circuit). -// auto f_public_inputs_ct = f_public_inputs_nt.to_circuit_type(composer); - -// for (size_t i = 0; i < f_public_inputs_ct.args.size(); ++i) { -// args[i].assert_equal(f_public_inputs_ct.args[i]); -// } - -// auto call_stack_item_hash = f_public_inputs_ct.hash(); - -// array_push(private_circuit_public_inputs.private_call_stack, call_stack_item_hash); - -// // The return values are implicitly constrained by being returned as circuit types from this method, for -// // further use in the circuit. Note: ALL elements of the return_values array MUST be constrained, even if -// // they're placeholder zeroes. -// return f_public_inputs_ct.return_values; -// } - -// template void FunctionExecutionContext::finalise_utxos() -// { -// // Copy some vectors, as we can't control whether they'll be pushed-to further, when we call Note methods. -// auto new_nullifiers_copy = new_nullifiers; - -// size_t used_nullifiers_count = 0; -// fr next_nullifier; -// std::vector new_nonces; - -// // This is almost a visitor pattern. Call methods on each note. The note will choose what to do. -// for (size_t i = 0; i < new_notes.size(); ++i) { -// NoteInterface& note = *new_notes[i]; - -// if (note.needs_nonce()) { -// const bool next_nullifier_available = new_nullifiers_copy.size() > used_nullifiers_count; - -// if (next_nullifier_available) { -// next_nullifier = new_nullifiers_copy[used_nullifiers_count++]; -// note.set_nonce(next_nullifier); -// } else { -// const fr new_nonce = note.generate_nonce(); -// new_nonces.push_back(new_nonce); -// } -// } - -// new_commitments.push_back(note.get_commitment()); -// } - -// // Push new_nonces to the end of new_nullifiers: -// std::copy(new_nonces.begin(), new_nonces.end(), std::back_inserter(new_nullifiers)); -// } - -// template void FunctionExecutionContext::finalise() -// { -// finalise_utxos(); -// private_circuit_public_inputs.set_commitments(new_commitments); -// private_circuit_public_inputs.set_nullifiers(new_nullifiers); -// private_circuit_public_inputs.set_public(composer); -// final_private_circuit_public_inputs = -// private_circuit_public_inputs.remove_optionality().template to_native_type(); -// }; - -// } // namespace aztec3::circuits::apps \ No newline at end of file From cff4170bc5009dd96d3e79b03b5cec167f158256 Mon Sep 17 00:00:00 2001 From: David Banks <47112877+dbanks12@users.noreply.github.com> Date: Fri, 24 Feb 2023 03:56:50 -0500 Subject: [PATCH 056/166] use () instead of {} in struct initalization to ensure all zeros (#27) --- circuits/src/aztec3/circuits/kernel/private/.test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circuits/src/aztec3/circuits/kernel/private/.test.cpp b/circuits/src/aztec3/circuits/kernel/private/.test.cpp index d198182c319..ca4a526f50d 100644 --- a/circuits/src/aztec3/circuits/kernel/private/.test.cpp +++ b/circuits/src/aztec3/circuits/kernel/private/.test.cpp @@ -140,7 +140,7 @@ TEST(private_kernel_tests, test_deposit) .is_fee_payment_tx = false, .is_rebate_payment_tx = false, .is_contract_deployment_tx = false, - .contract_deployment_data = ContractDeploymentData{}, + .contract_deployment_data = ContractDeploymentData(), .reference_block_num = 0, }, .chain_id = 1, From c0636ee2c648e2d45cf29cbd1adfe795b5b4ce47 Mon Sep 17 00:00:00 2001 From: Suyash Bagad Date: Fri, 24 Feb 2023 23:11:17 +0530 Subject: [PATCH 057/166] Fix mock kernel circuit: use 32-bit random values as P0 and P1 elements in a recursive proof. (#28) --- circuits/src/aztec3/circuits/mock/mock_kernel_circuit.hpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/circuits/src/aztec3/circuits/mock/mock_kernel_circuit.hpp b/circuits/src/aztec3/circuits/mock/mock_kernel_circuit.hpp index 4b02cc308d7..71472116726 100644 --- a/circuits/src/aztec3/circuits/mock/mock_kernel_circuit.hpp +++ b/circuits/src/aztec3/circuits/mock/mock_kernel_circuit.hpp @@ -1,5 +1,6 @@ #pragma once #include +#include #include #include #include @@ -10,6 +11,10 @@ namespace aztec3::circuits::mock { +namespace { +auto& engine = numeric::random::get_debug_engine(); +} + using aztec3::circuits::abis::private_kernel::PublicInputs; using NT = plonk::stdlib::types::NativeTypes; using plonk::stdlib::pedersen_commitment; @@ -27,7 +32,7 @@ template void mock_kernel_circuit(Composer& composer, Public std::vector dummy_witness_indices; // 16 is the number of values added to `proof_witness_indices` at the end of `verify_proof`. for (size_t i = 0; i < 16; ++i) { - fr witness = fr(witness_t(&composer, 0)); + fr witness = fr(witness_t(&composer, engine.get_random_uint32())); uint32_t witness_index = witness.get_witness_index(); dummy_witness_indices.push_back(witness_index); } From f12a3d13752643392b9eca3e6bad336b989975f0 Mon Sep 17 00:00:00 2001 From: Suyash Bagad Date: Fri, 24 Feb 2023 23:24:27 +0530 Subject: [PATCH 058/166] update bb. (#29) --- circuits/barretenberg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circuits/barretenberg b/circuits/barretenberg index e8281300ed0..e184c92276c 160000 --- a/circuits/barretenberg +++ b/circuits/barretenberg @@ -1 +1 @@ -Subproject commit e8281300ed033d2d893e753e5510bed7286a699d +Subproject commit e184c92276ce6ec7e7848b50a22bbd9f83591d5d From 22fef3bf6a5a5d000f1cbd09981d40fe04c39f7b Mon Sep 17 00:00:00 2001 From: Suyash Bagad Date: Mon, 27 Feb 2023 20:24:42 +0530 Subject: [PATCH 059/166] move unnamed namespace out. (#30) --- circuits/src/aztec3/circuits/mock/mock_kernel_circuit.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/circuits/src/aztec3/circuits/mock/mock_kernel_circuit.hpp b/circuits/src/aztec3/circuits/mock/mock_kernel_circuit.hpp index 71472116726..9245a9cddf3 100644 --- a/circuits/src/aztec3/circuits/mock/mock_kernel_circuit.hpp +++ b/circuits/src/aztec3/circuits/mock/mock_kernel_circuit.hpp @@ -9,12 +9,12 @@ #include // #include -namespace aztec3::circuits::mock { - namespace { auto& engine = numeric::random::get_debug_engine(); } +namespace aztec3::circuits::mock { + using aztec3::circuits::abis::private_kernel::PublicInputs; using NT = plonk::stdlib::types::NativeTypes; using plonk::stdlib::pedersen_commitment; From 066c6def79f1c265518d76995893434c052eae8c Mon Sep 17 00:00:00 2001 From: Suyash Bagad Date: Thu, 2 Mar 2023 13:15:21 +0000 Subject: [PATCH 060/166] Update `bb/aztec3`. --- circuits/barretenberg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circuits/barretenberg b/circuits/barretenberg index e184c92276c..46752f735c0 160000 --- a/circuits/barretenberg +++ b/circuits/barretenberg @@ -1 +1 @@ -Subproject commit e184c92276ce6ec7e7848b50a22bbd9f83591d5d +Subproject commit 46752f735c0ed8382f65ac007a0361955164bf1e From 5a6076457b5f9c14968f9a22374f41bcd848b9c7 Mon Sep 17 00:00:00 2001 From: Suyash Bagad Date: Thu, 2 Mar 2023 19:20:43 +0530 Subject: [PATCH 061/166] update `bb/aztec3`. (#32) --- circuits/barretenberg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circuits/barretenberg b/circuits/barretenberg index 46752f735c0..da723ddec1e 160000 --- a/circuits/barretenberg +++ b/circuits/barretenberg @@ -1 +1 @@ -Subproject commit 46752f735c0ed8382f65ac007a0361955164bf1e +Subproject commit da723ddec1e60bd796788531e8c37f908dbef52d From fef5d87ea21992c59b8035008a2427e39e784f40 Mon Sep 17 00:00:00 2001 From: Suyash Bagad Date: Thu, 2 Mar 2023 21:12:23 +0530 Subject: [PATCH 062/166] Linearised Prover Removed from BB (#31) * Linearised prover removed from bb: so nomenclature has changed slightly. `UnrolledProver` -> `Prover` * Update submodule. * More fixes. --- circuits/barretenberg | 2 +- .../aztec3/circuits/kernel/private/.test.cpp | 4 +- .../aztec3/circuits/kernel/private/init.hpp | 2 +- .../aztec3/circuits/recursion/aggregator.hpp | 8 ++-- .../aztec3/circuits/recursion/play.test.cpp | 38 +++++++++---------- 5 files changed, 27 insertions(+), 27 deletions(-) diff --git a/circuits/barretenberg b/circuits/barretenberg index da723ddec1e..74c66a79515 160000 --- a/circuits/barretenberg +++ b/circuits/barretenberg @@ -1 +1 @@ -Subproject commit da723ddec1e60bd796788531e8c37f908dbef52d +Subproject commit 74c66a795151b8f4f94576511f7ec0de4d596f9d diff --git a/circuits/src/aztec3/circuits/kernel/private/.test.cpp b/circuits/src/aztec3/circuits/kernel/private/.test.cpp index ca4a526f50d..06c6ad426d3 100644 --- a/circuits/src/aztec3/circuits/kernel/private/.test.cpp +++ b/circuits/src/aztec3/circuits/kernel/private/.test.cpp @@ -118,7 +118,7 @@ TEST(private_kernel_tests, test_deposit) OptionalPrivateCircuitPublicInputs opt_deposit_public_inputs = deposit(deposit_ctx, amount, asset_id, memo); PrivateCircuitPublicInputs deposit_public_inputs = opt_deposit_public_inputs.remove_optionality(); - UnrolledProver deposit_prover = deposit_composer.create_unrolled_prover(); + Prover deposit_prover = deposit_composer.create_prover(); NT::Proof deposit_proof = deposit_prover.construct_proof(); // info("\ndeposit_proof: ", deposit_proof.proof_data); @@ -203,7 +203,7 @@ TEST(private_kernel_tests, test_deposit) mock_kernel_circuit(mock_kernel_composer, mock_kernel_public_inputs); - UnrolledProver mock_kernel_prover = mock_kernel_composer.create_unrolled_prover(); + Prover mock_kernel_prover = mock_kernel_composer.create_prover(); NT::Proof mock_kernel_proof = mock_kernel_prover.construct_proof(); // info("\nmock_kernel_proof: ", mock_kernel_proof.proof_data); diff --git a/circuits/src/aztec3/circuits/kernel/private/init.hpp b/circuits/src/aztec3/circuits/kernel/private/init.hpp index c15272db478..5e352e851e3 100644 --- a/circuits/src/aztec3/circuits/kernel/private/init.hpp +++ b/circuits/src/aztec3/circuits/kernel/private/init.hpp @@ -16,7 +16,7 @@ namespace aztec3::circuits::kernel::private_kernel { // Turbo specific, at the moment: using Composer = plonk::stdlib::types::Composer; -using plonk::stdlib::types::UnrolledProver; +using plonk::stdlib::types::Prover; using Aggregator = aztec3::circuits::recursion::Aggregator; diff --git a/circuits/src/aztec3/circuits/recursion/aggregator.hpp b/circuits/src/aztec3/circuits/recursion/aggregator.hpp index 1cb98367012..41523c02f27 100644 --- a/circuits/src/aztec3/circuits/recursion/aggregator.hpp +++ b/circuits/src/aztec3/circuits/recursion/aggregator.hpp @@ -24,8 +24,8 @@ using transcript::Manifest; // using AggregationObject = recursion_output; // // Native Types: -// using Proof = waffle::plonk_proof; -// using VK = std::shared_ptr; +// using Proof = plonk::proof; +// using VK = std::shared_ptr; // static AggregationObject aggregate(Composer* composer, // const VK& vk, @@ -33,7 +33,7 @@ using transcript::Manifest; // const AggregationObject recursion_output = AggregationObject()) // { // std::shared_ptr> recursive_vk = verification_key::from_witness(composer, vk); -// const transcript::Manifest recursive_manifest = Composer::create_unrolled_manifest(vk->num_public_inputs); +// const transcript::Manifest recursive_manifest = Composer::create_manifest(vk->num_public_inputs); // AggregationObject result = verify_proof>( // composer, recursive_vk, recursive_manifest, proof, recursion_output); @@ -50,7 +50,7 @@ class Aggregator { const size_t& num_public_inputs, const CT::AggregationObject recursion_output = CT::AggregationObject()) { - const Manifest recursive_manifest = Composer::create_unrolled_manifest(num_public_inputs); + const Manifest recursive_manifest = Composer::create_manifest(num_public_inputs); CT::AggregationObject result = verify_proof( composer, vk, recursive_manifest, proof, recursion_output); diff --git a/circuits/src/aztec3/circuits/recursion/play.test.cpp b/circuits/src/aztec3/circuits/recursion/play.test.cpp index 2170ba81d16..979f48632c3 100644 --- a/circuits/src/aztec3/circuits/recursion/play.test.cpp +++ b/circuits/src/aztec3/circuits/recursion/play.test.cpp @@ -9,7 +9,7 @@ using namespace plonk::stdlib::types; using plonk::stdlib::recursion::recursion_output; // namespace { -// std::shared_ptr srs; +// std::shared_ptr srs; // private_kernel::circuit_data private_kernel_cd; // private_circuit::circuit_data private_circuit_cd; // } // namespace @@ -19,7 +19,7 @@ class play_tests : public ::testing::Test { // static void SetUpTestCase() // { // std::string CRS_PATH = "../srs_db/ignition"; - // srs = std::make_shared(CRS_PATH); + // srs = std::make_shared(CRS_PATH); // private_circuit_cd = join_split::get_circuit_data(srs); // private_kernel_cd = claim::get_circuit_data(srs); // } @@ -40,8 +40,8 @@ TEST(play_tests, test_play_app_proof_gen) info("Play app circuit logic failed: ", app_composer.err()); } - UnrolledProver app_prover = app_composer.create_unrolled_prover(); - waffle::plonk_proof app_proof = app_prover.construct_proof(); + stdlib::types::Prover app_prover = app_composer.create_prover(); + proof app_proof = app_prover.construct_proof(); info("app_proof: ", app_proof.proof_data); } @@ -54,11 +54,11 @@ TEST(play_tests, test_play_recursive_proof_gen) info("Play app circuit logic failed: ", app_composer.err()); } - UnrolledProver app_prover = app_composer.create_unrolled_prover(); - waffle::plonk_proof app_proof = app_prover.construct_proof(); + stdlib::types::Prover app_prover = app_composer.create_prover(); + proof app_proof = app_prover.construct_proof(); info("app_proof: ", app_proof.proof_data); - std::shared_ptr app_vk = app_composer.compute_verification_key(); + std::shared_ptr app_vk = app_composer.compute_verification_key(); Composer recursive_composer = Composer("../barretenberg/cpp/srs_db/ignition"); recursion_output recursion_output = play_recursive_circuit(recursive_composer, app_vk, app_proof); @@ -77,9 +77,9 @@ TEST(play_tests, test_play_recursive_2_proof_gen) info("Play app circuit logic failed: ", app_composer.err()); } - UnrolledProver app_prover = app_composer.create_unrolled_prover(); - waffle::plonk_proof app_proof = app_prover.construct_proof(); - std::shared_ptr app_vk = app_composer.compute_verification_key(); + stdlib::types::Prover app_prover = app_composer.create_prover(); + proof app_proof = app_prover.construct_proof(); + std::shared_ptr app_vk = app_composer.compute_verification_key(); //******************************************************************************* @@ -90,9 +90,9 @@ TEST(play_tests, test_play_recursive_2_proof_gen) info("dummy_circuit logic failed: ", dummy_circuit_composer.err()); } - UnrolledProver dummy_circuit_prover = dummy_circuit_composer.create_unrolled_prover(); - waffle::plonk_proof dummy_circuit_proof = dummy_circuit_prover.construct_proof(); - std::shared_ptr dummy_circuit_vk = dummy_circuit_composer.compute_verification_key(); + stdlib::types::Prover dummy_circuit_prover = dummy_circuit_composer.create_prover(); + proof dummy_circuit_proof = dummy_circuit_prover.construct_proof(); + std::shared_ptr dummy_circuit_vk = dummy_circuit_composer.compute_verification_key(); //******************************************************************************* @@ -104,11 +104,11 @@ TEST(play_tests, test_play_recursive_2_proof_gen) info("recursion_1 circuit logic failed: ", recursion_1_composer.err()); } - UnrolledProver recursion_1_prover = recursion_1_composer.create_unrolled_prover(); + stdlib::types::Prover recursion_1_prover = recursion_1_composer.create_prover(); - waffle::plonk_proof recursion_1_proof = recursion_1_prover.construct_proof(); + proof recursion_1_proof = recursion_1_prover.construct_proof(); - std::shared_ptr recursion_1_vk = recursion_1_composer.compute_verification_key(); + std::shared_ptr recursion_1_vk = recursion_1_composer.compute_verification_key(); //******************************************************************************* @@ -120,9 +120,9 @@ TEST(play_tests, test_play_recursive_2_proof_gen) // info("recursion_2 circuit logic failed: ", recursion_2_composer.err()); // } - // UnrolledProver recursion_2_prover = recursion_2_composer.create_unrolled_prover(); - // waffle::plonk_proof recursion_2_proof = recursion_2_prover.construct_proof(); - // std::shared_ptr recursion_2_vk = recursion_2_composer.compute_verification_key(); + // Prover recursion_2_prover = recursion_2_composer.create_prover(); + // proof recursion_2_proof = recursion_2_prover.construct_proof(); + // std::shared_ptr recursion_2_vk = recursion_2_composer.compute_verification_key(); } } // namespace aztec3::circuits::recursion \ No newline at end of file From dc55b1a50b709bfbbc925adb1ef34f0f05423dc6 Mon Sep 17 00:00:00 2001 From: David Banks <47112877+dbanks12@users.noreply.github.com> Date: Mon, 6 Mar 2023 10:57:22 -0700 Subject: [PATCH 063/166] Add cbind for hashing tx req along with test (#26) * add cbind for hashing tx req * cleanup txreq hash test * debug info to hashing functions, rename cbind test for hashing * debug * change contract deployment data struct initialization (was getting garbage vals) * c_bind working, cleanup * doxygen comment for c_bind * wasm sentence in doxygen comment for c_bind * use NT::fr::serialize* instead of barretenberg::fr::serialize in kernel c_binds, use random inputs in tx req hash cbind test and just results against TxRequest.hash() * rename/mv kernel c_bind tests to abis. Massively simplify hash_tx_req test * cbind test comments * better namespacing in cbind * newline end of file * remove unused namespace item * cleanup test namespace, other minor cleanup --- circuits/src/aztec3/circuits/abis/c_bind.cpp | 31 ++++++++++++ circuits/src/aztec3/circuits/abis/c_bind.h | 9 ++++ .../src/aztec3/circuits/abis/c_bind.test.cpp | 48 +++++++++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 circuits/src/aztec3/circuits/abis/c_bind.cpp create mode 100644 circuits/src/aztec3/circuits/abis/c_bind.h create mode 100644 circuits/src/aztec3/circuits/abis/c_bind.test.cpp diff --git a/circuits/src/aztec3/circuits/abis/c_bind.cpp b/circuits/src/aztec3/circuits/abis/c_bind.cpp new file mode 100644 index 00000000000..557e1f0b225 --- /dev/null +++ b/circuits/src/aztec3/circuits/abis/c_bind.cpp @@ -0,0 +1,31 @@ +#include "c_bind.h" +#include "tx_request.hpp" + +#include + +namespace { +using aztec3::circuits::abis::TxRequest; +using NT = plonk::stdlib::types::NativeTypes; +} // namespace + +#define WASM_EXPORT __attribute__((visibility("default"))) + +extern "C" { + +/** + * @brief Hashes a TX request. This is a WASM-export that can be called from Typescript. + * + * @details given a `uint8_t*` buffer representing a full TX request, + * read it into a `TxRequest` object, hash it to a `fr`, + * and serialize it to a `uint8_t*` output buffer + * + * @param tx_request_buf buffer of bytes containing all data needed to construct a TX request via `read()` + * @param output buffer that will contain the output which will be the hashed `TxRequest` + */ +WASM_EXPORT void abis__hash_tx_request(uint8_t const* tx_request_buf, uint8_t* output) +{ + TxRequest tx_request; + read(tx_request_buf, tx_request); + NT::fr::serialize_to_buffer(tx_request.hash(), output); +} +} diff --git a/circuits/src/aztec3/circuits/abis/c_bind.h b/circuits/src/aztec3/circuits/abis/c_bind.h new file mode 100644 index 00000000000..db27da4e5e4 --- /dev/null +++ b/circuits/src/aztec3/circuits/abis/c_bind.h @@ -0,0 +1,9 @@ +#include + +#define WASM_EXPORT __attribute__((visibility("default"))) + +extern "C" { + +WASM_EXPORT void abis__hash_tx_request(uint8_t const* tx_request_buf, uint8_t* output); + +} diff --git a/circuits/src/aztec3/circuits/abis/c_bind.test.cpp b/circuits/src/aztec3/circuits/abis/c_bind.test.cpp new file mode 100644 index 00000000000..96622e4e8cd --- /dev/null +++ b/circuits/src/aztec3/circuits/abis/c_bind.test.cpp @@ -0,0 +1,48 @@ +#include "c_bind.h" + +#include "tx_request.hpp" + +#include +#include + +namespace { +using NT = plonk::stdlib::types::NativeTypes; +auto& engine = numeric::random::get_debug_engine(); +} // namespace + +namespace aztec3::circuits::abis { + +TEST(abis, hash_tx_request) +{ + // randomize function args for tx request + std::array args; + for (size_t i = 0; i < ARGS_LENGTH; i++) { + args[i] = fr(engine.get_random_uint256()); + } + + // Construct mostly empty TxRequest with some randomized fields + TxRequest tx_request = TxRequest{ + .from = engine.get_random_uint256(), + .to = engine.get_random_uint256(), + .function_signature = FunctionSignature(), + .args = args, + .nonce = engine.get_random_uint256(), + .tx_context = TxContext(), + .chain_id = engine.get_random_uint256(), + }; + + // Write the tx request to a buffer and + // allocate an output buffer for cbind hash results + std::vector buf; + write(buf, tx_request); + uint8_t* output = (uint8_t*)malloc(32 * sizeof(uint8_t)); + // Make the c_bind call to hash the tx request + abis__hash_tx_request(buf.data(), output); + + // Convert buffer to `fr` for comparison to in-test calculated hash + NT::fr got_hash = NT::fr::serialize_from_buffer(output); + // Confirm cbind output == hash of tx request + EXPECT_EQ(got_hash, tx_request.hash()); +} + +} // namespace aztec3::circuits::abis From cc3f93e7b9c945f8b9c79ce85a18938f8fe7e600 Mon Sep 17 00:00:00 2001 From: David Banks <47112877+dbanks12@users.noreply.github.com> Date: Tue, 7 Mar 2023 11:05:14 -0700 Subject: [PATCH 064/166] move c++ into cpp/ (#36) --- circuits/.gitmodules | 2 +- circuits/build_manifest.json | 16 ++++++++-------- circuits/build_manifest.sh | 8 ++++---- circuits/{ => cpp}/.clang-format | 0 circuits/{ => cpp}/.dockerignore | 0 circuits/{ => cpp}/CMakeLists.txt | 0 circuits/{ => cpp}/barretenberg | 0 circuits/{ => cpp}/bootstrap.sh | 0 circuits/{ => cpp}/cmake/arch.cmake | 0 circuits/{ => cpp}/cmake/barretenberg.cmake | 0 circuits/{ => cpp}/cmake/benchmark.cmake | 0 circuits/{ => cpp}/cmake/build.cmake | 0 circuits/{ => cpp}/cmake/gtest.cmake | 0 circuits/{ => cpp}/cmake/module.cmake | 0 circuits/{ => cpp}/cmake/threading.cmake | 0 circuits/{ => cpp}/cmake/toolchain.cmake | 0 .../cmake/toolchains/aarch64-linux-clang.cmake | 0 .../cmake/toolchains/arm-apple-clang.cmake | 0 .../cmake/toolchains/arm64-linux-gcc.cmake | 0 .../cmake/toolchains/i386-linux-clang.cmake | 0 .../cmake/toolchains/wasm-linux-clang.cmake | 0 .../cmake/toolchains/x86_64-apple-clang.cmake | 0 .../cmake/toolchains/x86_64-linux-clang.cmake | 0 .../cmake/toolchains/x86_64-linux-gcc.cmake | 0 .../cmake/toolchains/x86_64-linux-gcc10.cmake | 0 .../dockerfiles/Dockerfile.arm64-linux-gcc | 0 .../dockerfiles/Dockerfile.crosstool-ng | 0 .../dockerfiles/Dockerfile.crosstool-ng-arm64 | 0 .../dockerfiles/Dockerfile.wasm-linux-clang | 0 .../Dockerfile.wasm-linux-clang-assert | 0 .../dockerfiles/Dockerfile.x86_64-linux-clang | 0 .../Dockerfile.x86_64-linux-clang-assert | 0 .../dockerfiles/Dockerfile.x86_64-linux-gcc | 0 circuits/{ => cpp}/format.sh | 0 circuits/{ => cpp}/scripts/a3-tests | 0 circuits/{ => cpp}/scripts/run_tests | 0 circuits/{ => cpp}/src/CMakeLists.txt | 0 circuits/{ => cpp}/src/aztec3/CMakeLists.txt | 0 .../{ => cpp}/src/aztec3/circuits/CMakeLists.txt | 0 .../{ => cpp}/src/aztec3/circuits/abis/.test.cpp | 0 .../src/aztec3/circuits/abis/CMakeLists.txt | 0 .../{ => cpp}/src/aztec3/circuits/abis/README.md | 0 .../src/aztec3/circuits/abis/c_bind.cpp | 0 .../{ => cpp}/src/aztec3/circuits/abis/c_bind.h | 0 .../src/aztec3/circuits/abis/c_bind.test.cpp | 0 .../src/aztec3/circuits/abis/call_context.hpp | 0 .../src/aztec3/circuits/abis/call_stack_item.hpp | 0 .../circuits/abis/contract_deployment_data.hpp | 0 .../aztec3/circuits/abis/function_signature.hpp | 0 .../{ => cpp}/src/aztec3/circuits/abis/index.hpp | 0 .../circuits/abis/optionally_revealed_data.hpp | 0 .../abis/private_circuit_public_inputs.hpp | 0 .../abis/private_kernel/accumulated_data.hpp | 0 .../call_context_reconciliation_data.hpp | 0 .../abis/private_kernel/constant_data.hpp | 0 .../circuits/abis/private_kernel/globals.hpp | 0 .../abis/private_kernel/old_tree_roots.hpp | 0 .../abis/private_kernel/previous_kernel_data.hpp | 0 .../abis/private_kernel/private_call_data.hpp | 0 .../abis/private_kernel/private_inputs.hpp | 0 .../abis/private_kernel/public_inputs.hpp | 0 .../abis/public_circuit_public_inputs.hpp | 0 .../aztec3/circuits/abis/signed_tx_request.hpp | 0 .../src/aztec3/circuits/abis/state_read.hpp | 0 .../aztec3/circuits/abis/state_transition.hpp | 0 .../src/aztec3/circuits/abis/tx_context.hpp | 0 .../src/aztec3/circuits/abis/tx_request.hpp | 0 .../{ => cpp}/src/aztec3/circuits/apps/.test.cpp | 0 .../src/aztec3/circuits/apps/CMakeLists.txt | 0 .../{ => cpp}/src/aztec3/circuits/apps/README.md | 0 .../src/aztec3/circuits/apps/contract.hpp | 0 .../src/aztec3/circuits/apps/contract.tpp | 0 .../circuits/apps/function_declaration.hpp | 0 .../circuits/apps/function_execution_context.hpp | 0 .../src/aztec3/circuits/apps/l1_call.hpp | 0 .../circuits/apps/l1_function_interface.hpp | 0 .../circuits/apps/l1_function_interface.tpp | 0 .../apps/notes/default_private_note/note.hpp | 0 .../apps/notes/default_private_note/note.tpp | 0 .../notes/default_private_note/note_preimage.hpp | 0 .../default_private_note/nullifier_preimage.hpp | 0 .../default_singleton_private_note/note.hpp | 0 .../default_singleton_private_note/note.tpp | 0 .../note_preimage.hpp | 0 .../nullifier_preimage.hpp | 0 .../circuits/apps/notes/note_interface.hpp | 0 .../src/aztec3/circuits/apps/opcodes/opcodes.hpp | 0 .../src/aztec3/circuits/apps/opcodes/opcodes.tpp | 0 .../src/aztec3/circuits/apps/oracle_wrapper.hpp | 0 .../aztec3/circuits/apps/private_state.test.cpp | 0 .../circuits/apps/state_vars/field_state_var.hpp | 0 .../apps/state_vars/mapping_state_var.hpp | 0 .../apps/state_vars/mapping_state_var.tpp | 0 .../circuits/apps/state_vars/state_var_base.hpp | 0 .../circuits/apps/state_vars/state_var_base.tpp | 0 .../apps/state_vars/utxo_set_state_var.hpp | 0 .../apps/state_vars/utxo_set_state_var.tpp | 0 .../circuits/apps/state_vars/utxo_state_var.hpp | 0 .../circuits/apps/state_vars/utxo_state_var.tpp | 0 .../circuits/apps/test_apps/escrow/.test.cpp | 0 .../circuits/apps/test_apps/escrow/README.md | 0 .../circuits/apps/test_apps/escrow/contract.hpp | 0 .../circuits/apps/test_apps/escrow/deposit.cpp | 0 .../circuits/apps/test_apps/escrow/deposit.hpp | 0 .../circuits/apps/test_apps/escrow/index.hpp | 0 .../circuits/apps/test_apps/escrow/init.hpp | 0 .../circuits/apps/test_apps/escrow/transfer.cpp | 0 .../circuits/apps/test_apps/escrow/transfer.hpp | 0 .../circuits/apps/test_apps/escrow/withdraw.cpp | 0 .../circuits/apps/test_apps/escrow/withdraw.hpp | 0 .../private_to_private_function_call/.test.cpp | 0 .../private_to_private_function_call/README.md | 0 .../contract.hpp | 0 .../function_1_1.cpp | 0 .../function_1_1.hpp | 0 .../function_2_1.cpp | 0 .../function_2_1.hpp | 0 .../private_to_private_function_call/index.hpp | 0 .../private_to_private_function_call/init.hpp | 0 .../src/aztec3/circuits/apps/utxo_datum.hpp | 0 .../src/aztec3/circuits/kernel/CMakeLists.txt | 0 .../src/aztec3/circuits/kernel/private/.test.cpp | 0 .../src/aztec3/circuits/kernel/private/index.hpp | 0 .../src/aztec3/circuits/kernel/private/init.hpp | 0 .../kernel/private/private_kernel_circuit.cpp | 0 .../kernel/private/private_kernel_circuit.hpp | 0 .../src/aztec3/circuits/mock/mock_circuit.hpp | 0 .../aztec3/circuits/mock/mock_kernel_circuit.hpp | 0 .../src/aztec3/circuits/recursion/CMakeLists.txt | 0 .../src/aztec3/circuits/recursion/aggregator.hpp | 0 .../src/aztec3/circuits/recursion/index.hpp | 0 .../src/aztec3/circuits/recursion/play.test.cpp | 0 .../circuits/recursion/play_app_circuit.hpp | 0 .../recursion/play_recursive_circuit.hpp | 0 .../src/aztec3/circuits/rollup/CMakeLists.txt | 0 circuits/{ => cpp}/src/aztec3/constants.hpp | 0 circuits/{ => cpp}/src/aztec3/dbs/CMakeLists.txt | 0 .../src/aztec3/dbs/private_state_db.hpp | 0 .../{ => cpp}/src/aztec3/oracle/CMakeLists.txt | 0 circuits/{ => cpp}/src/aztec3/oracle/README.md | 0 circuits/{ => cpp}/src/aztec3/oracle/fake_db.hpp | 0 circuits/{ => cpp}/src/aztec3/oracle/oracle.hpp | 0 142 files changed, 13 insertions(+), 13 deletions(-) rename circuits/{ => cpp}/.clang-format (100%) rename circuits/{ => cpp}/.dockerignore (100%) rename circuits/{ => cpp}/CMakeLists.txt (100%) rename circuits/{ => cpp}/barretenberg (100%) rename circuits/{ => cpp}/bootstrap.sh (100%) rename circuits/{ => cpp}/cmake/arch.cmake (100%) rename circuits/{ => cpp}/cmake/barretenberg.cmake (100%) rename circuits/{ => cpp}/cmake/benchmark.cmake (100%) rename circuits/{ => cpp}/cmake/build.cmake (100%) rename circuits/{ => cpp}/cmake/gtest.cmake (100%) rename circuits/{ => cpp}/cmake/module.cmake (100%) rename circuits/{ => cpp}/cmake/threading.cmake (100%) rename circuits/{ => cpp}/cmake/toolchain.cmake (100%) rename circuits/{ => cpp}/cmake/toolchains/aarch64-linux-clang.cmake (100%) rename circuits/{ => cpp}/cmake/toolchains/arm-apple-clang.cmake (100%) rename circuits/{ => cpp}/cmake/toolchains/arm64-linux-gcc.cmake (100%) rename circuits/{ => cpp}/cmake/toolchains/i386-linux-clang.cmake (100%) rename circuits/{ => cpp}/cmake/toolchains/wasm-linux-clang.cmake (100%) rename circuits/{ => cpp}/cmake/toolchains/x86_64-apple-clang.cmake (100%) rename circuits/{ => cpp}/cmake/toolchains/x86_64-linux-clang.cmake (100%) rename circuits/{ => cpp}/cmake/toolchains/x86_64-linux-gcc.cmake (100%) rename circuits/{ => cpp}/cmake/toolchains/x86_64-linux-gcc10.cmake (100%) rename circuits/{ => cpp}/dockerfiles/Dockerfile.arm64-linux-gcc (100%) rename circuits/{ => cpp}/dockerfiles/Dockerfile.crosstool-ng (100%) rename circuits/{ => cpp}/dockerfiles/Dockerfile.crosstool-ng-arm64 (100%) rename circuits/{ => cpp}/dockerfiles/Dockerfile.wasm-linux-clang (100%) rename circuits/{ => cpp}/dockerfiles/Dockerfile.wasm-linux-clang-assert (100%) rename circuits/{ => cpp}/dockerfiles/Dockerfile.x86_64-linux-clang (100%) rename circuits/{ => cpp}/dockerfiles/Dockerfile.x86_64-linux-clang-assert (100%) rename circuits/{ => cpp}/dockerfiles/Dockerfile.x86_64-linux-gcc (100%) rename circuits/{ => cpp}/format.sh (100%) rename circuits/{ => cpp}/scripts/a3-tests (100%) rename circuits/{ => cpp}/scripts/run_tests (100%) rename circuits/{ => cpp}/src/CMakeLists.txt (100%) rename circuits/{ => cpp}/src/aztec3/CMakeLists.txt (100%) rename circuits/{ => cpp}/src/aztec3/circuits/CMakeLists.txt (100%) rename circuits/{ => cpp}/src/aztec3/circuits/abis/.test.cpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/abis/CMakeLists.txt (100%) rename circuits/{ => cpp}/src/aztec3/circuits/abis/README.md (100%) rename circuits/{ => cpp}/src/aztec3/circuits/abis/c_bind.cpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/abis/c_bind.h (100%) rename circuits/{ => cpp}/src/aztec3/circuits/abis/c_bind.test.cpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/abis/call_context.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/abis/call_stack_item.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/abis/contract_deployment_data.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/abis/function_signature.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/abis/index.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/abis/optionally_revealed_data.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/abis/private_kernel/accumulated_data.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/abis/private_kernel/call_context_reconciliation_data.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/abis/private_kernel/constant_data.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/abis/private_kernel/globals.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/abis/private_kernel/old_tree_roots.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/abis/private_kernel/private_call_data.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/abis/private_kernel/private_inputs.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/abis/private_kernel/public_inputs.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/abis/signed_tx_request.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/abis/state_read.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/abis/state_transition.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/abis/tx_context.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/abis/tx_request.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/.test.cpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/CMakeLists.txt (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/README.md (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/contract.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/contract.tpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/function_declaration.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/function_execution_context.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/l1_call.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/l1_function_interface.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/l1_function_interface.tpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/notes/default_private_note/note.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/notes/default_private_note/note.tpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/notes/default_private_note/note_preimage.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/notes/default_private_note/nullifier_preimage.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/notes/default_singleton_private_note/note.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/notes/default_singleton_private_note/note.tpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/notes/default_singleton_private_note/note_preimage.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/notes/default_singleton_private_note/nullifier_preimage.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/notes/note_interface.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/opcodes/opcodes.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/opcodes/opcodes.tpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/oracle_wrapper.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/private_state.test.cpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/state_vars/field_state_var.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/state_vars/mapping_state_var.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/state_vars/mapping_state_var.tpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/state_vars/state_var_base.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/state_vars/state_var_base.tpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/state_vars/utxo_set_state_var.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/state_vars/utxo_set_state_var.tpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/state_vars/utxo_state_var.tpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/test_apps/escrow/README.md (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/test_apps/escrow/deposit.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/test_apps/escrow/index.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/test_apps/escrow/init.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/test_apps/escrow/transfer.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/test_apps/escrow/withdraw.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/README.md (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/contract.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_1_1.cpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_1_1.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_2_1.cpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_2_1.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/index.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/init.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/apps/utxo_datum.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/kernel/CMakeLists.txt (100%) rename circuits/{ => cpp}/src/aztec3/circuits/kernel/private/.test.cpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/kernel/private/index.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/kernel/private/init.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/kernel/private/private_kernel_circuit.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/mock/mock_circuit.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/mock/mock_kernel_circuit.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/recursion/CMakeLists.txt (100%) rename circuits/{ => cpp}/src/aztec3/circuits/recursion/aggregator.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/recursion/index.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/recursion/play.test.cpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/recursion/play_app_circuit.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/recursion/play_recursive_circuit.hpp (100%) rename circuits/{ => cpp}/src/aztec3/circuits/rollup/CMakeLists.txt (100%) rename circuits/{ => cpp}/src/aztec3/constants.hpp (100%) rename circuits/{ => cpp}/src/aztec3/dbs/CMakeLists.txt (100%) rename circuits/{ => cpp}/src/aztec3/dbs/private_state_db.hpp (100%) rename circuits/{ => cpp}/src/aztec3/oracle/CMakeLists.txt (100%) rename circuits/{ => cpp}/src/aztec3/oracle/README.md (100%) rename circuits/{ => cpp}/src/aztec3/oracle/fake_db.hpp (100%) rename circuits/{ => cpp}/src/aztec3/oracle/oracle.hpp (100%) diff --git a/circuits/.gitmodules b/circuits/.gitmodules index 44d9f4ad174..cfe7b14e1c1 100644 --- a/circuits/.gitmodules +++ b/circuits/.gitmodules @@ -1,5 +1,5 @@ [submodule "barretenberg"] - path = barretenberg + path = cpp/barretenberg url = git@github.com:AztecProtocol/barretenberg.git branch = aztec3 [submodule "aztec-build-system"] diff --git a/circuits/build_manifest.json b/circuits/build_manifest.json index 1a574840014..41be4339731 100644 --- a/circuits/build_manifest.json +++ b/circuits/build_manifest.json @@ -1,26 +1,26 @@ { "aztec3-circuits-wasm-linux-clang": { - "buildDir": ".", + "buildDir": "cpp", "dockerfile": "dockerfiles/Dockerfile.wasm-linux-clang", - "rebuildPatterns": ["^."], + "rebuildPatterns": ["^cpp/"], "dependencies": [] }, "aztec3-circuits-wasm-linux-clang-assert": { - "buildDir": ".", + "buildDir": "cpp", "dockerfile": "dockerfiles/Dockerfile.wasm-linux-clang-assert", - "rebuildPatterns": ["^."], + "rebuildPatterns": ["^cpp/"], "dependencies": [] }, "aztec3-circuits-x86_64-linux-clang": { - "buildDir": ".", + "buildDir": "cpp", "dockerfile": "dockerfiles/Dockerfile.x86_64-linux-clang", - "rebuildPatterns": ["^."], + "rebuildPatterns": ["^cpp/"], "dependencies": [] }, "aztec3-circuits-x86_64-linux-clang-assert": { - "buildDir": ".", + "buildDir": "cpp", "dockerfile": "dockerfiles/Dockerfile.x86_64-linux-clang-assert", - "rebuildPatterns": ["^."], + "rebuildPatterns": ["^cpp/"], "dependencies": [] } } \ No newline at end of file diff --git a/circuits/build_manifest.sh b/circuits/build_manifest.sh index 609e769ee9f..27c20aef9c8 100644 --- a/circuits/build_manifest.sh +++ b/circuits/build_manifest.sh @@ -7,8 +7,8 @@ # Commenting out a few projects, as the main use case is now to build the images needed to run end-to-end tests. # If wanting to just see if docker images actually build, you can temporarily uncomment required projects. PROJECTS=( - aztec3-circuits-wasm:./:./dockerfiles/Dockerfile.wasm-linux-clang:aztec3-circuits-wasm-linux-clang - aztec3-circuits-wasm-assert:./:./dockerfiles/Dockerfile.wasm-linux-clang-assert:aztec3-circuits-wasm-linux-clang-assert - aztec3-circuits-x86_64-clang:./:./dockerfiles/Dockerfile.x86_64-linux-clang:aztec3-circuits-x86_64-linux-clang - aztec3-circuits-x86_64-clang-assert:./:./dockerfiles/Dockerfile.x86_64-linux-clang-assert:aztec3-circuits-x86_64-linux-clang-assert + aztec3-circuits-wasm:cpp:./dockerfiles/Dockerfile.wasm-linux-clang:aztec3-circuits-wasm-linux-clang + aztec3-circuits-wasm-assert:cpp:./dockerfiles/Dockerfile.wasm-linux-clang-assert:aztec3-circuits-wasm-linux-clang-assert + aztec3-circuits-x86_64-clang:cpp:./dockerfiles/Dockerfile.x86_64-linux-clang:aztec3-circuits-x86_64-linux-clang + aztec3-circuits-x86_64-clang-assert:cpp:./dockerfiles/Dockerfile.x86_64-linux-clang-assert:aztec3-circuits-x86_64-linux-clang-assert ) \ No newline at end of file diff --git a/circuits/.clang-format b/circuits/cpp/.clang-format similarity index 100% rename from circuits/.clang-format rename to circuits/cpp/.clang-format diff --git a/circuits/.dockerignore b/circuits/cpp/.dockerignore similarity index 100% rename from circuits/.dockerignore rename to circuits/cpp/.dockerignore diff --git a/circuits/CMakeLists.txt b/circuits/cpp/CMakeLists.txt similarity index 100% rename from circuits/CMakeLists.txt rename to circuits/cpp/CMakeLists.txt diff --git a/circuits/barretenberg b/circuits/cpp/barretenberg similarity index 100% rename from circuits/barretenberg rename to circuits/cpp/barretenberg diff --git a/circuits/bootstrap.sh b/circuits/cpp/bootstrap.sh similarity index 100% rename from circuits/bootstrap.sh rename to circuits/cpp/bootstrap.sh diff --git a/circuits/cmake/arch.cmake b/circuits/cpp/cmake/arch.cmake similarity index 100% rename from circuits/cmake/arch.cmake rename to circuits/cpp/cmake/arch.cmake diff --git a/circuits/cmake/barretenberg.cmake b/circuits/cpp/cmake/barretenberg.cmake similarity index 100% rename from circuits/cmake/barretenberg.cmake rename to circuits/cpp/cmake/barretenberg.cmake diff --git a/circuits/cmake/benchmark.cmake b/circuits/cpp/cmake/benchmark.cmake similarity index 100% rename from circuits/cmake/benchmark.cmake rename to circuits/cpp/cmake/benchmark.cmake diff --git a/circuits/cmake/build.cmake b/circuits/cpp/cmake/build.cmake similarity index 100% rename from circuits/cmake/build.cmake rename to circuits/cpp/cmake/build.cmake diff --git a/circuits/cmake/gtest.cmake b/circuits/cpp/cmake/gtest.cmake similarity index 100% rename from circuits/cmake/gtest.cmake rename to circuits/cpp/cmake/gtest.cmake diff --git a/circuits/cmake/module.cmake b/circuits/cpp/cmake/module.cmake similarity index 100% rename from circuits/cmake/module.cmake rename to circuits/cpp/cmake/module.cmake diff --git a/circuits/cmake/threading.cmake b/circuits/cpp/cmake/threading.cmake similarity index 100% rename from circuits/cmake/threading.cmake rename to circuits/cpp/cmake/threading.cmake diff --git a/circuits/cmake/toolchain.cmake b/circuits/cpp/cmake/toolchain.cmake similarity index 100% rename from circuits/cmake/toolchain.cmake rename to circuits/cpp/cmake/toolchain.cmake diff --git a/circuits/cmake/toolchains/aarch64-linux-clang.cmake b/circuits/cpp/cmake/toolchains/aarch64-linux-clang.cmake similarity index 100% rename from circuits/cmake/toolchains/aarch64-linux-clang.cmake rename to circuits/cpp/cmake/toolchains/aarch64-linux-clang.cmake diff --git a/circuits/cmake/toolchains/arm-apple-clang.cmake b/circuits/cpp/cmake/toolchains/arm-apple-clang.cmake similarity index 100% rename from circuits/cmake/toolchains/arm-apple-clang.cmake rename to circuits/cpp/cmake/toolchains/arm-apple-clang.cmake diff --git a/circuits/cmake/toolchains/arm64-linux-gcc.cmake b/circuits/cpp/cmake/toolchains/arm64-linux-gcc.cmake similarity index 100% rename from circuits/cmake/toolchains/arm64-linux-gcc.cmake rename to circuits/cpp/cmake/toolchains/arm64-linux-gcc.cmake diff --git a/circuits/cmake/toolchains/i386-linux-clang.cmake b/circuits/cpp/cmake/toolchains/i386-linux-clang.cmake similarity index 100% rename from circuits/cmake/toolchains/i386-linux-clang.cmake rename to circuits/cpp/cmake/toolchains/i386-linux-clang.cmake diff --git a/circuits/cmake/toolchains/wasm-linux-clang.cmake b/circuits/cpp/cmake/toolchains/wasm-linux-clang.cmake similarity index 100% rename from circuits/cmake/toolchains/wasm-linux-clang.cmake rename to circuits/cpp/cmake/toolchains/wasm-linux-clang.cmake diff --git a/circuits/cmake/toolchains/x86_64-apple-clang.cmake b/circuits/cpp/cmake/toolchains/x86_64-apple-clang.cmake similarity index 100% rename from circuits/cmake/toolchains/x86_64-apple-clang.cmake rename to circuits/cpp/cmake/toolchains/x86_64-apple-clang.cmake diff --git a/circuits/cmake/toolchains/x86_64-linux-clang.cmake b/circuits/cpp/cmake/toolchains/x86_64-linux-clang.cmake similarity index 100% rename from circuits/cmake/toolchains/x86_64-linux-clang.cmake rename to circuits/cpp/cmake/toolchains/x86_64-linux-clang.cmake diff --git a/circuits/cmake/toolchains/x86_64-linux-gcc.cmake b/circuits/cpp/cmake/toolchains/x86_64-linux-gcc.cmake similarity index 100% rename from circuits/cmake/toolchains/x86_64-linux-gcc.cmake rename to circuits/cpp/cmake/toolchains/x86_64-linux-gcc.cmake diff --git a/circuits/cmake/toolchains/x86_64-linux-gcc10.cmake b/circuits/cpp/cmake/toolchains/x86_64-linux-gcc10.cmake similarity index 100% rename from circuits/cmake/toolchains/x86_64-linux-gcc10.cmake rename to circuits/cpp/cmake/toolchains/x86_64-linux-gcc10.cmake diff --git a/circuits/dockerfiles/Dockerfile.arm64-linux-gcc b/circuits/cpp/dockerfiles/Dockerfile.arm64-linux-gcc similarity index 100% rename from circuits/dockerfiles/Dockerfile.arm64-linux-gcc rename to circuits/cpp/dockerfiles/Dockerfile.arm64-linux-gcc diff --git a/circuits/dockerfiles/Dockerfile.crosstool-ng b/circuits/cpp/dockerfiles/Dockerfile.crosstool-ng similarity index 100% rename from circuits/dockerfiles/Dockerfile.crosstool-ng rename to circuits/cpp/dockerfiles/Dockerfile.crosstool-ng diff --git a/circuits/dockerfiles/Dockerfile.crosstool-ng-arm64 b/circuits/cpp/dockerfiles/Dockerfile.crosstool-ng-arm64 similarity index 100% rename from circuits/dockerfiles/Dockerfile.crosstool-ng-arm64 rename to circuits/cpp/dockerfiles/Dockerfile.crosstool-ng-arm64 diff --git a/circuits/dockerfiles/Dockerfile.wasm-linux-clang b/circuits/cpp/dockerfiles/Dockerfile.wasm-linux-clang similarity index 100% rename from circuits/dockerfiles/Dockerfile.wasm-linux-clang rename to circuits/cpp/dockerfiles/Dockerfile.wasm-linux-clang diff --git a/circuits/dockerfiles/Dockerfile.wasm-linux-clang-assert b/circuits/cpp/dockerfiles/Dockerfile.wasm-linux-clang-assert similarity index 100% rename from circuits/dockerfiles/Dockerfile.wasm-linux-clang-assert rename to circuits/cpp/dockerfiles/Dockerfile.wasm-linux-clang-assert diff --git a/circuits/dockerfiles/Dockerfile.x86_64-linux-clang b/circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-clang similarity index 100% rename from circuits/dockerfiles/Dockerfile.x86_64-linux-clang rename to circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-clang diff --git a/circuits/dockerfiles/Dockerfile.x86_64-linux-clang-assert b/circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-clang-assert similarity index 100% rename from circuits/dockerfiles/Dockerfile.x86_64-linux-clang-assert rename to circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-clang-assert diff --git a/circuits/dockerfiles/Dockerfile.x86_64-linux-gcc b/circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-gcc similarity index 100% rename from circuits/dockerfiles/Dockerfile.x86_64-linux-gcc rename to circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-gcc diff --git a/circuits/format.sh b/circuits/cpp/format.sh similarity index 100% rename from circuits/format.sh rename to circuits/cpp/format.sh diff --git a/circuits/scripts/a3-tests b/circuits/cpp/scripts/a3-tests similarity index 100% rename from circuits/scripts/a3-tests rename to circuits/cpp/scripts/a3-tests diff --git a/circuits/scripts/run_tests b/circuits/cpp/scripts/run_tests similarity index 100% rename from circuits/scripts/run_tests rename to circuits/cpp/scripts/run_tests diff --git a/circuits/src/CMakeLists.txt b/circuits/cpp/src/CMakeLists.txt similarity index 100% rename from circuits/src/CMakeLists.txt rename to circuits/cpp/src/CMakeLists.txt diff --git a/circuits/src/aztec3/CMakeLists.txt b/circuits/cpp/src/aztec3/CMakeLists.txt similarity index 100% rename from circuits/src/aztec3/CMakeLists.txt rename to circuits/cpp/src/aztec3/CMakeLists.txt diff --git a/circuits/src/aztec3/circuits/CMakeLists.txt b/circuits/cpp/src/aztec3/circuits/CMakeLists.txt similarity index 100% rename from circuits/src/aztec3/circuits/CMakeLists.txt rename to circuits/cpp/src/aztec3/circuits/CMakeLists.txt diff --git a/circuits/src/aztec3/circuits/abis/.test.cpp b/circuits/cpp/src/aztec3/circuits/abis/.test.cpp similarity index 100% rename from circuits/src/aztec3/circuits/abis/.test.cpp rename to circuits/cpp/src/aztec3/circuits/abis/.test.cpp diff --git a/circuits/src/aztec3/circuits/abis/CMakeLists.txt b/circuits/cpp/src/aztec3/circuits/abis/CMakeLists.txt similarity index 100% rename from circuits/src/aztec3/circuits/abis/CMakeLists.txt rename to circuits/cpp/src/aztec3/circuits/abis/CMakeLists.txt diff --git a/circuits/src/aztec3/circuits/abis/README.md b/circuits/cpp/src/aztec3/circuits/abis/README.md similarity index 100% rename from circuits/src/aztec3/circuits/abis/README.md rename to circuits/cpp/src/aztec3/circuits/abis/README.md diff --git a/circuits/src/aztec3/circuits/abis/c_bind.cpp b/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp similarity index 100% rename from circuits/src/aztec3/circuits/abis/c_bind.cpp rename to circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp diff --git a/circuits/src/aztec3/circuits/abis/c_bind.h b/circuits/cpp/src/aztec3/circuits/abis/c_bind.h similarity index 100% rename from circuits/src/aztec3/circuits/abis/c_bind.h rename to circuits/cpp/src/aztec3/circuits/abis/c_bind.h diff --git a/circuits/src/aztec3/circuits/abis/c_bind.test.cpp b/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp similarity index 100% rename from circuits/src/aztec3/circuits/abis/c_bind.test.cpp rename to circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp diff --git a/circuits/src/aztec3/circuits/abis/call_context.hpp b/circuits/cpp/src/aztec3/circuits/abis/call_context.hpp similarity index 100% rename from circuits/src/aztec3/circuits/abis/call_context.hpp rename to circuits/cpp/src/aztec3/circuits/abis/call_context.hpp diff --git a/circuits/src/aztec3/circuits/abis/call_stack_item.hpp b/circuits/cpp/src/aztec3/circuits/abis/call_stack_item.hpp similarity index 100% rename from circuits/src/aztec3/circuits/abis/call_stack_item.hpp rename to circuits/cpp/src/aztec3/circuits/abis/call_stack_item.hpp diff --git a/circuits/src/aztec3/circuits/abis/contract_deployment_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/contract_deployment_data.hpp similarity index 100% rename from circuits/src/aztec3/circuits/abis/contract_deployment_data.hpp rename to circuits/cpp/src/aztec3/circuits/abis/contract_deployment_data.hpp diff --git a/circuits/src/aztec3/circuits/abis/function_signature.hpp b/circuits/cpp/src/aztec3/circuits/abis/function_signature.hpp similarity index 100% rename from circuits/src/aztec3/circuits/abis/function_signature.hpp rename to circuits/cpp/src/aztec3/circuits/abis/function_signature.hpp diff --git a/circuits/src/aztec3/circuits/abis/index.hpp b/circuits/cpp/src/aztec3/circuits/abis/index.hpp similarity index 100% rename from circuits/src/aztec3/circuits/abis/index.hpp rename to circuits/cpp/src/aztec3/circuits/abis/index.hpp diff --git a/circuits/src/aztec3/circuits/abis/optionally_revealed_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/optionally_revealed_data.hpp similarity index 100% rename from circuits/src/aztec3/circuits/abis/optionally_revealed_data.hpp rename to circuits/cpp/src/aztec3/circuits/abis/optionally_revealed_data.hpp diff --git a/circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp similarity index 100% rename from circuits/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp rename to circuits/cpp/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp diff --git a/circuits/src/aztec3/circuits/abis/private_kernel/accumulated_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/accumulated_data.hpp similarity index 100% rename from circuits/src/aztec3/circuits/abis/private_kernel/accumulated_data.hpp rename to circuits/cpp/src/aztec3/circuits/abis/private_kernel/accumulated_data.hpp diff --git a/circuits/src/aztec3/circuits/abis/private_kernel/call_context_reconciliation_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/call_context_reconciliation_data.hpp similarity index 100% rename from circuits/src/aztec3/circuits/abis/private_kernel/call_context_reconciliation_data.hpp rename to circuits/cpp/src/aztec3/circuits/abis/private_kernel/call_context_reconciliation_data.hpp diff --git a/circuits/src/aztec3/circuits/abis/private_kernel/constant_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/constant_data.hpp similarity index 100% rename from circuits/src/aztec3/circuits/abis/private_kernel/constant_data.hpp rename to circuits/cpp/src/aztec3/circuits/abis/private_kernel/constant_data.hpp diff --git a/circuits/src/aztec3/circuits/abis/private_kernel/globals.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/globals.hpp similarity index 100% rename from circuits/src/aztec3/circuits/abis/private_kernel/globals.hpp rename to circuits/cpp/src/aztec3/circuits/abis/private_kernel/globals.hpp diff --git a/circuits/src/aztec3/circuits/abis/private_kernel/old_tree_roots.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/old_tree_roots.hpp similarity index 100% rename from circuits/src/aztec3/circuits/abis/private_kernel/old_tree_roots.hpp rename to circuits/cpp/src/aztec3/circuits/abis/private_kernel/old_tree_roots.hpp diff --git a/circuits/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp similarity index 100% rename from circuits/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp rename to circuits/cpp/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp diff --git a/circuits/src/aztec3/circuits/abis/private_kernel/private_call_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/private_call_data.hpp similarity index 100% rename from circuits/src/aztec3/circuits/abis/private_kernel/private_call_data.hpp rename to circuits/cpp/src/aztec3/circuits/abis/private_kernel/private_call_data.hpp diff --git a/circuits/src/aztec3/circuits/abis/private_kernel/private_inputs.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/private_inputs.hpp similarity index 100% rename from circuits/src/aztec3/circuits/abis/private_kernel/private_inputs.hpp rename to circuits/cpp/src/aztec3/circuits/abis/private_kernel/private_inputs.hpp diff --git a/circuits/src/aztec3/circuits/abis/private_kernel/public_inputs.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/public_inputs.hpp similarity index 100% rename from circuits/src/aztec3/circuits/abis/private_kernel/public_inputs.hpp rename to circuits/cpp/src/aztec3/circuits/abis/private_kernel/public_inputs.hpp diff --git a/circuits/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp b/circuits/cpp/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp similarity index 100% rename from circuits/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp rename to circuits/cpp/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp diff --git a/circuits/src/aztec3/circuits/abis/signed_tx_request.hpp b/circuits/cpp/src/aztec3/circuits/abis/signed_tx_request.hpp similarity index 100% rename from circuits/src/aztec3/circuits/abis/signed_tx_request.hpp rename to circuits/cpp/src/aztec3/circuits/abis/signed_tx_request.hpp diff --git a/circuits/src/aztec3/circuits/abis/state_read.hpp b/circuits/cpp/src/aztec3/circuits/abis/state_read.hpp similarity index 100% rename from circuits/src/aztec3/circuits/abis/state_read.hpp rename to circuits/cpp/src/aztec3/circuits/abis/state_read.hpp diff --git a/circuits/src/aztec3/circuits/abis/state_transition.hpp b/circuits/cpp/src/aztec3/circuits/abis/state_transition.hpp similarity index 100% rename from circuits/src/aztec3/circuits/abis/state_transition.hpp rename to circuits/cpp/src/aztec3/circuits/abis/state_transition.hpp diff --git a/circuits/src/aztec3/circuits/abis/tx_context.hpp b/circuits/cpp/src/aztec3/circuits/abis/tx_context.hpp similarity index 100% rename from circuits/src/aztec3/circuits/abis/tx_context.hpp rename to circuits/cpp/src/aztec3/circuits/abis/tx_context.hpp diff --git a/circuits/src/aztec3/circuits/abis/tx_request.hpp b/circuits/cpp/src/aztec3/circuits/abis/tx_request.hpp similarity index 100% rename from circuits/src/aztec3/circuits/abis/tx_request.hpp rename to circuits/cpp/src/aztec3/circuits/abis/tx_request.hpp diff --git a/circuits/src/aztec3/circuits/apps/.test.cpp b/circuits/cpp/src/aztec3/circuits/apps/.test.cpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/.test.cpp rename to circuits/cpp/src/aztec3/circuits/apps/.test.cpp diff --git a/circuits/src/aztec3/circuits/apps/CMakeLists.txt b/circuits/cpp/src/aztec3/circuits/apps/CMakeLists.txt similarity index 100% rename from circuits/src/aztec3/circuits/apps/CMakeLists.txt rename to circuits/cpp/src/aztec3/circuits/apps/CMakeLists.txt diff --git a/circuits/src/aztec3/circuits/apps/README.md b/circuits/cpp/src/aztec3/circuits/apps/README.md similarity index 100% rename from circuits/src/aztec3/circuits/apps/README.md rename to circuits/cpp/src/aztec3/circuits/apps/README.md diff --git a/circuits/src/aztec3/circuits/apps/contract.hpp b/circuits/cpp/src/aztec3/circuits/apps/contract.hpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/contract.hpp rename to circuits/cpp/src/aztec3/circuits/apps/contract.hpp diff --git a/circuits/src/aztec3/circuits/apps/contract.tpp b/circuits/cpp/src/aztec3/circuits/apps/contract.tpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/contract.tpp rename to circuits/cpp/src/aztec3/circuits/apps/contract.tpp diff --git a/circuits/src/aztec3/circuits/apps/function_declaration.hpp b/circuits/cpp/src/aztec3/circuits/apps/function_declaration.hpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/function_declaration.hpp rename to circuits/cpp/src/aztec3/circuits/apps/function_declaration.hpp diff --git a/circuits/src/aztec3/circuits/apps/function_execution_context.hpp b/circuits/cpp/src/aztec3/circuits/apps/function_execution_context.hpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/function_execution_context.hpp rename to circuits/cpp/src/aztec3/circuits/apps/function_execution_context.hpp diff --git a/circuits/src/aztec3/circuits/apps/l1_call.hpp b/circuits/cpp/src/aztec3/circuits/apps/l1_call.hpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/l1_call.hpp rename to circuits/cpp/src/aztec3/circuits/apps/l1_call.hpp diff --git a/circuits/src/aztec3/circuits/apps/l1_function_interface.hpp b/circuits/cpp/src/aztec3/circuits/apps/l1_function_interface.hpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/l1_function_interface.hpp rename to circuits/cpp/src/aztec3/circuits/apps/l1_function_interface.hpp diff --git a/circuits/src/aztec3/circuits/apps/l1_function_interface.tpp b/circuits/cpp/src/aztec3/circuits/apps/l1_function_interface.tpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/l1_function_interface.tpp rename to circuits/cpp/src/aztec3/circuits/apps/l1_function_interface.tpp diff --git a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.hpp b/circuits/cpp/src/aztec3/circuits/apps/notes/default_private_note/note.hpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/notes/default_private_note/note.hpp rename to circuits/cpp/src/aztec3/circuits/apps/notes/default_private_note/note.hpp diff --git a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note.tpp b/circuits/cpp/src/aztec3/circuits/apps/notes/default_private_note/note.tpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/notes/default_private_note/note.tpp rename to circuits/cpp/src/aztec3/circuits/apps/notes/default_private_note/note.tpp diff --git a/circuits/src/aztec3/circuits/apps/notes/default_private_note/note_preimage.hpp b/circuits/cpp/src/aztec3/circuits/apps/notes/default_private_note/note_preimage.hpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/notes/default_private_note/note_preimage.hpp rename to circuits/cpp/src/aztec3/circuits/apps/notes/default_private_note/note_preimage.hpp diff --git a/circuits/src/aztec3/circuits/apps/notes/default_private_note/nullifier_preimage.hpp b/circuits/cpp/src/aztec3/circuits/apps/notes/default_private_note/nullifier_preimage.hpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/notes/default_private_note/nullifier_preimage.hpp rename to circuits/cpp/src/aztec3/circuits/apps/notes/default_private_note/nullifier_preimage.hpp diff --git a/circuits/src/aztec3/circuits/apps/notes/default_singleton_private_note/note.hpp b/circuits/cpp/src/aztec3/circuits/apps/notes/default_singleton_private_note/note.hpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/notes/default_singleton_private_note/note.hpp rename to circuits/cpp/src/aztec3/circuits/apps/notes/default_singleton_private_note/note.hpp diff --git a/circuits/src/aztec3/circuits/apps/notes/default_singleton_private_note/note.tpp b/circuits/cpp/src/aztec3/circuits/apps/notes/default_singleton_private_note/note.tpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/notes/default_singleton_private_note/note.tpp rename to circuits/cpp/src/aztec3/circuits/apps/notes/default_singleton_private_note/note.tpp diff --git a/circuits/src/aztec3/circuits/apps/notes/default_singleton_private_note/note_preimage.hpp b/circuits/cpp/src/aztec3/circuits/apps/notes/default_singleton_private_note/note_preimage.hpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/notes/default_singleton_private_note/note_preimage.hpp rename to circuits/cpp/src/aztec3/circuits/apps/notes/default_singleton_private_note/note_preimage.hpp diff --git a/circuits/src/aztec3/circuits/apps/notes/default_singleton_private_note/nullifier_preimage.hpp b/circuits/cpp/src/aztec3/circuits/apps/notes/default_singleton_private_note/nullifier_preimage.hpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/notes/default_singleton_private_note/nullifier_preimage.hpp rename to circuits/cpp/src/aztec3/circuits/apps/notes/default_singleton_private_note/nullifier_preimage.hpp diff --git a/circuits/src/aztec3/circuits/apps/notes/note_interface.hpp b/circuits/cpp/src/aztec3/circuits/apps/notes/note_interface.hpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/notes/note_interface.hpp rename to circuits/cpp/src/aztec3/circuits/apps/notes/note_interface.hpp diff --git a/circuits/src/aztec3/circuits/apps/opcodes/opcodes.hpp b/circuits/cpp/src/aztec3/circuits/apps/opcodes/opcodes.hpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/opcodes/opcodes.hpp rename to circuits/cpp/src/aztec3/circuits/apps/opcodes/opcodes.hpp diff --git a/circuits/src/aztec3/circuits/apps/opcodes/opcodes.tpp b/circuits/cpp/src/aztec3/circuits/apps/opcodes/opcodes.tpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/opcodes/opcodes.tpp rename to circuits/cpp/src/aztec3/circuits/apps/opcodes/opcodes.tpp diff --git a/circuits/src/aztec3/circuits/apps/oracle_wrapper.hpp b/circuits/cpp/src/aztec3/circuits/apps/oracle_wrapper.hpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/oracle_wrapper.hpp rename to circuits/cpp/src/aztec3/circuits/apps/oracle_wrapper.hpp diff --git a/circuits/src/aztec3/circuits/apps/private_state.test.cpp b/circuits/cpp/src/aztec3/circuits/apps/private_state.test.cpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/private_state.test.cpp rename to circuits/cpp/src/aztec3/circuits/apps/private_state.test.cpp diff --git a/circuits/src/aztec3/circuits/apps/state_vars/field_state_var.hpp b/circuits/cpp/src/aztec3/circuits/apps/state_vars/field_state_var.hpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/state_vars/field_state_var.hpp rename to circuits/cpp/src/aztec3/circuits/apps/state_vars/field_state_var.hpp diff --git a/circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.hpp b/circuits/cpp/src/aztec3/circuits/apps/state_vars/mapping_state_var.hpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.hpp rename to circuits/cpp/src/aztec3/circuits/apps/state_vars/mapping_state_var.hpp diff --git a/circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.tpp b/circuits/cpp/src/aztec3/circuits/apps/state_vars/mapping_state_var.tpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/state_vars/mapping_state_var.tpp rename to circuits/cpp/src/aztec3/circuits/apps/state_vars/mapping_state_var.tpp diff --git a/circuits/src/aztec3/circuits/apps/state_vars/state_var_base.hpp b/circuits/cpp/src/aztec3/circuits/apps/state_vars/state_var_base.hpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/state_vars/state_var_base.hpp rename to circuits/cpp/src/aztec3/circuits/apps/state_vars/state_var_base.hpp diff --git a/circuits/src/aztec3/circuits/apps/state_vars/state_var_base.tpp b/circuits/cpp/src/aztec3/circuits/apps/state_vars/state_var_base.tpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/state_vars/state_var_base.tpp rename to circuits/cpp/src/aztec3/circuits/apps/state_vars/state_var_base.tpp diff --git a/circuits/src/aztec3/circuits/apps/state_vars/utxo_set_state_var.hpp b/circuits/cpp/src/aztec3/circuits/apps/state_vars/utxo_set_state_var.hpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/state_vars/utxo_set_state_var.hpp rename to circuits/cpp/src/aztec3/circuits/apps/state_vars/utxo_set_state_var.hpp diff --git a/circuits/src/aztec3/circuits/apps/state_vars/utxo_set_state_var.tpp b/circuits/cpp/src/aztec3/circuits/apps/state_vars/utxo_set_state_var.tpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/state_vars/utxo_set_state_var.tpp rename to circuits/cpp/src/aztec3/circuits/apps/state_vars/utxo_set_state_var.tpp diff --git a/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp b/circuits/cpp/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp rename to circuits/cpp/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp diff --git a/circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.tpp b/circuits/cpp/src/aztec3/circuits/apps/state_vars/utxo_state_var.tpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/state_vars/utxo_state_var.tpp rename to circuits/cpp/src/aztec3/circuits/apps/state_vars/utxo_state_var.tpp diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp b/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp rename to circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/README.md b/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/README.md similarity index 100% rename from circuits/src/aztec3/circuits/apps/test_apps/escrow/README.md rename to circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/README.md diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp b/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp rename to circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/contract.hpp diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp b/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp rename to circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.hpp b/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/deposit.hpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/test_apps/escrow/deposit.hpp rename to circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/deposit.hpp diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/index.hpp b/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/index.hpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/test_apps/escrow/index.hpp rename to circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/index.hpp diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/init.hpp b/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/init.hpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/test_apps/escrow/init.hpp rename to circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/init.hpp diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp b/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp rename to circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.hpp b/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/transfer.hpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/test_apps/escrow/transfer.hpp rename to circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/transfer.hpp diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp b/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp rename to circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp diff --git a/circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.hpp b/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/withdraw.hpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/test_apps/escrow/withdraw.hpp rename to circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/withdraw.hpp diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp b/circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp rename to circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/README.md b/circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/README.md similarity index 100% rename from circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/README.md rename to circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/README.md diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/contract.hpp b/circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/contract.hpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/contract.hpp rename to circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/contract.hpp diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_1_1.cpp b/circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_1_1.cpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_1_1.cpp rename to circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_1_1.cpp diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_1_1.hpp b/circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_1_1.hpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_1_1.hpp rename to circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_1_1.hpp diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_2_1.cpp b/circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_2_1.cpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_2_1.cpp rename to circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_2_1.cpp diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_2_1.hpp b/circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_2_1.hpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_2_1.hpp rename to circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/function_2_1.hpp diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/index.hpp b/circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/index.hpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/index.hpp rename to circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/index.hpp diff --git a/circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/init.hpp b/circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/init.hpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/init.hpp rename to circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/init.hpp diff --git a/circuits/src/aztec3/circuits/apps/utxo_datum.hpp b/circuits/cpp/src/aztec3/circuits/apps/utxo_datum.hpp similarity index 100% rename from circuits/src/aztec3/circuits/apps/utxo_datum.hpp rename to circuits/cpp/src/aztec3/circuits/apps/utxo_datum.hpp diff --git a/circuits/src/aztec3/circuits/kernel/CMakeLists.txt b/circuits/cpp/src/aztec3/circuits/kernel/CMakeLists.txt similarity index 100% rename from circuits/src/aztec3/circuits/kernel/CMakeLists.txt rename to circuits/cpp/src/aztec3/circuits/kernel/CMakeLists.txt diff --git a/circuits/src/aztec3/circuits/kernel/private/.test.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/.test.cpp similarity index 100% rename from circuits/src/aztec3/circuits/kernel/private/.test.cpp rename to circuits/cpp/src/aztec3/circuits/kernel/private/.test.cpp diff --git a/circuits/src/aztec3/circuits/kernel/private/index.hpp b/circuits/cpp/src/aztec3/circuits/kernel/private/index.hpp similarity index 100% rename from circuits/src/aztec3/circuits/kernel/private/index.hpp rename to circuits/cpp/src/aztec3/circuits/kernel/private/index.hpp diff --git a/circuits/src/aztec3/circuits/kernel/private/init.hpp b/circuits/cpp/src/aztec3/circuits/kernel/private/init.hpp similarity index 100% rename from circuits/src/aztec3/circuits/kernel/private/init.hpp rename to circuits/cpp/src/aztec3/circuits/kernel/private/init.hpp diff --git a/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp similarity index 100% rename from circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp rename to circuits/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp diff --git a/circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.hpp b/circuits/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.hpp similarity index 100% rename from circuits/src/aztec3/circuits/kernel/private/private_kernel_circuit.hpp rename to circuits/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.hpp diff --git a/circuits/src/aztec3/circuits/mock/mock_circuit.hpp b/circuits/cpp/src/aztec3/circuits/mock/mock_circuit.hpp similarity index 100% rename from circuits/src/aztec3/circuits/mock/mock_circuit.hpp rename to circuits/cpp/src/aztec3/circuits/mock/mock_circuit.hpp diff --git a/circuits/src/aztec3/circuits/mock/mock_kernel_circuit.hpp b/circuits/cpp/src/aztec3/circuits/mock/mock_kernel_circuit.hpp similarity index 100% rename from circuits/src/aztec3/circuits/mock/mock_kernel_circuit.hpp rename to circuits/cpp/src/aztec3/circuits/mock/mock_kernel_circuit.hpp diff --git a/circuits/src/aztec3/circuits/recursion/CMakeLists.txt b/circuits/cpp/src/aztec3/circuits/recursion/CMakeLists.txt similarity index 100% rename from circuits/src/aztec3/circuits/recursion/CMakeLists.txt rename to circuits/cpp/src/aztec3/circuits/recursion/CMakeLists.txt diff --git a/circuits/src/aztec3/circuits/recursion/aggregator.hpp b/circuits/cpp/src/aztec3/circuits/recursion/aggregator.hpp similarity index 100% rename from circuits/src/aztec3/circuits/recursion/aggregator.hpp rename to circuits/cpp/src/aztec3/circuits/recursion/aggregator.hpp diff --git a/circuits/src/aztec3/circuits/recursion/index.hpp b/circuits/cpp/src/aztec3/circuits/recursion/index.hpp similarity index 100% rename from circuits/src/aztec3/circuits/recursion/index.hpp rename to circuits/cpp/src/aztec3/circuits/recursion/index.hpp diff --git a/circuits/src/aztec3/circuits/recursion/play.test.cpp b/circuits/cpp/src/aztec3/circuits/recursion/play.test.cpp similarity index 100% rename from circuits/src/aztec3/circuits/recursion/play.test.cpp rename to circuits/cpp/src/aztec3/circuits/recursion/play.test.cpp diff --git a/circuits/src/aztec3/circuits/recursion/play_app_circuit.hpp b/circuits/cpp/src/aztec3/circuits/recursion/play_app_circuit.hpp similarity index 100% rename from circuits/src/aztec3/circuits/recursion/play_app_circuit.hpp rename to circuits/cpp/src/aztec3/circuits/recursion/play_app_circuit.hpp diff --git a/circuits/src/aztec3/circuits/recursion/play_recursive_circuit.hpp b/circuits/cpp/src/aztec3/circuits/recursion/play_recursive_circuit.hpp similarity index 100% rename from circuits/src/aztec3/circuits/recursion/play_recursive_circuit.hpp rename to circuits/cpp/src/aztec3/circuits/recursion/play_recursive_circuit.hpp diff --git a/circuits/src/aztec3/circuits/rollup/CMakeLists.txt b/circuits/cpp/src/aztec3/circuits/rollup/CMakeLists.txt similarity index 100% rename from circuits/src/aztec3/circuits/rollup/CMakeLists.txt rename to circuits/cpp/src/aztec3/circuits/rollup/CMakeLists.txt diff --git a/circuits/src/aztec3/constants.hpp b/circuits/cpp/src/aztec3/constants.hpp similarity index 100% rename from circuits/src/aztec3/constants.hpp rename to circuits/cpp/src/aztec3/constants.hpp diff --git a/circuits/src/aztec3/dbs/CMakeLists.txt b/circuits/cpp/src/aztec3/dbs/CMakeLists.txt similarity index 100% rename from circuits/src/aztec3/dbs/CMakeLists.txt rename to circuits/cpp/src/aztec3/dbs/CMakeLists.txt diff --git a/circuits/src/aztec3/dbs/private_state_db.hpp b/circuits/cpp/src/aztec3/dbs/private_state_db.hpp similarity index 100% rename from circuits/src/aztec3/dbs/private_state_db.hpp rename to circuits/cpp/src/aztec3/dbs/private_state_db.hpp diff --git a/circuits/src/aztec3/oracle/CMakeLists.txt b/circuits/cpp/src/aztec3/oracle/CMakeLists.txt similarity index 100% rename from circuits/src/aztec3/oracle/CMakeLists.txt rename to circuits/cpp/src/aztec3/oracle/CMakeLists.txt diff --git a/circuits/src/aztec3/oracle/README.md b/circuits/cpp/src/aztec3/oracle/README.md similarity index 100% rename from circuits/src/aztec3/oracle/README.md rename to circuits/cpp/src/aztec3/oracle/README.md diff --git a/circuits/src/aztec3/oracle/fake_db.hpp b/circuits/cpp/src/aztec3/oracle/fake_db.hpp similarity index 100% rename from circuits/src/aztec3/oracle/fake_db.hpp rename to circuits/cpp/src/aztec3/oracle/fake_db.hpp diff --git a/circuits/src/aztec3/oracle/oracle.hpp b/circuits/cpp/src/aztec3/oracle/oracle.hpp similarity index 100% rename from circuits/src/aztec3/oracle/oracle.hpp rename to circuits/cpp/src/aztec3/oracle/oracle.hpp From 6cf29a54b0d04fb665829bbb6f120166528a751c Mon Sep 17 00:00:00 2001 From: Suyash Bagad Date: Wed, 8 Mar 2023 14:51:14 +0530 Subject: [PATCH 065/166] Update bb (to Phated's latest barretenberg master with large cmake infra update) (#37) * update bb * updating cmake infra to work with and use phated's latest barretenberg master * add CMAKE_BBERG_PRESET cacheVariable that is used to set barretenberg's preset from this project. Fix gitignores * fix bootstrap bug, fix externalproject for Ninja by adding BUILD_BYPRODUCTS * use wasi-sdk in barretenberg submodule so that presets both point there. make sure WASM is set in cmake before doing * fix wasi path in dockerfiles * fix cpp path in scripts * fix wasm dockerfiles and run_tests scripts for new cpp path and srs script paths --------- Co-authored-by: dbanks12 --- circuits/.gitignore | 14 +- circuits/cpp/.gitignore | 6 + circuits/cpp/CMakeLists.txt | 111 ++++++++- circuits/cpp/CMakePresets.json | 230 ++++++++++++++++++ circuits/cpp/barretenberg | 2 +- circuits/cpp/bootstrap.sh | 57 +++-- circuits/cpp/cmake/barretenberg.cmake | 22 +- circuits/cpp/cmake/benchmark.cmake | 15 +- circuits/cpp/cmake/gtest.cmake | 57 +++-- circuits/cpp/cmake/module.cmake | 63 +++-- circuits/cpp/cmake/toolchain.cmake | 10 - .../cpp/cmake/toolchains/aarch64-darwin.cmake | 2 + .../toolchains/aarch64-linux-clang.cmake | 6 - .../cpp/cmake/toolchains/aarch64-linux.cmake | 2 + .../cmake/toolchains/arm-apple-clang.cmake | 4 - .../cmake/toolchains/arm64-linux-gcc.cmake | 21 -- .../cmake/toolchains/i386-linux-clang.cmake | 13 - .../cpp/cmake/toolchains/i386-linux.cmake | 7 + .../cmake/toolchains/wasm-linux-clang.cmake | 38 --- .../cpp/cmake/toolchains/wasm32-wasi.cmake | 3 + .../cmake/toolchains/x86_64-apple-clang.cmake | 3 - .../cpp/cmake/toolchains/x86_64-darwin.cmake | 2 + .../cmake/toolchains/x86_64-linux-clang.cmake | 9 - .../cmake/toolchains/x86_64-linux-gcc.cmake | 2 - .../cmake/toolchains/x86_64-linux-gcc10.cmake | 2 - .../cpp/cmake/toolchains/x86_64-linux.cmake | 2 + .../dockerfiles/Dockerfile.arm64-linux-gcc | 5 +- .../cpp/dockerfiles/Dockerfile.crosstool-ng | 2 + .../dockerfiles/Dockerfile.crosstool-ng-arm64 | 2 + .../dockerfiles/Dockerfile.wasm-linux-clang | 11 +- .../Dockerfile.wasm-linux-clang-assert | 13 +- .../dockerfiles/Dockerfile.x86_64-linux-clang | 7 +- .../Dockerfile.x86_64-linux-clang-assert | 9 +- .../dockerfiles/Dockerfile.x86_64-linux-gcc | 7 +- circuits/cpp/scripts/run_tests | 7 +- circuits/cpp/src/CMakeLists.txt | 10 +- .../abis/public_circuit_public_inputs.hpp | 18 +- 37 files changed, 531 insertions(+), 263 deletions(-) create mode 100644 circuits/cpp/.gitignore create mode 100644 circuits/cpp/CMakePresets.json delete mode 100644 circuits/cpp/cmake/toolchain.cmake create mode 100644 circuits/cpp/cmake/toolchains/aarch64-darwin.cmake delete mode 100644 circuits/cpp/cmake/toolchains/aarch64-linux-clang.cmake create mode 100644 circuits/cpp/cmake/toolchains/aarch64-linux.cmake delete mode 100644 circuits/cpp/cmake/toolchains/arm-apple-clang.cmake delete mode 100644 circuits/cpp/cmake/toolchains/arm64-linux-gcc.cmake delete mode 100644 circuits/cpp/cmake/toolchains/i386-linux-clang.cmake create mode 100644 circuits/cpp/cmake/toolchains/i386-linux.cmake delete mode 100644 circuits/cpp/cmake/toolchains/wasm-linux-clang.cmake create mode 100644 circuits/cpp/cmake/toolchains/wasm32-wasi.cmake delete mode 100644 circuits/cpp/cmake/toolchains/x86_64-apple-clang.cmake create mode 100644 circuits/cpp/cmake/toolchains/x86_64-darwin.cmake delete mode 100644 circuits/cpp/cmake/toolchains/x86_64-linux-clang.cmake delete mode 100644 circuits/cpp/cmake/toolchains/x86_64-linux-gcc.cmake delete mode 100644 circuits/cpp/cmake/toolchains/x86_64-linux-gcc10.cmake create mode 100644 circuits/cpp/cmake/toolchains/x86_64-linux.cmake diff --git a/circuits/.gitignore b/circuits/.gitignore index cedb78bc7ec..600d2d33bad 100644 --- a/circuits/.gitignore +++ b/circuits/.gitignore @@ -1,13 +1 @@ -.cache/ -.vscode/ -build/ -build-wasm/ -src/wasi-sdk-* -src/aztec/proof_system/proving_key/fixtures -src/aztec/rollup/proofs/*/fixtures -srs_db/ignition/transcript* -srs_db/lagrange -srs_db/coset_lagrange -srs_db/modified_lagrange -# to be unignored when we agree on clang-tidy rules -.clangd \ No newline at end of file +.vscode \ No newline at end of file diff --git a/circuits/cpp/.gitignore b/circuits/cpp/.gitignore new file mode 100644 index 00000000000..179de6ae623 --- /dev/null +++ b/circuits/cpp/.gitignore @@ -0,0 +1,6 @@ +.cache/ +build*/ +src/wasi-sdk-* +CMakeUserPresets.json +# to be unignored when we agree on clang-tidy rules +.clangd \ No newline at end of file diff --git a/circuits/cpp/CMakeLists.txt b/circuits/cpp/CMakeLists.txt index 4930ba0321a..454cdf8c44c 100644 --- a/circuits/cpp/CMakeLists.txt +++ b/circuits/cpp/CMakeLists.txt @@ -1,7 +1,7 @@ -# aztec-connect-cpp +# aztec3-circuits # copyright 2019 Spilsbury Holdings Ltd -cmake_minimum_required(VERSION 3.16) +cmake_minimum_required(VERSION 3.24) # Get the full path to barretenberg. This is helpful because the required # relative path changes based on where in cmake the path is used. @@ -10,33 +10,66 @@ cmake_minimum_required(VERSION 3.16) get_filename_component(BBERG_DIR ../barretenberg/cpp REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") -include(cmake/toolchain.cmake) - -set(PROJECT_VERSION 0.1.0) -project(Aztec3Circuits +project( + Aztec3Circuits DESCRIPTION "Project containing Aztec3 Circuits Infrastucture in C++." - LANGUAGES CXX C) - -# include barretenberg as ExternalProject -include(cmake/barretenberg.cmake) + VERSION 0.1.0 + LANGUAGES CXX C +) option(DISABLE_ASM "Disable custom assembly" OFF) option(DISABLE_ADX "Disable ADX assembly variant" OFF) option(MULTITHREADING "Enable multi-threading" ON) option(TESTING "Build tests" ON) +option(BENCHMARKS "Build benchmarks" ON) +option(FUZZING "Build fuzzing harnesses" OFF) +option(DISABLE_TBB "Intel Thread Building Blocks" ON) +option(COVERAGE "Enable collecting coverage from tests" OFF) +option(ENABLE_HEAVY_TESTS "Enable heavy tests when collecting coverage" OFF) -if(ARM) +if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64" OR CMAKE_SYSTEM_PROCESSOR MATCHES "arm64") message(STATUS "Compiling for ARM.") + set(ARM ON) set(DISABLE_ASM ON) set(DISABLE_ADX ON) set(RUN_HAVE_STD_REGEX 0) set(RUN_HAVE_POSIX_REGEX 0) + set(DISABLE_TBB 0) +endif() + +if(FUZZING) + add_definitions(-DFUZZING=1) + + if(DISABLE_CUSTOM_MUTATORS) + add_definitions(-DDISABLE_CUSTOM_MUTATORS=1) + endif() + + set(SANITIZER_OPTIONS "") + + if(ADDRESS_SANITIZER) + set(SANITIZER_OPTIONS ${SANITIZER_OPTIONS} -fsanitize=address) + endif() + + if(UNDEFINED_BEHAVIOUR_SANITIZER) + set(SANITIZER_OPTIONS ${SANITIZER_OPTIONS} -fsanitize=undefined -fno-sanitize=alignment) + endif() + + add_compile_options(-fsanitize=fuzzer-no-link ${SANITIZER_OPTIONS}) + + set(WASM OFF) + set(BENCHMARKS OFF) + set(MULTITHREADING OFF) + set(TESTING OFF) endif() -if(WASM) +if(CMAKE_SYSTEM_PROCESSOR MATCHES "wasm32") message(STATUS "Compiling for WebAssembly.") + set(WASM ON) set(DISABLE_ASM ON) set(MULTITHREADING OFF) + set(BENCHMARKS OFF) + set(DISABLE_TBB 1) + add_compile_definitions(_WASI_EMULATED_PROCESS_CLOCKS=1) endif() set(CMAKE_C_STANDARD 11) @@ -45,10 +78,62 @@ set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED TRUE) set(CMAKE_CXX_EXTENSIONS ON) +if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "10") + message(WARNING "Clang <10 is not supported") + endif() +elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU") + if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "10") + message(WARNING "GCC <10 is not supported") + endif() +else() + message(WARNING "Unsuported compiler, use Clang >10 or GCC >10") +endif() + +if(COVERAGE) + + # We've only set up LLVM coverage + if(NOT(CMAKE_CXX_COMPILER_ID MATCHES "Clang")) + message(FATAL_ERROR "Creating coverage is only available for clang") + endif() + + # Get major clang version + string(REPLACE "." ";" VERSION_LIST ${CMAKE_CXX_COMPILER_VERSION}) + list(GET VERSION_LIST 0 CLANG_VERSION_MAJOR) + + # Find llvm-profdata + set(PROFDATA_EXECUTABLE_NAME "llvm-profdata-${CLANG_VERSION_MAJOR}") + find_program(PROFDATA_EXECUTABLE ${PROFDATA_EXECUTABLE_NAME}) + if(PROFDATA_EXECUTABLE MATCHES "NOTFOUND") + message(FATAL_ERROR "Couldn't find ${PROFDATA_EXECUTABLE_NAME}") + endif() + + # Find llvm-cov + set(COV_EXECUTABLE_NAME "llvm-cov-${CLANG_VERSION_MAJOR}") + find_program(COV_EXECUTABLE ${COV_EXECUTABLE_NAME}) + if(COV_EXECUTABLE MATCHES "NOTFOUND") + message(FATAL_ERROR "Couldn't find ${COV_EXECUTABLE_NAME}") + endif() + + # Add profiling compile options and disable optimisations + add_compile_options(-fprofile-instr-generate -fcoverage-mapping -O0) + + # Add a custom target for creating the report + add_custom_target(create_full_coverage_report + COMMAND "${CMAKE_SOURCE_DIR}/scripts/collect_coverage_information.sh" ${PROFDATA_EXECUTABLE} ${COV_EXECUTABLE} + VERBATIM + ) +endif() + +# include barretenberg as ExternalProject +# (needs WASM to be set already) +include(cmake/barretenberg.cmake) + include(cmake/build.cmake) +include(GNUInstallDirs) include(cmake/arch.cmake) include(cmake/threading.cmake) include(cmake/gtest.cmake) +include(cmake/benchmark.cmake) include(cmake/module.cmake) - add_subdirectory(src) \ No newline at end of file diff --git a/circuits/cpp/CMakePresets.json b/circuits/cpp/CMakePresets.json new file mode 100644 index 00000000000..eb08c79bbec --- /dev/null +++ b/circuits/cpp/CMakePresets.json @@ -0,0 +1,230 @@ +{ + "version": 5, + "cmakeMinimumRequired": { + "major": 3, + "minor": 24, + "patch": 0 + }, + "configurePresets": [ + { + "name": "default", + "displayName": "Build with Clang", + "description": "Build with globally installed Clang", + "binaryDir": "build", + "generator": "Ninja", + "environment": { + "CC": "clang", + "CXX": "clang++", + "CMAKE_EXPORT_COMPILE_COMMANDS": "ON" + }, + "cacheVariables": { + "CMAKE_BBERG_PRESET": "default" + } + }, + { + "name": "homebrew", + "displayName": "Homebrew + Clang", + "description": "Build with Clang installed via Homebrew", + "inherits": "default", + "environment": { + "CC": "$env{BREW_PREFIX}/opt/llvm/bin/clang", + "CXX": "$env{BREW_PREFIX}/opt/llvm/bin/clang++", + "LDFLAGS": "-L$env{BREW_PREFIX}/opt/libomp/lib", + "CPPFLAGS": "-I$env{BREW_PREFIX}/opt/libomp/include" + }, + "cacheVariables": { + "CMAKE_BBERG_PRESET": "homebrew" + } + }, + { + "name": "clang15", + "displayName": "Build with Clang-15", + "description": "Build with globally installed Clang-15", + "inherits": "default", + "environment": { + "CC": "clang-15", + "CXX": "clang++-15" + }, + "cacheVariables": { + "CMAKE_BBERG_PRESET": "clang15" + } + }, + { + "name": "gcc", + "displayName": "Build with GCC", + "description": "Build with globally installed GCC", + "inherits": "default", + "environment": { + "CC": "gcc", + "CXX": "g++" + }, + "cacheVariables": { + "CMAKE_BBERG_PRESET": "gcc" + } + }, + { + "name": "gcc10", + "displayName": "Build with GCC-10", + "description": "Build with globally installed GCC-10", + "inherits": "default", + "environment": { + "CC": "gcc-10", + "CXX": "g++-10" + }, + "cacheVariables": { + "CMAKE_BBERG_PRESET": "gcc10" + } + }, + { + "name": "bench", + "displayName": "Build benchmarks", + "description": "Build default preset but with a special benchmark directory", + "inherits": "default", + "binaryDir": "build-bench" + }, + { + "name": "fuzzing", + "displayName": "Build with fuzzing", + "description": "Build default preset but with fuzzing enabled", + "inherits": "default", + "binaryDir": "build-fuzzing", + "cacheVariables": { + "FUZZING": "ON", + "CMAKE_BBERG_PRESET": "fuzzing" + } + }, + { + "name": "coverage", + "displayName": "Build with coverage", + "description": "Build default preset but with coverage enabled", + "inherits": "default", + "binaryDir": "build-coverage", + "cacheVariables": { + "COVERAGE": "ON", + "CMAKE_BUILD_TYPE": "Debug", + "CMAKE_BBERG_PRESET": "coverage" + } + }, + { + "name": "wasm", + "displayName": "Build for WASM", + "description": "Build with a specific wasm-sdk to create wasm", + "binaryDir": "build-wasm", + "toolchainFile": "cmake/toolchains/wasm32-wasi.cmake", + "environment": { + "WASI_SDK_PREFIX": "${sourceDir}/barretenberg/cpp/src/wasi-sdk-12.0", + "CC": "$env{WASI_SDK_PREFIX}/bin/clang", + "CXX": "$env{WASI_SDK_PREFIX}/bin/clang++", + "AR": "$env{WASI_SDK_PREFIX}/bin/llvm-ar", + "RANLIB": "$env{WASI_SDK_PREFIX}/bin/llvm-ranlib" + }, + "cacheVariables": { + "CMAKE_SYSROOT": "$env{WASI_SDK_PREFIX}/share/wasi-sysroot", + "CMAKE_STAGING_PREFIX": "$env{WASI_SDK_PREFIX}/share/wasi-sysroot", + "CMAKE_FIND_ROOT_PATH_MODE_PROGRAM": "NEVER", + "CMAKE_FIND_ROOT_PATH_MODE_LIBRARY": "ONLY", + "CMAKE_FIND_ROOT_PATH_MODE_INCLUDE": "ONLY", + "CMAKE_FIND_ROOT_PATH_MODE_PACKAGE": "ONLY", + "CMAKE_C_COMPILER_WORKS": "ON", + "CMAKE_CXX_COMPILER_WORKS": "ON", + "CMAKE_BBERG_PRESET": "wasm" + } + } + ], + "buildPresets": [ + { + "name": "default", + "configurePreset": "default", + "inheritConfigureEnvironment": true, + "jobs": 0 + }, + { + "name": "homebrew", + "inherits": "default", + "configurePreset": "homebrew" + }, + { + "name": "clang15", + "inherits": "default", + "configurePreset": "clang15" + }, + { + "name": "gcc", + "inherits": "default", + "configurePreset": "gcc" + }, + { + "name": "gcc10", + "inherits": "default", + "configurePreset": "gcc10" + }, + { + "name": "bench", + "inherits": "default", + "configurePreset": "bench" + }, + { + "name": "fuzzing", + "inherits": "default", + "configurePreset": "fuzzing" + }, + { + "name": "coverage", + "inherits": "default", + "configurePreset": "coverage" + }, + { + "name": "wasm", + "configurePreset": "wasm", + "inheritConfigureEnvironment": true, + "jobs": 0 + } + ], + "testPresets": [ + { + "name": "default", + "configurePreset": "default", + "inheritConfigureEnvironment": true + }, + { + "name": "homebrew", + "inherits": "default", + "configurePreset": "homebrew" + }, + { + "name": "clang15", + "inherits": "default", + "configurePreset": "clang15" + }, + { + "name": "gcc", + "inherits": "default", + "configurePreset": "gcc" + }, + { + "name": "gcc10", + "inherits": "default", + "configurePreset": "gcc10" + }, + { + "name": "bench", + "inherits": "default", + "configurePreset": "bench" + }, + { + "name": "fuzzing", + "inherits": "default", + "configurePreset": "fuzzing" + }, + { + "name": "coverage", + "inherits": "default", + "configurePreset": "coverage" + }, + { + "name": "wasm", + "configurePreset": "wasm", + "inheritConfigureEnvironment": true + } + ] +} \ No newline at end of file diff --git a/circuits/cpp/barretenberg b/circuits/cpp/barretenberg index 74c66a79515..a67b5aa243a 160000 --- a/circuits/cpp/barretenberg +++ b/circuits/cpp/barretenberg @@ -1 +1 @@ -Subproject commit 74c66a795151b8f4f94576511f7ec0de4d596f9d +Subproject commit a67b5aa243ad55b364dd4976766613af337447bc diff --git a/circuits/cpp/bootstrap.sh b/circuits/cpp/bootstrap.sh index b2084f13ebb..7d854e84efc 100755 --- a/circuits/cpp/bootstrap.sh +++ b/circuits/cpp/bootstrap.sh @@ -1,5 +1,5 @@ #!/bin/bash -set -e +set -eu # Update the submodule git submodule update --init --recursive @@ -7,16 +7,15 @@ git submodule update --init --recursive # Clean. rm -rf ./build rm -rf ./build-wasm -rm -rf ./src/wasi-sdk-* # Clean barretenberg. -rm -rf ../barretenberg/cpp/build -rm -rf ../barretenberg/cpp/build-wasm -rm -rf ../barretenberg/cpp/src/wasi-sdk-* +rm -rf ./barretenberg/cpp/build +rm -rf ./barretenberg/cpp/build-wasm +rm -rf ./barretenberg/cpp/src/wasi-sdk-* # Install formatting git hook. HOOKS_DIR=$(git rev-parse --git-path hooks) -echo "cd \$(git rev-parse --show-toplevel) && ./format.sh staged" > $HOOKS_DIR/pre-commit +echo "cd \$(git rev-parse --show-toplevel)/cpp && ./format.sh staged" > $HOOKS_DIR/pre-commit chmod +x $HOOKS_DIR/pre-commit # Determine system. @@ -33,37 +32,41 @@ fi (cd barretenberg/cpp/srs_db && ./download_ignition.sh 3) # Pick native toolchain file. +ARCH=$(uname -m) if [ "$OS" == "macos" ]; then + if [ "$(which brew)" != "" ]; then export BREW_PREFIX=$(brew --prefix) + # Ensure we have toolchain. if [ ! "$?" -eq 0 ] || [ ! -f "$BREW_PREFIX/opt/llvm/bin/clang++" ]; then - echo "Default clang not sufficient. Install homebrew, and then: brew install llvm libomp clang-format" - exit 1 - fi - ARCH=$(uname -m) - if [ "$ARCH" = "arm64" ]; then - TOOLCHAIN=arm-apple-clang - else - TOOLCHAIN=x86_64-apple-clang + echo "Default clang not sufficient. Install homebrew, and then: brew install llvm libomp clang-format" + exit 1 fi + + PRESET=homebrew + else + PRESET=default + fi else - TOOLCHAIN=x86_64-linux-clang + if [ "$(which clang++-15)" != "" ]; then + PRESET=clang15 + else + PRESET=default + fi fi +echo "#################################" +echo "# Building with preset: $PRESET" +echo "# When running cmake directly, remember to use: --build --preset $PRESET" +echo "#################################" + # Build native. -mkdir -p build && cd build -cmake -DCMAKE_BUILD_TYPE=RelWithAssert -DTOOLCHAIN=$TOOLCHAIN .. -cmake --build . --parallel ${@/#/--target } -cd .. +cmake --preset $PRESET -DCMAKE_BUILD_TYPE=RelWithAssert +cmake --build --preset $PRESET ${@/#/--target } # Install the webassembly toolchain. -WASI_VERSION=12 -cd ./src -curl -s -L https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-$WASI_VERSION/wasi-sdk-$WASI_VERSION.0-$OS.tar.gz | tar zxfv - -cd .. +(cd ./barretenberg/cpp/src && export WASI_VERSION=12 && curl -s -L https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-$WASI_VERSION/wasi-sdk-$WASI_VERSION.0-$OS.tar.gz | tar zxfv -) # Build WASM. -mkdir -p build-wasm && cd build-wasm -cmake -DTOOLCHAIN=wasm-linux-clang .. -cmake --build . --parallel # --target aztec3.wasm -cd .. \ No newline at end of file +cmake --preset wasm +cmake --build --preset wasm diff --git a/circuits/cpp/cmake/barretenberg.cmake b/circuits/cpp/cmake/barretenberg.cmake index 70854c4458e..12cb0140181 100644 --- a/circuits/cpp/cmake/barretenberg.cmake +++ b/circuits/cpp/cmake/barretenberg.cmake @@ -9,25 +9,17 @@ include(ExternalProject) +# Reference barretenberg artifacts (like library archives) via this dir: if (WASM) set(BBERG_BUILD_DIR ${BBERG_DIR}/build-wasm) else() set(BBERG_BUILD_DIR ${BBERG_DIR}/build) endif() -# If the OpenMP library is included via this option, propogate to ExternalProject configure -if (OpenMP_omp_LIBRARY) - set(LIB_OMP_OPTION -DOpenMP_omp_LIBRARY=${OpenMP_omp_LIBRARY}) +if(NOT CMAKE_BBERG_PRESET) + set(CMAKE_BBERG_PRESET default) endif() -# Make sure barretenberg doesn't set its own WASI_SDK_PREFIX -if (WASI_SDK_PREFIX) - set(WASI_SDK_OPTION -DWASI_SDK_PREFIX=${WASI_SDK_PREFIX}) -endif() - -# cmake configure cli args for ExternalProject -set(BBERG_CONFIGURE_ARGS -DTOOLCHAIN=${TOOLCHAIN} ${WASI_SDK_OPTION} ${LIB_OMP_OPTION} -DCI=${CI}) - # Naming: Project: Barretenberg, Libraries: barretenberg, env # Need BUILD_ALWAYS to ensure that barretenberg is automatically reconfigured when its CMake files change # "Enabling this option forces the build step to always be run. This can be the easiest way to robustly @@ -35,12 +27,14 @@ set(BBERG_CONFIGURE_ARGS -DTOOLCHAIN=${TOOLCHAIN} ${WASI_SDK_OPTION} ${LIB_OMP_O # default success timestamp-based method." - https://cmake.org/cmake/help/latest/module/ExternalProject.html ExternalProject_Add(Barretenberg SOURCE_DIR ${BBERG_DIR} - BINARY_DIR ${BBERG_BUILD_DIR} # build directory + BUILD_IN_SOURCE TRUE BUILD_ALWAYS TRUE UPDATE_COMMAND "" INSTALL_COMMAND "" - CONFIGURE_COMMAND ${CMAKE_COMMAND} ${BBERG_CONFIGURE_ARGS} .. - BUILD_COMMAND ${CMAKE_COMMAND} --build . --parallel --target barretenberg --target env) + CONFIGURE_COMMAND ${CMAKE_COMMAND} --preset ${CMAKE_BBERG_PRESET} + BUILD_COMMAND ${CMAKE_COMMAND} --build --preset ${CMAKE_BBERG_PRESET} --target barretenberg --target env + # byproducts needed by ninja generator (not needed by make) + BUILD_BYPRODUCTS ${BBERG_BUILD_DIR}/lib/libbarretenberg.a ${BBERG_BUILD_DIR}/lib/libenv.a) include_directories(${BBERG_DIR}/src/aztec) diff --git a/circuits/cpp/cmake/benchmark.cmake b/circuits/cpp/cmake/benchmark.cmake index abcdb7875e4..c8f90548d66 100644 --- a/circuits/cpp/cmake/benchmark.cmake +++ b/circuits/cpp/cmake/benchmark.cmake @@ -9,12 +9,17 @@ if(BENCHMARKS) benchmark GIT_REPOSITORY https://github.com/google/benchmark GIT_TAG v1.7.1 + FIND_PACKAGE_ARGS ) - FetchContent_GetProperties(benchmark) - if(NOT benchmark_POPULATED) - fetchcontent_populate(benchmark) - set(BENCHMARK_ENABLE_TESTING OFF CACHE BOOL "Benchmark tests off") - add_subdirectory(${benchmark_SOURCE_DIR} ${benchmark_BINARY_DIR} EXCLUDE_FROM_ALL) + set(BENCHMARK_ENABLE_TESTING OFF CACHE BOOL "Benchmark tests off") + set(BENCHMARK_ENABLE_INSTALL OFF CACHE BOOL "Benchmark installation off") + + FetchContent_MakeAvailable(benchmark) + if(NOT benchmark_FOUND) + # FetchContent_MakeAvailable calls FetchContent_Populate if `find_package` is unsuccessful + # so these variables will be available if we reach this case + set_property(DIRECTORY ${benchmark_SOURCE_DIR} PROPERTY EXCLUDE_FROM_ALL) + set_property(DIRECTORY ${benchmark_BINARY_DIR} PROPERTY EXCLUDE_FROM_ALL) endif() endif() diff --git a/circuits/cpp/cmake/gtest.cmake b/circuits/cpp/cmake/gtest.cmake index 96e88741e9e..e86bf49756e 100644 --- a/circuits/cpp/cmake/gtest.cmake +++ b/circuits/cpp/cmake/gtest.cmake @@ -3,38 +3,49 @@ if(TESTING) include(FetchContent) FetchContent_Declare( - googletest + GTest GIT_REPOSITORY https://github.com/google/googletest.git # Version 1.12.1 is not compatible with WASI-SDK 12 - GIT_TAG release-1.10.0 + GIT_TAG release-1.10.0 + FIND_PACKAGE_ARGS ) - FetchContent_GetProperties(googletest) - if(NOT googletest_POPULATED) - FetchContent_Populate(googletest) - add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR} EXCLUDE_FROM_ALL) - endif() + set(BUILD_GMOCK OFF CACHE BOOL "Build with gMock disabled") + set(INSTALL_GTEST OFF CACHE BOOL "gTest installation disabled") - # Disable all warning when compiling gtest - target_compile_options( - gtest - PRIVATE - -w - ) + FetchContent_MakeAvailable(GTest) - if(WASM) - target_compile_definitions( + if (NOT GTest_FOUND) + # FetchContent_MakeAvailable calls FetchContent_Populate if `find_package` is unsuccessful + # so these variables will be available if we reach this case + set_property(DIRECTORY ${gtest_SOURCE_DIR} PROPERTY EXCLUDE_FROM_ALL) + set_property(DIRECTORY ${gtest_BINARY_DIR} PROPERTY EXCLUDE_FROM_ALL) + + # Disable all warning when compiling gtest + target_compile_options( gtest PRIVATE - -DGTEST_HAS_EXCEPTIONS=0 - -DGTEST_HAS_STREAM_REDIRECTION=0) - endif() + -w + ) - mark_as_advanced( - BUILD_GMOCK BUILD_GTEST BUILD_SHARED_LIBS - gmock_build_tests gtest_build_samples gtest_build_tests - gtest_disable_pthreads gtest_force_shared_crt gtest_hide_internal_symbols - ) + if(WASM) + target_compile_definitions( + gtest + PRIVATE + -DGTEST_HAS_EXCEPTIONS=0 + -DGTEST_HAS_STREAM_REDIRECTION=0 + ) + endif() + + mark_as_advanced( + BUILD_GMOCK BUILD_GTEST BUILD_SHARED_LIBS + gmock_build_tests gtest_build_samples gtest_build_tests + gtest_disable_pthreads gtest_force_shared_crt gtest_hide_internal_symbols + ) + + add_library(GTest::gtest ALIAS gtest) + add_library(GTest::gtest_main ALIAS gtest_main) + endif() enable_testing() endif() diff --git a/circuits/cpp/cmake/module.cmake b/circuits/cpp/cmake/module.cmake index c6a156e0e59..788b1127e72 100644 --- a/circuits/cpp/cmake/module.cmake +++ b/circuits/cpp/cmake/module.cmake @@ -14,7 +14,7 @@ function(barretenberg_module MODULE_NAME) file(GLOB_RECURSE SOURCE_FILES *.cpp) - file(GLOB_RECURSE HEADER_FILES *.hpp) + file(GLOB_RECURSE HEADER_FILES *.hpp *.tcc) list(FILTER SOURCE_FILES EXCLUDE REGEX ".*\.(fuzzer|test|bench).cpp$") if(SOURCE_FILES) @@ -54,7 +54,7 @@ function(barretenberg_module MODULE_NAME) target_link_libraries( ${MODULE_NAME}_test_objects PRIVATE - gtest + GTest::gtest env ${TBB_IMPORTED_TARGETS} ) @@ -81,7 +81,8 @@ function(barretenberg_module MODULE_NAME) ) endif() - if(DISABLE_HEAVY_TESTS) + if((COVERAGE AND NOT ENABLE_HEAVY_TESTS) OR (DISABLE_HEAVY_TESTS)) + # Heavy tests take hours when we are using profiling instrumentation target_compile_definitions( ${MODULE_NAME}_test_objects PRIVATE @@ -94,22 +95,56 @@ function(barretenberg_module MODULE_NAME) PRIVATE ${MODULE_LINK_NAME} ${ARGN} - gtest - gtest_main + GTest::gtest + GTest::gtest_main env ${TBB_IMPORTED_TARGETS} ) if(NOT WASM AND NOT CI) - # Currently haven't found a way to easily wrap the calls in wasmtime when run from ctest. - gtest_discover_tests(${MODULE_NAME}_tests WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) + # If collecting coverage data, set profile + # For some reason processor affinity doesn't work, so the developer has to set it manually anyway + if(COVERAGE) + # Profile filename has to be dependent on some process characteristic, because ctest calls all tests individually and the profiles get overwritten + gtest_discover_tests(${MODULE_NAME}_tests + PROPERTIES ENVIRONMENT "LLVM_PROFILE_FILE=${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/profdata/${MODULE_NAME}.%p.profraw" + PROPERTIES PROCESSOR_AFFINITY ON + PROPERTIES PROCESSORS 16 + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) + else() + # Currently haven't found a way to easily wrap the calls in wasmtime when run from ctest. + gtest_discover_tests(${MODULE_NAME}_tests WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) + endif() endif() - add_custom_target( - run_${MODULE_NAME}_tests - COMMAND ${MODULE_NAME}_tests - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - ) + if(COVERAGE) + target_link_options( + ${MODULE_NAME}_tests + PRIVATE + -fprofile-instr-generate -fcoverage-mapping + ) + add_custom_target( + run_${MODULE_NAME}_tests + COMMAND mkdir -p ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/profdata + COMMAND LLVM_PROFILE_FILE=${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/profdata/${MODULE_NAME}.%p.profraw ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${MODULE_NAME}_tests + BYPRODUCTS ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/profdata/${MODULE_NAME}.profraw + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + DEPENDS ${MODULE_NAME}_tests + ) + add_custom_target( + generate_${MODULE_NAME}_tests_coverage + COMMAND ${PROFDATA_EXECUTABLE} merge -sparse ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/profdata/${MODULE_NAME}.profraw -o ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/profdata/${MODULE_NAME}.profdata + DEPENDS ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/profdata/${MODULE_NAME}.profraw + BYPRODUCTS ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/profdata/${MODULE_NAME}.profdata + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + ) + else() + add_custom_target( + run_${MODULE_NAME}_tests + COMMAND ${MODULE_NAME}_tests + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + ) + endif() endif() file(GLOB_RECURSE FUZZERS_SOURCE_FILES *.fuzzer.cpp) @@ -150,7 +185,7 @@ function(barretenberg_module MODULE_NAME) target_link_libraries( ${MODULE_NAME}_bench_objects PRIVATE - benchmark + benchmark::benchmark env ${TBB_IMPORTED_TARGETS} ) @@ -166,7 +201,7 @@ function(barretenberg_module MODULE_NAME) PRIVATE ${MODULE_LINK_NAME} ${ARGN} - benchmark + benchmark::benchmark env ${TBB_IMPORTED_TARGETS} ) diff --git a/circuits/cpp/cmake/toolchain.cmake b/circuits/cpp/cmake/toolchain.cmake deleted file mode 100644 index 4de860fac49..00000000000 --- a/circuits/cpp/cmake/toolchain.cmake +++ /dev/null @@ -1,10 +0,0 @@ -if (CMAKE_C_COMPILER AND CMAKE_CXX_COMPILER) - message(STATUS "Toolchain: manually chosen ${CMAKE_C_COMPILER} and ${CMAKE_CXX_COMPILER}") -else() - if(NOT TOOLCHAIN) - set(TOOLCHAIN "x86_64-linux-clang" CACHE STRING "Build toolchain." FORCE) - endif() - message(STATUS "Toolchain: ${TOOLCHAIN}") - - include("./cmake/toolchains/${TOOLCHAIN}.cmake") -endif() \ No newline at end of file diff --git a/circuits/cpp/cmake/toolchains/aarch64-darwin.cmake b/circuits/cpp/cmake/toolchains/aarch64-darwin.cmake new file mode 100644 index 00000000000..a3b8d52fa72 --- /dev/null +++ b/circuits/cpp/cmake/toolchains/aarch64-darwin.cmake @@ -0,0 +1,2 @@ +set(CMAKE_SYSTEM_NAME Darwin) +set(CMAKE_SYSTEM_PROCESSOR aarch64) diff --git a/circuits/cpp/cmake/toolchains/aarch64-linux-clang.cmake b/circuits/cpp/cmake/toolchains/aarch64-linux-clang.cmake deleted file mode 100644 index e876c0c0385..00000000000 --- a/circuits/cpp/cmake/toolchains/aarch64-linux-clang.cmake +++ /dev/null @@ -1,6 +0,0 @@ -set(ARM ON) -set(CMAKE_SYSTEM_NAME Linux) -set(CMAKE_SYSTEM_PROCESSOR aarch64) - -set(CMAKE_C_COMPILER "clang") -set(CMAKE_CXX_COMPILER "clang++") diff --git a/circuits/cpp/cmake/toolchains/aarch64-linux.cmake b/circuits/cpp/cmake/toolchains/aarch64-linux.cmake new file mode 100644 index 00000000000..d79a26e90fd --- /dev/null +++ b/circuits/cpp/cmake/toolchains/aarch64-linux.cmake @@ -0,0 +1,2 @@ +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR aarch64) diff --git a/circuits/cpp/cmake/toolchains/arm-apple-clang.cmake b/circuits/cpp/cmake/toolchains/arm-apple-clang.cmake deleted file mode 100644 index 1b451ab08d5..00000000000 --- a/circuits/cpp/cmake/toolchains/arm-apple-clang.cmake +++ /dev/null @@ -1,4 +0,0 @@ -set(APPLE ON) -set(ARM ON) -set(CMAKE_CXX_COMPILER "$ENV{BREW_PREFIX}/opt/llvm/bin/clang++") -set(CMAKE_C_COMPILER "$ENV{BREW_PREFIX}/opt/llvm/bin/clang") \ No newline at end of file diff --git a/circuits/cpp/cmake/toolchains/arm64-linux-gcc.cmake b/circuits/cpp/cmake/toolchains/arm64-linux-gcc.cmake deleted file mode 100644 index bc8bd0b8028..00000000000 --- a/circuits/cpp/cmake/toolchains/arm64-linux-gcc.cmake +++ /dev/null @@ -1,21 +0,0 @@ -set(ARM ON) -set(CMAKE_SYSTEM_NAME Linux) -set(CMAKE_SYSTEM_VERSION 1) -set(CMAKE_SYSTEM_PROCESSOR aarch64) - -set(cross_triple "aarch64-unknown-linux-gnu") -set(cross_root /usr/xcc/${cross_triple}) - -set(CMAKE_C_COMPILER $ENV{CC}) -set(CMAKE_CXX_COMPILER $ENV{CXX}) -set(CMAKE_Fortran_COMPILER $ENV{FC}) - -set(CMAKE_CXX_FLAGS "-I ${cross_root}/include/") - -set(CMAKE_FIND_ROOT_PATH ${cross_root} ${cross_root}/${cross_triple}) -set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) -set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH) -set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH) -set(CMAKE_SYSROOT ${cross_root}/${cross_triple}/sysroot) - -set(CMAKE_CROSSCOMPILING_EMULATOR /usr/bin/qemu-aarch64) \ No newline at end of file diff --git a/circuits/cpp/cmake/toolchains/i386-linux-clang.cmake b/circuits/cpp/cmake/toolchains/i386-linux-clang.cmake deleted file mode 100644 index acbdb3d47e1..00000000000 --- a/circuits/cpp/cmake/toolchains/i386-linux-clang.cmake +++ /dev/null @@ -1,13 +0,0 @@ -# Sometimes we need to set compilers manually, for example for fuzzing -if(NOT CMAKE_C_COMPILER) - set(CMAKE_C_COMPILER "clang") -endif() - -if(NOT CMAKE_CXX_COMPILER) - set(CMAKE_CXX_COMPILER "clang++") -endif() - -add_compile_options("-m32") -add_link_options("-m32") -set(MULTITHREADING OFF) -add_definitions(-DDISABLE_SHENANIGANS=1) \ No newline at end of file diff --git a/circuits/cpp/cmake/toolchains/i386-linux.cmake b/circuits/cpp/cmake/toolchains/i386-linux.cmake new file mode 100644 index 00000000000..db424698ee8 --- /dev/null +++ b/circuits/cpp/cmake/toolchains/i386-linux.cmake @@ -0,0 +1,7 @@ +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR i386) + +add_compile_options("-m32") +add_link_options("-m32") +set(MULTITHREADING OFF) +add_definitions(-DDISABLE_SHENANIGANS=1) diff --git a/circuits/cpp/cmake/toolchains/wasm-linux-clang.cmake b/circuits/cpp/cmake/toolchains/wasm-linux-clang.cmake deleted file mode 100644 index d410e8833f1..00000000000 --- a/circuits/cpp/cmake/toolchains/wasm-linux-clang.cmake +++ /dev/null @@ -1,38 +0,0 @@ -# Cmake toolchain description file for the Makefile - -# This is arbitrary, AFAIK, for now. -cmake_minimum_required(VERSION 3.4.0) - -set(WASM ON) -set(CMAKE_SYSTEM_NAME Generic) -set(CMAKE_SYSTEM_VERSION 1) -set(CMAKE_SYSTEM_PROCESSOR wasm32) -set(triple wasm32-wasi) - -if (NOT WASI_SDK_PREFIX) - # can be set by a dependent project - set(WASI_SDK_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/src/wasi-sdk-12.0") -endif() -set(CMAKE_C_COMPILER ${WASI_SDK_PREFIX}/bin/clang) -set(CMAKE_CXX_COMPILER ${WASI_SDK_PREFIX}/bin/clang++) -set(CMAKE_AR ${WASI_SDK_PREFIX}/bin/llvm-ar CACHE STRING "wasi-sdk build") -set(CMAKE_RANLIB ${WASI_SDK_PREFIX}/bin/llvm-ranlib CACHE STRING "wasi-sdk build") -set(CMAKE_C_COMPILER_TARGET ${triple} CACHE STRING "wasi-sdk build") -set(CMAKE_CXX_COMPILER_TARGET ${triple} CACHE STRING "wasi-sdk build") -#set(CMAKE_EXE_LINKER_FLAGS "-Wl,--no-threads" CACHE STRING "wasi-sdk build") - -set(CMAKE_SYSROOT ${WASI_SDK_PREFIX}/share/wasi-sysroot CACHE STRING "wasi-sdk build") -set(CMAKE_STAGING_PREFIX ${WASI_SDK_PREFIX}/share/wasi-sysroot CACHE STRING "wasi-sdk build") - -# Don't look in the sysroot for executables to run during the build -set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) -# Only look in the sysroot (not in the host paths) for the rest -set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) -set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) -set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) - -# Some other hacks -set(CMAKE_C_COMPILER_WORKS ON) -set(CMAKE_CXX_COMPILER_WORKS ON) - -add_definitions(-D_WASI_EMULATED_PROCESS_CLOCKS=1) \ No newline at end of file diff --git a/circuits/cpp/cmake/toolchains/wasm32-wasi.cmake b/circuits/cpp/cmake/toolchains/wasm32-wasi.cmake new file mode 100644 index 00000000000..17e19376ed8 --- /dev/null +++ b/circuits/cpp/cmake/toolchains/wasm32-wasi.cmake @@ -0,0 +1,3 @@ +set(CMAKE_SYSTEM_NAME Generic) +set(CMAKE_SYSTEM_VERSION 1) +set(CMAKE_SYSTEM_PROCESSOR wasm32) diff --git a/circuits/cpp/cmake/toolchains/x86_64-apple-clang.cmake b/circuits/cpp/cmake/toolchains/x86_64-apple-clang.cmake deleted file mode 100644 index 35440991b94..00000000000 --- a/circuits/cpp/cmake/toolchains/x86_64-apple-clang.cmake +++ /dev/null @@ -1,3 +0,0 @@ -set(APPLE ON) -set(CMAKE_CXX_COMPILER "$ENV{BREW_PREFIX}/opt/llvm/bin/clang++") -set(CMAKE_C_COMPILER "$ENV{BREW_PREFIX}/opt/llvm/bin/clang") \ No newline at end of file diff --git a/circuits/cpp/cmake/toolchains/x86_64-darwin.cmake b/circuits/cpp/cmake/toolchains/x86_64-darwin.cmake new file mode 100644 index 00000000000..0aa93407fbd --- /dev/null +++ b/circuits/cpp/cmake/toolchains/x86_64-darwin.cmake @@ -0,0 +1,2 @@ +set(CMAKE_SYSTEM_NAME Darwin) +set(CMAKE_SYSTEM_PROCESSOR x86_64) diff --git a/circuits/cpp/cmake/toolchains/x86_64-linux-clang.cmake b/circuits/cpp/cmake/toolchains/x86_64-linux-clang.cmake deleted file mode 100644 index 529afc02a49..00000000000 --- a/circuits/cpp/cmake/toolchains/x86_64-linux-clang.cmake +++ /dev/null @@ -1,9 +0,0 @@ -# Specifically use clang 15 binaries if available. Otherwise fallback on default version. -find_program(CLANGXX_15 "clang++-15") -if (CLANGXX_15) - set(CMAKE_C_COMPILER "clang-15") - set(CMAKE_CXX_COMPILER "clang++-15") -else() - set(CMAKE_C_COMPILER "clang") - set(CMAKE_CXX_COMPILER "clang++") -endif() \ No newline at end of file diff --git a/circuits/cpp/cmake/toolchains/x86_64-linux-gcc.cmake b/circuits/cpp/cmake/toolchains/x86_64-linux-gcc.cmake deleted file mode 100644 index d1b2790e887..00000000000 --- a/circuits/cpp/cmake/toolchains/x86_64-linux-gcc.cmake +++ /dev/null @@ -1,2 +0,0 @@ -set(CMAKE_C_COMPILER "gcc") -set(CMAKE_CXX_COMPILER "g++") \ No newline at end of file diff --git a/circuits/cpp/cmake/toolchains/x86_64-linux-gcc10.cmake b/circuits/cpp/cmake/toolchains/x86_64-linux-gcc10.cmake deleted file mode 100644 index 8ce971f493f..00000000000 --- a/circuits/cpp/cmake/toolchains/x86_64-linux-gcc10.cmake +++ /dev/null @@ -1,2 +0,0 @@ -set(CMAKE_C_COMPILER "gcc-10") -set(CMAKE_CXX_COMPILER "g++-10") \ No newline at end of file diff --git a/circuits/cpp/cmake/toolchains/x86_64-linux.cmake b/circuits/cpp/cmake/toolchains/x86_64-linux.cmake new file mode 100644 index 00000000000..69c1e6d234a --- /dev/null +++ b/circuits/cpp/cmake/toolchains/x86_64-linux.cmake @@ -0,0 +1,2 @@ +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR x86_64) diff --git a/circuits/cpp/dockerfiles/Dockerfile.arm64-linux-gcc b/circuits/cpp/dockerfiles/Dockerfile.arm64-linux-gcc index c2a508f1698..0b1c7a338d0 100644 --- a/circuits/cpp/dockerfiles/Dockerfile.arm64-linux-gcc +++ b/circuits/cpp/dockerfiles/Dockerfile.arm64-linux-gcc @@ -1,6 +1,7 @@ +# Unused & not maintained. This probably won't work without changes. FROM aztecprotocol/crosstool-ng-arm64:latest -WORKDIR /usr/src/aztec3-circuits +WORKDIR /usr/src/aztec3-circuits/cpp COPY . . -RUN mkdir build && cd build && cmake -DTOOLCHAIN=arm64-linux-gcc .. && cmake --build . --parallel +RUN cmake --toolchain ./cmake/toolchains/aarch64-linux.cmake --preset gcc && cmake --build --preset gcc RUN cd build && for test in ./bin/*_tests; do qemu-aarch64 $test; done ENTRYPOINT /bin/bash \ No newline at end of file diff --git a/circuits/cpp/dockerfiles/Dockerfile.crosstool-ng b/circuits/cpp/dockerfiles/Dockerfile.crosstool-ng index 4fa18b30c4d..a6346d3fd68 100644 --- a/circuits/cpp/dockerfiles/Dockerfile.crosstool-ng +++ b/circuits/cpp/dockerfiles/Dockerfile.crosstool-ng @@ -1,3 +1,5 @@ +# Unused & not maintained. This probably won't work without changes. + FROM ubuntu:latest RUN apt-get update && apt-get install -y autoconf flex texinfo unzip help2man file gawk libtool-bin ncurses-dev bison python-dev diff --git a/circuits/cpp/dockerfiles/Dockerfile.crosstool-ng-arm64 b/circuits/cpp/dockerfiles/Dockerfile.crosstool-ng-arm64 index ed60507121b..58f0402940d 100644 --- a/circuits/cpp/dockerfiles/Dockerfile.crosstool-ng-arm64 +++ b/circuits/cpp/dockerfiles/Dockerfile.crosstool-ng-arm64 @@ -1,3 +1,5 @@ +# Unused & not maintained. This probably won't work without changes. + FROM aztecprotocol/crosstool-ng:1.24.0 # Build toolchain. diff --git a/circuits/cpp/dockerfiles/Dockerfile.wasm-linux-clang b/circuits/cpp/dockerfiles/Dockerfile.wasm-linux-clang index d4acbe4a283..51037fadd4b 100644 --- a/circuits/cpp/dockerfiles/Dockerfile.wasm-linux-clang +++ b/circuits/cpp/dockerfiles/Dockerfile.wasm-linux-clang @@ -1,14 +1,11 @@ FROM ubuntu:kinetic AS builder RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y build-essential wget git libssl-dev cmake curl binaryen -RUN curl https://wasmtime.dev/install.sh -sSf | bash /dev/stdin --version v3.0.1 -WORKDIR /usr/src/aztec3-circuits/src +WORKDIR /usr/src/aztec3-circuits/cpp/barretenberg/cpp/src RUN curl -s -L https://github.com/CraneStation/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-linux.tar.gz | tar zxfv - -WORKDIR /usr/src/aztec3-circuits +WORKDIR /usr/src/aztec3-circuits/cpp COPY . . -# Build both honk_tests barretenberg.wasm -# This ensures that we aren't using features that would be incompatible with WASM for Honk # TODO Add wasm target when ready: --target aztec3.wasm -RUN mkdir build && cd build && cmake -DTOOLCHAIN=wasm-linux-clang .. && cmake --build . --parallel +RUN cmake --preset wasm && cmake --build --preset wasm #FROM alpine:3.17 -#COPY --from=builder /usr/src/aztec3-circuits/build/bin/aztec3.wasm /usr/src/aztec3-circuits/build/bin/aztec3.wasm +#COPY --from=builder /usr/src/aztec3-circuits/cpp/build-wasm/bin/aztec3.wasm /usr/src/aztec3-circuits/cpp/build-wasm/bin/aztec3.wasm diff --git a/circuits/cpp/dockerfiles/Dockerfile.wasm-linux-clang-assert b/circuits/cpp/dockerfiles/Dockerfile.wasm-linux-clang-assert index 24e3cfd8833..917c467482c 100644 --- a/circuits/cpp/dockerfiles/Dockerfile.wasm-linux-clang-assert +++ b/circuits/cpp/dockerfiles/Dockerfile.wasm-linux-clang-assert @@ -1,15 +1,14 @@ FROM ubuntu:kinetic AS builder RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y build-essential git libssl-dev cmake curl binaryen -WORKDIR /usr/src/aztec3-circuits/src +WORKDIR /usr/src/aztec3-circuits/cpp/barretenberg/cpp/src RUN curl -s -L https://github.com/CraneStation/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-linux.tar.gz | tar zxfv - -WORKDIR /usr/src/aztec3-circuits +WORKDIR /usr/src/aztec3-circuits/cpp COPY . . -# Build both honk_tests barretenberg.wasm -# This ensures that we aren't using features that would be incompatible with WASM for Honk -RUN mkdir build && cd build && cmake -DTOOLCHAIN=wasm-linux-clang .. && cmake --build . --parallel + +RUN cmake --preset wasm && cmake --build --preset wasm FROM ubuntu:kinetic RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y xz-utils curl RUN curl https://wasmtime.dev/install.sh -sSf | bash /dev/stdin --version v3.0.1 -COPY --from=builder /usr/src/aztec3-circuits/barretenberg/cpp/srs_db /usr/src/aztec3-circuits/barretenberg/cpp/srs_db -COPY --from=builder /usr/src/aztec3-circuits/build/bin/*_tests /usr/src/aztec3-circuits/build/bin/ +COPY --from=builder /usr/src/aztec3-circuits/cpp/barretenberg/cpp/srs_db /usr/src/aztec3-circuits/cpp/barretenberg/cpp/srs_db +COPY --from=builder /usr/src/aztec3-circuits/cpp/build-wasm/bin/*_tests /usr/src/aztec3-circuits/cpp/build-wasm/bin/ diff --git a/circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-clang b/circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-clang index 8c960bead10..98667a53a03 100644 --- a/circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-clang +++ b/circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-clang @@ -6,16 +6,17 @@ RUN apk update \ clang15 \ openmp-dev \ cmake \ + ninja \ git \ curl \ perl -WORKDIR /usr/src/aztec3-circuits +WORKDIR /usr/src/aztec3-circuits/cpp COPY . . # Build the entire project, as we want to check everything builds under clang -RUN mkdir build && cd build && cmake .. && cmake --build . --parallel +RUN cmake --preset default && cmake --build --preset default FROM alpine:3.17 RUN apk update && apk add openmp -COPY --from=builder /usr/src/aztec3-circuits/barretenberg/cpp/srs_db /usr/src/aztec3-circuits/barretenberg/cpp/srs_db \ No newline at end of file +COPY --from=builder /usr/src/aztec3-circuits/cpp/barretenberg/cpp/srs_db /usr/src/aztec3-circuits/cpp/barretenberg/cpp/srs_db \ No newline at end of file diff --git a/circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-clang-assert b/circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-clang-assert index 70f8cca912d..41d13318d49 100644 --- a/circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-clang-assert +++ b/circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-clang-assert @@ -6,17 +6,18 @@ RUN apk update \ clang15 \ openmp-dev \ cmake \ + ninja \ git \ curl \ perl -WORKDIR /usr/src/aztec3-circuits +WORKDIR /usr/src/aztec3-circuits/cpp COPY . . # Build everything to ensure everything builds. All tests will be run from the result of this build. -RUN mkdir build && cd build && cmake -DCMAKE_BUILD_TYPE=RelWithAssert -DCI=ON .. && cmake --build . --parallel +RUN cmake --preset default -DCMAKE_BUILD_TYPE=RelWithAssert -DCI=ON && cmake --build --preset default FROM alpine:3.17 RUN apk update && apk add curl openmp -COPY --from=builder /usr/src/aztec3-circuits/barretenberg/cpp/srs_db /usr/src/aztec3-circuits/barretenberg/cpp/srs_db -COPY --from=builder /usr/src/aztec3-circuits/build/bin/*_tests /usr/src/aztec3-circuits/build/bin/ \ No newline at end of file +COPY --from=builder /usr/src/aztec3-circuits/cpp/barretenberg/cpp/srs_db /usr/src/aztec3-circuits/cpp/barretenberg/cpp/srs_db +COPY --from=builder /usr/src/aztec3-circuits/cpp/build/bin/*_tests /usr/src/aztec3-circuits/cpp/build/bin/ \ No newline at end of file diff --git a/circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-gcc b/circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-gcc index a6edcc6e51f..a8d343b1381 100644 --- a/circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-gcc +++ b/circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-gcc @@ -4,13 +4,14 @@ RUN apk update \ && apk add --no-cache \ build-base \ cmake \ + ninja \ git \ curl -WORKDIR /usr/src/aztec3-circuits +WORKDIR /usr/src/aztec3-circuits/cpp COPY . . # Build the entire project, as we want to check everything builds under gcc. -RUN mkdir build && cd build && cmake -DTOOLCHAIN=x86_64-linux-gcc -DCI=ON .. && cmake --build . --parallel +RUN cmake --preset gcc -DCI=ON && cmake --build --preset gcc FROM alpine:3.17 RUN apk update && apk add libstdc++ libgomp -COPY --from=builder /usr/src/aztec3-circuits/barretenberg/cpp/srs_db /usr/src/aztec3-circuits/barretenberg/cpp/srs_db +COPY --from=builder /usr/src/aztec3-circuits/cpp/barretenberg/cpp/srs_db /usr/src/aztec3-circuits/cpp/barretenberg/cpp/srs_db diff --git a/circuits/cpp/scripts/run_tests b/circuits/cpp/scripts/run_tests index 53c625425b8..128361bf1fe 100755 --- a/circuits/cpp/scripts/run_tests +++ b/circuits/cpp/scripts/run_tests @@ -22,14 +22,15 @@ fi if [ -z "$WASM_MODE" ]; then TEST_CMD="./bin/\$BIN $@" + BUILD_DIR=/usr/src/aztec3-circuits/cpp/build else TEST_CMD="wasmtime --dir .. bin/\$BIN $@" + BUILD_DIR=/usr/src/aztec3-circuits/cpp/build-wasm fi docker run --rm -t $IMAGE_URI /bin/sh -c "\ set -e; \ - cd /usr/src/aztec3-circuits/barretenberg/cpp/srs_db; \ + cd /usr/src/aztec3-circuits/cpp/barretenberg/cpp/srs_db; \ ./download_ignition.sh $NUM_TRANSCRIPTS; \ - ./download_ignition_lagrange.sh 24; \ - cd /usr/src/aztec3-circuits/build; \ + cd $BUILD_DIR; \ for BIN in $TESTS; do $TEST_CMD; done" diff --git a/circuits/cpp/src/CMakeLists.txt b/circuits/cpp/src/CMakeLists.txt index a694ab8909a..22985b6396a 100644 --- a/circuits/cpp/src/CMakeLists.txt +++ b/circuits/cpp/src/CMakeLists.txt @@ -3,7 +3,7 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) add_compile_options(-Werror -Wall -Wextra -Wconversion -Wsign-conversion -Wno-deprecated -Wno-tautological-compare -Wfatal-errors) if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") - add_compile_options(-Wno-unguarded-availability-new -Wno-c99-extensions -fconstexpr-steps=100000000) + add_compile_options(-fconstexpr-steps=100000000) if(MEMORY_CHECKS) message(STATUS "Compiling with memory checks.") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address") @@ -11,7 +11,7 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") endif() if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") - add_compile_options(-Wno-deprecated-copy -fconstexpr-ops-limit=100000000) + add_compile_options(-fconstexpr-ops-limit=100000000) endif() include_directories(${CMAKE_CURRENT_SOURCE_DIR}) @@ -25,8 +25,4 @@ else() message(STATUS "Using optimized assembly for field arithmetic.") endif() -add_subdirectory(aztec3) - -if(BENCHMARKS) - add_subdirectory(benchmark) -endif() \ No newline at end of file +add_subdirectory(aztec3) \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp b/circuits/cpp/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp index 8205b2714cd..b26bc35a06e 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp @@ -76,20 +76,20 @@ template struct PublicCircuitPublicInputs { PublicCircuitPublicInputs> pis = { to_circuit_type(call_context), - .args = to_ct(args), - .return_values = to_ct(return_values), + to_ct(args), + to_ct(return_values), - .emitted_events = to_ct(emitted_events), + to_ct(emitted_events), - .state_transitions = map(state_transitions, to_circuit_type), - .state_reads = map(state_reads, to_circuit_type), + map(state_transitions, to_circuit_type), + map(state_reads, to_circuit_type), - .public_call_stack = to_ct(public_call_stack), - .l1_msg_stack = to_ct(l1_msg_stack), + to_ct(public_call_stack), + to_ct(l1_msg_stack), - .old_private_data_tree_root = to_ct(old_private_data_tree_root), + to_ct(old_private_data_tree_root), - .prover_address = to_ct(prover_address), + to_ct(prover_address), }; return pis; From 9626fc7a23c210b2c3b8255d3731386a96f9163d Mon Sep 17 00:00:00 2001 From: David Banks <47112877+dbanks12@users.noreply.github.com> Date: Wed, 8 Mar 2023 08:45:48 -0700 Subject: [PATCH 066/166] c_bind for computing function selector (keccak) (#35) --- .../cpp/src/aztec3/circuits/abis/c_bind.cpp | 29 +++++++++++ .../cpp/src/aztec3/circuits/abis/c_bind.h | 1 + .../src/aztec3/circuits/abis/c_bind.test.cpp | 48 +++++++++++++++++++ 3 files changed, 78 insertions(+) diff --git a/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp b/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp index 557e1f0b225..7234bab78dc 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp +++ b/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp @@ -2,8 +2,10 @@ #include "tx_request.hpp" #include +#include namespace { +using aztec3::GeneratorIndex; using aztec3::circuits::abis::TxRequest; using NT = plonk::stdlib::types::NativeTypes; } // namespace @@ -28,4 +30,31 @@ WASM_EXPORT void abis__hash_tx_request(uint8_t const* tx_request_buf, uint8_t* o read(tx_request_buf, tx_request); NT::fr::serialize_to_buffer(tx_request.hash(), output); } + +/** + * @brief Generates a function's "selector" from its "signature" using keccak256. + * This is a WASM-export that can be called from Typescript. + * + * @details given a `char const*` c-string representing a "function signature", + * hash using keccak and return its first 4 bytes (the "function selector") + * by copying them into the `output` buffer arg. This is a workalike of + * Ethereum/solidity's function selector computation.... + * Ethereum function selector is computed as follows: + * `uint8_t* hash = keccak256(const char* func_sig);` + * where func_sig does NOT include the trailing null character + * And the resulting cstring for "transfer(address,uint256)" is: + * `0xa9059cbb` + * The 0th to 3rd bytes make up the function selector like: + * where 0xa9 is hash[0], 05 is hash[1], 9c is hash[2], and bb is hash[3] + * + * @param func_sig_cstr c-string representing the function signature string like "transfer(uint256,address)" + * @param output buffer that will contain the output which will be 4-byte function selector + */ +WASM_EXPORT void abis__compute_function_selector(char const* func_sig_cstr, uint8_t* output) +{ + // Hash the function signature using keccak256 + auto keccak_hash = ethash_keccak256((uint8_t*)func_sig_cstr, std::char_traits::length(func_sig_cstr)); + // Get the first 4 bytes of the hash's 0th word and copy into output buffer + memcpy(output, &keccak_hash.word64s[0], 4 * sizeof(uint8_t)); +} } diff --git a/circuits/cpp/src/aztec3/circuits/abis/c_bind.h b/circuits/cpp/src/aztec3/circuits/abis/c_bind.h index db27da4e5e4..ecd7647a991 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/c_bind.h +++ b/circuits/cpp/src/aztec3/circuits/abis/c_bind.h @@ -5,5 +5,6 @@ extern "C" { WASM_EXPORT void abis__hash_tx_request(uint8_t const* tx_request_buf, uint8_t* output); +WASM_EXPORT void abis__compute_function_selector(char const* func_sig_cstr, uint8_t* output); } diff --git a/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp b/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp index 96622e4e8cd..d55a37315be 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp @@ -6,8 +6,28 @@ #include namespace { + using NT = plonk::stdlib::types::NativeTypes; auto& engine = numeric::random::get_debug_engine(); + +/** + * @brief Convert a bytes buffer to a hex string. + * + * @details convert each byte to two hex characters + * + * @param bytes buffer of bytes to be converted to hex string + * @param first_n_bytes only include the first n bytes of `bytes` in the conversion + * @return a string containing the hex representation of the first n bytes of the input buffer + */ +std::string bytes_to_hex_str(uint8_t* bytes, int first_n_bytes) +{ + std::ostringstream stream; + for (int i = 0; i < first_n_bytes; i++) { + stream << std::setw(2) << std::setfill('0') << std::hex << static_cast(bytes[i]); + } + return stream.str(); +} + } // namespace namespace aztec3::circuits::abis { @@ -45,4 +65,32 @@ TEST(abis, hash_tx_request) EXPECT_EQ(got_hash, tx_request.hash()); } +TEST(abis, compute_function_selector_transfer) +{ + const char* function_signature = "transfer(address,uint256)"; + + // allocate an output buffer for cbind selector results + uint8_t* output = (uint8_t*)malloc(4 * sizeof(uint8_t)); + // Make the c_bind call to compute the function selector via keccak256 + abis__compute_function_selector(function_signature, output); + + // get the selector as a hex string of 4 bytes and + // compare against known good selector from solidity + EXPECT_EQ(bytes_to_hex_str(output, 4), "a9059cbb"); +} + +TEST(abis, compute_function_selector_transferFrom) +{ + const char* function_signature = "transferFrom(address,address,uint256)"; + + // allocate an output buffer for cbind selector results + uint8_t* output = (uint8_t*)malloc(4 * sizeof(uint8_t)); + // Make the c_bind call to compute the function selector via keccak256 + abis__compute_function_selector(function_signature, output); + + // get the selector as a hex string of 4 bytes and + // compare against known good selector from solidity + EXPECT_EQ(bytes_to_hex_str(output, 4), "23b872dd"); +} + } // namespace aztec3::circuits::abis From 75d1b5c169cda3be5800f0299ec21528ac51cfe5 Mon Sep 17 00:00:00 2001 From: David Banks <47112877+dbanks12@users.noreply.github.com> Date: Wed, 8 Mar 2023 13:14:26 -0700 Subject: [PATCH 067/166] fix bad mix of designated and non-designated intializers (#40) --- .../abis/public_circuit_public_inputs.hpp | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/circuits/cpp/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp b/circuits/cpp/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp index b26bc35a06e..e178da3d123 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp @@ -74,22 +74,22 @@ template struct PublicCircuitPublicInputs { auto to_circuit_type = [&](auto& e) { return e.to_circuit_type(composer); }; PublicCircuitPublicInputs> pis = { - to_circuit_type(call_context), + .call_context = to_circuit_type(call_context), - to_ct(args), - to_ct(return_values), + .args = to_ct(args), + .return_values = to_ct(return_values), - to_ct(emitted_events), + .emitted_events = to_ct(emitted_events), - map(state_transitions, to_circuit_type), - map(state_reads, to_circuit_type), + .state_transitions = map(state_transitions, to_circuit_type), + .state_reads = map(state_reads, to_circuit_type), - to_ct(public_call_stack), - to_ct(l1_msg_stack), + .public_call_stack = to_ct(public_call_stack), + .l1_msg_stack = to_ct(l1_msg_stack), - to_ct(old_private_data_tree_root), + .old_private_data_tree_root = to_ct(old_private_data_tree_root), - to_ct(prover_address), + .prover_address = to_ct(prover_address), }; return pis; From 78a88c13c7e7f53af6adc7ad30b1776a027a152e Mon Sep 17 00:00:00 2001 From: David Banks <47112877+dbanks12@users.noreply.github.com> Date: Wed, 8 Mar 2023 14:23:40 -0700 Subject: [PATCH 068/166] add missing frees in cbind test (#42) --- circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp b/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp index d55a37315be..428f150c536 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp @@ -61,6 +61,7 @@ TEST(abis, hash_tx_request) // Convert buffer to `fr` for comparison to in-test calculated hash NT::fr got_hash = NT::fr::serialize_from_buffer(output); + free(output); // Confirm cbind output == hash of tx request EXPECT_EQ(got_hash, tx_request.hash()); } @@ -73,6 +74,7 @@ TEST(abis, compute_function_selector_transfer) uint8_t* output = (uint8_t*)malloc(4 * sizeof(uint8_t)); // Make the c_bind call to compute the function selector via keccak256 abis__compute_function_selector(function_signature, output); + free(output); // get the selector as a hex string of 4 bytes and // compare against known good selector from solidity @@ -87,6 +89,7 @@ TEST(abis, compute_function_selector_transferFrom) uint8_t* output = (uint8_t*)malloc(4 * sizeof(uint8_t)); // Make the c_bind call to compute the function selector via keccak256 abis__compute_function_selector(function_signature, output); + free(output); // get the selector as a hex string of 4 bytes and // compare against known good selector from solidity From 8b0ec47bd2b3c446f6d64efce92f05216cc7cc8b Mon Sep 17 00:00:00 2001 From: David Banks <47112877+dbanks12@users.noreply.github.com> Date: Thu, 9 Mar 2023 16:48:32 -0700 Subject: [PATCH 069/166] Cleanup abis cbinds to use std arrays instead of pointers+malloc+free (#54) --- .../src/aztec3/circuits/abis/c_bind.test.cpp | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp b/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp index 428f150c536..0e1bf2bc19f 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp @@ -11,19 +11,19 @@ using NT = plonk::stdlib::types::NativeTypes; auto& engine = numeric::random::get_debug_engine(); /** - * @brief Convert a bytes buffer to a hex string. + * @brief Convert a bytes array to a hex string. * * @details convert each byte to two hex characters * - * @param bytes buffer of bytes to be converted to hex string - * @param first_n_bytes only include the first n bytes of `bytes` in the conversion - * @return a string containing the hex representation of the first n bytes of the input buffer + * @tparam NUM_BYTES length of bytes array input + * @param bytes array of bytes to be converted to hex string + * @return a string containing the hex representation of the NUM_BYTES bytes of the input array */ -std::string bytes_to_hex_str(uint8_t* bytes, int first_n_bytes) +template std::string bytes_to_hex_str(std::array bytes) { std::ostringstream stream; - for (int i = 0; i < first_n_bytes; i++) { - stream << std::setw(2) << std::setfill('0') << std::hex << static_cast(bytes[i]); + for (const uint8_t& byte : bytes) { + stream << std::setw(2) << std::setfill('0') << std::hex << static_cast(byte); } return stream.str(); } @@ -55,13 +55,15 @@ TEST(abis, hash_tx_request) // allocate an output buffer for cbind hash results std::vector buf; write(buf, tx_request); - uint8_t* output = (uint8_t*)malloc(32 * sizeof(uint8_t)); + + // create an output buffer for cbind hash results + std::array output = { 0 }; // Make the c_bind call to hash the tx request - abis__hash_tx_request(buf.data(), output); + abis__hash_tx_request(buf.data(), output.data()); // Convert buffer to `fr` for comparison to in-test calculated hash - NT::fr got_hash = NT::fr::serialize_from_buffer(output); - free(output); + NT::fr got_hash = NT::fr::serialize_from_buffer(output.data()); + // Confirm cbind output == hash of tx request EXPECT_EQ(got_hash, tx_request.hash()); } @@ -70,30 +72,28 @@ TEST(abis, compute_function_selector_transfer) { const char* function_signature = "transfer(address,uint256)"; - // allocate an output buffer for cbind selector results - uint8_t* output = (uint8_t*)malloc(4 * sizeof(uint8_t)); + // create an output buffer for cbind selector results + std::array output = { 0 }; // Make the c_bind call to compute the function selector via keccak256 - abis__compute_function_selector(function_signature, output); - free(output); + abis__compute_function_selector(function_signature, output.data()); // get the selector as a hex string of 4 bytes and // compare against known good selector from solidity - EXPECT_EQ(bytes_to_hex_str(output, 4), "a9059cbb"); + EXPECT_EQ(bytes_to_hex_str(output), "a9059cbb"); } TEST(abis, compute_function_selector_transferFrom) { const char* function_signature = "transferFrom(address,address,uint256)"; - // allocate an output buffer for cbind selector results - uint8_t* output = (uint8_t*)malloc(4 * sizeof(uint8_t)); + // create an output buffer for cbind selector results + std::array output = { 0 }; // Make the c_bind call to compute the function selector via keccak256 - abis__compute_function_selector(function_signature, output); - free(output); + abis__compute_function_selector(function_signature, output.data()); // get the selector as a hex string of 4 bytes and // compare against known good selector from solidity - EXPECT_EQ(bytes_to_hex_str(output, 4), "23b872dd"); + EXPECT_EQ(bytes_to_hex_str(output), "23b872dd"); } } // namespace aztec3::circuits::abis From 90784e2aa28e9d2cdb07f2e63942d0c25d317990 Mon Sep 17 00:00:00 2001 From: David Banks <47112877+dbanks12@users.noreply.github.com> Date: Thu, 9 Mar 2023 17:21:00 -0700 Subject: [PATCH 070/166] Make function selector cbind more C++ like (#55) * memcpy -> std::copy * use reinterpret casts instead of c-style casts * use strlen instead of char_traits length --- circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp b/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp index 7234bab78dc..e66765a4b6b 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp +++ b/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp @@ -52,9 +52,11 @@ WASM_EXPORT void abis__hash_tx_request(uint8_t const* tx_request_buf, uint8_t* o */ WASM_EXPORT void abis__compute_function_selector(char const* func_sig_cstr, uint8_t* output) { - // Hash the function signature using keccak256 - auto keccak_hash = ethash_keccak256((uint8_t*)func_sig_cstr, std::char_traits::length(func_sig_cstr)); - // Get the first 4 bytes of the hash's 0th word and copy into output buffer - memcpy(output, &keccak_hash.word64s[0], 4 * sizeof(uint8_t)); + // hash the function signature using keccak256 + auto keccak_hash = ethash_keccak256(reinterpret_cast(func_sig_cstr), strlen(func_sig_cstr)); + // get a pointer to the start of the hash bytes + uint8_t const* hash_bytes = reinterpret_cast(&keccak_hash.word64s[0]); + // get the first 4 bytes of the hash's 0th word and copy into output buffer + std::copy(hash_bytes, hash_bytes + 4, output); } } From 60d001381dfe49f4e46fcc2e6fd28a74856f60f8 Mon Sep 17 00:00:00 2001 From: David Banks <47112877+dbanks12@users.noreply.github.com> Date: Tue, 14 Mar 2023 18:36:33 -0400 Subject: [PATCH 071/166] Function leaf (preimage struct & cbind) (#56) * function_selector size is configurable via const * function leaf preimage struct with a hash function * cbind is done for computing function leaf hash * test for function leaf cbind --- .../cpp/src/aztec3/circuits/abis/c_bind.cpp | 29 +++- .../cpp/src/aztec3/circuits/abis/c_bind.h | 1 + .../src/aztec3/circuits/abis/c_bind.test.cpp | 46 +++++-- .../circuits/abis/function_leaf_preimage.hpp | 124 ++++++++++++++++++ .../circuits/abis/function_signature.hpp | 8 +- circuits/cpp/src/aztec3/constants.hpp | 3 + 6 files changed, 194 insertions(+), 17 deletions(-) create mode 100644 circuits/cpp/src/aztec3/circuits/abis/function_leaf_preimage.hpp diff --git a/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp b/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp index e66765a4b6b..2ebd1fe3f55 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp +++ b/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp @@ -1,11 +1,16 @@ #include "c_bind.h" #include "tx_request.hpp" +#include "function_leaf_preimage.hpp" + +#include #include #include +#include namespace { using aztec3::GeneratorIndex; +using aztec3::circuits::abis::FunctionLeafPreimage; using aztec3::circuits::abis::TxRequest; using NT = plonk::stdlib::types::NativeTypes; } // namespace @@ -56,7 +61,27 @@ WASM_EXPORT void abis__compute_function_selector(char const* func_sig_cstr, uint auto keccak_hash = ethash_keccak256(reinterpret_cast(func_sig_cstr), strlen(func_sig_cstr)); // get a pointer to the start of the hash bytes uint8_t const* hash_bytes = reinterpret_cast(&keccak_hash.word64s[0]); - // get the first 4 bytes of the hash's 0th word and copy into output buffer - std::copy(hash_bytes, hash_bytes + 4, output); + // get the correct number of bytes from the hash and copy into output buffer + std::copy_n(hash_bytes, aztec3::FUNCTION_SELECTOR_NUM_BYTES, output); } + +/** + * @brief Generates a function tree leaf from its preimage. + * This is a WASM-export that can be called from Typescript. + * + * @details given a `uint8_t const*` buffer representing a function leaf's prieimage, + * construct a FunctionLeafPreimage instance, hash, and return the serialized results + * in the `output` buffer. + * + * @param function_leaf_preimage_buf a buffer of bytes representing the function leaf's preimage + * contents (`function_selector`, `is_private`, `vk_hash`, and `acir_hash`) + * @param output buffer that will contain the output. The hashed and serialized function leaf. + */ +WASM_EXPORT void abis__compute_function_leaf(uint8_t const* function_leaf_preimage_buf, uint8_t* output) +{ + FunctionLeafPreimage leaf_preimage; + read(function_leaf_preimage_buf, leaf_preimage); + leaf_preimage.hash(); + NT::fr::serialize_to_buffer(leaf_preimage.hash(), output); } +} // extern "C" \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/abis/c_bind.h b/circuits/cpp/src/aztec3/circuits/abis/c_bind.h index ecd7647a991..77eec984d66 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/c_bind.h +++ b/circuits/cpp/src/aztec3/circuits/abis/c_bind.h @@ -6,5 +6,6 @@ extern "C" { WASM_EXPORT void abis__hash_tx_request(uint8_t const* tx_request_buf, uint8_t* output); WASM_EXPORT void abis__compute_function_selector(char const* func_sig_cstr, uint8_t* output); +WASM_EXPORT void abis__compute_function_leaf(uint8_t const* function_leaf_preimage_buf, uint8_t* output); } diff --git a/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp b/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp index 0e1bf2bc19f..a9852fac5b6 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp @@ -1,6 +1,7 @@ #include "c_bind.h" #include "tx_request.hpp" +#include "function_leaf_preimage.hpp" #include #include @@ -32,7 +33,7 @@ template std::string bytes_to_hex_str(std::array args; @@ -40,7 +41,7 @@ TEST(abis, hash_tx_request) args[i] = fr(engine.get_random_uint256()); } - // Construct mostly empty TxRequest with some randomized fields + // Construct TxRequest with some randomized fields TxRequest tx_request = TxRequest{ .from = engine.get_random_uint256(), .to = engine.get_random_uint256(), @@ -52,7 +53,6 @@ TEST(abis, hash_tx_request) }; // Write the tx request to a buffer and - // allocate an output buffer for cbind hash results std::vector buf; write(buf, tx_request); @@ -68,32 +68,56 @@ TEST(abis, hash_tx_request) EXPECT_EQ(got_hash, tx_request.hash()); } -TEST(abis, compute_function_selector_transfer) +TEST(abi_tests, compute_function_selector_transfer) { const char* function_signature = "transfer(address,uint256)"; // create an output buffer for cbind selector results - std::array output = { 0 }; + std::array output = { 0 }; // Make the c_bind call to compute the function selector via keccak256 abis__compute_function_selector(function_signature, output.data()); - // get the selector as a hex string of 4 bytes and + // get the selector as a hex string // compare against known good selector from solidity - EXPECT_EQ(bytes_to_hex_str(output), "a9059cbb"); + // In solidity where selectors are 4 bytes it is a9059cbb + std::string full_selector = "a9059cbb2ab09eb219583f4a59a5d0623ade346d962bcd4e46b11da047c9049b"; + EXPECT_EQ(bytes_to_hex_str(output), full_selector.substr(0, FUNCTION_SELECTOR_NUM_BYTES * 2)); } -TEST(abis, compute_function_selector_transferFrom) +TEST(abi_tests, compute_function_selector_transferFrom) { const char* function_signature = "transferFrom(address,address,uint256)"; // create an output buffer for cbind selector results - std::array output = { 0 }; + std::array output = { 0 }; // Make the c_bind call to compute the function selector via keccak256 abis__compute_function_selector(function_signature, output.data()); - // get the selector as a hex string of 4 bytes and + // get the selector as a hex string // compare against known good selector from solidity - EXPECT_EQ(bytes_to_hex_str(output), "23b872dd"); + std::string full_selector = "23b872dd7302113369cda2901243429419bec145408fa8b352b3dd92b66c680b"; + EXPECT_EQ(bytes_to_hex_str(output), full_selector.substr(0, FUNCTION_SELECTOR_NUM_BYTES * 2)); +} + +TEST(abi_tests, compute_function_leaf) +{ + // Construct FunctionLeafPreimage with some randomized fields + FunctionLeafPreimage preimage = FunctionLeafPreimage{ + .function_selector = engine.get_random_uint256(), + .is_private = static_cast(engine.get_random_uint8() & 1), + .vk_hash = engine.get_random_uint256(), + .acir_hash = engine.get_random_uint256(), + }; + + // Write the leaf preimage to a buffer + std::vector preimage_buf; + write(preimage_buf, preimage); + + std::array output = { 0 }; + abis__compute_function_leaf(preimage_buf.data(), output.data()); + + NT::fr got_leaf = NT::fr::serialize_from_buffer(output.data()); + EXPECT_EQ(got_leaf, preimage.hash()); } } // namespace aztec3::circuits::abis diff --git a/circuits/cpp/src/aztec3/circuits/abis/function_leaf_preimage.hpp b/circuits/cpp/src/aztec3/circuits/abis/function_leaf_preimage.hpp new file mode 100644 index 00000000000..efc9890e533 --- /dev/null +++ b/circuits/cpp/src/aztec3/circuits/abis/function_leaf_preimage.hpp @@ -0,0 +1,124 @@ +#pragma once +#include +#include +#include +#include + +namespace aztec3::circuits::abis { + +using plonk::stdlib::types::CircuitTypes; +using plonk::stdlib::types::NativeTypes; +using std::is_same; + +/** + * @brief A struct representing the "preimage" of a function tree leaf. + * Templated on NativeTypes/CircuitTypes. + * + * @details A FunctionLeafPreimage contains: + * - `function_selector` keccak hash of function signature truncated to NUM_FUNCTION_SELECTOR_BYTES + * - `is_private` boolean flag + * - `vk_hash` pedersen hash of the function verification key + * - `acir_hash` hash of the function's acir bytecode + * This struct includes a `hash()` function for computing its pedersen compression. + * There are also static functions for: + * - converting preimages between native/circuit types + * - serialising and deserialising preimages + * - writing a preimage to an ostream + */ +template struct FunctionLeafPreimage { + + typedef typename NCT::boolean boolean; + typedef typename NCT::fr fr; + + fr function_selector; + boolean is_private; + fr vk_hash; + fr acir_hash; + + bool operator==(FunctionLeafPreimage const&) const = default; + + static FunctionLeafPreimage empty() { return { 0, 0, 0, 0 }; }; + + template FunctionLeafPreimage> to_circuit_type(Composer& composer) const + { + static_assert((std::is_same::value)); + + // Capture the composer: + auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + + FunctionLeafPreimage> preimage = { + to_ct(function_selector), + to_ct(is_private), + to_ct(vk_hash), + to_ct(acir_hash), + }; + + return preimage; + }; + + template FunctionLeafPreimage to_native_type() const + { + static_assert(std::is_same, NCT>::value); + auto to_nt = [&](auto& e) { return plonk::stdlib::types::to_nt(e); }; + + FunctionLeafPreimage preimage = { + to_nt(function_selector), + to_nt(is_private), + to_nt(vk_hash), + to_nt(acir_hash), + }; + + return preimage; + }; + + void set_public() + { + static_assert(!(std::is_same::value)); + + function_selector.set_public(); + fr(is_private).set_public(); + vk_hash.set_public(); + acir_hash.set_public(); + } + + fr hash() const + { + std::vector inputs = { + function_selector, + fr(is_private), + vk_hash, + acir_hash, + }; + return NCT::compress(inputs, GeneratorIndex::FUNCTION_LEAF); + } +}; + +template void read(uint8_t const*& it, FunctionLeafPreimage& preimage) +{ + using serialize::read; + + read(it, preimage.function_selector); + read(it, preimage.is_private); + read(it, preimage.vk_hash); + read(it, preimage.acir_hash); +}; + +template void write(std::vector& buf, FunctionLeafPreimage const& preimage) +{ + using serialize::write; + + write(buf, preimage.function_selector); + write(buf, preimage.is_private); + write(buf, preimage.vk_hash); + write(buf, preimage.acir_hash); +}; + +template std::ostream& operator<<(std::ostream& os, FunctionLeafPreimage const& preimage) +{ + return os << "function_selector: " << preimage.function_selector << "\n" + << "is_private: " << preimage.is_private << "\n" + << "vk_hash: " << preimage.vk_hash << "\n" + << "acir_hash: " << preimage.acir_hash << "\n"; +} + +} // namespace aztec3::circuits::abis \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/abis/function_signature.hpp b/circuits/cpp/src/aztec3/circuits/abis/function_signature.hpp index 08e2300c817..541f2b1c511 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/function_signature.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/function_signature.hpp @@ -1,7 +1,7 @@ #pragma once -#include +//#include #include -#include +//#include #include #include #include @@ -9,7 +9,7 @@ namespace aztec3::circuits::abis { -using plonk::stdlib::witness_t; +// using plonk::stdlib::witness_t; using plonk::stdlib::types::CircuitTypes; using plonk::stdlib::types::NativeTypes; using std::is_same; @@ -18,7 +18,7 @@ template struct FunctionSignature { // typedef typename NCT::address address; typedef typename NCT::uint32 uint32; typedef typename NCT::boolean boolean; - typedef typename NCT::grumpkin_point grumpkin_point; + // typedef typename NCT::grumpkin_point grumpkin_point; typedef typename NCT::fr fr; uint32 function_encoding; // e.g. 1st 4-bytes of abi-encoding of function. diff --git a/circuits/cpp/src/aztec3/constants.hpp b/circuits/cpp/src/aztec3/constants.hpp index 61706b24829..43a4284c08b 100644 --- a/circuits/cpp/src/aztec3/constants.hpp +++ b/circuits/cpp/src/aztec3/constants.hpp @@ -29,6 +29,8 @@ constexpr size_t CONTRACT_TREE_HEIGHT = 4; constexpr size_t PRIVATE_DATA_TREE_HEIGHT = 8; constexpr size_t NULLIFIER_TREE_HEIGHT = 8; +constexpr size_t FUNCTION_SELECTOR_NUM_BYTES = 31; // must be <= 31 + // Enumerate the hash_indices which are used for pedersen hashing // Start from 1 to avoid the default generators. enum GeneratorIndex { @@ -52,6 +54,7 @@ enum GeneratorIndex { CONTRACT_DEPLOYMENT_DATA, TX_CONTEXT, TX_REQUEST, + FUNCTION_LEAF, }; enum StorageSlotGeneratorIndex { From 66f219a52f5b85319f277e53a0bc4b882c28a6b2 Mon Sep 17 00:00:00 2001 From: David Banks <47112877+dbanks12@users.noreply.github.com> Date: Wed, 15 Mar 2023 11:28:28 -0400 Subject: [PATCH 072/166] rename function signature to function data (#57) --- .../cpp/src/aztec3/circuits/abis/.test.cpp | 26 +++++------ .../src/aztec3/circuits/abis/c_bind.test.cpp | 2 +- .../aztec3/circuits/abis/call_stack_item.hpp | 16 +++---- ...nction_signature.hpp => function_data.hpp} | 44 +++++++++---------- .../cpp/src/aztec3/circuits/abis/index.hpp | 2 +- .../abis/optionally_revealed_data.hpp | 10 ++--- .../src/aztec3/circuits/abis/tx_context.hpp | 2 +- .../src/aztec3/circuits/abis/tx_request.hpp | 14 +++--- .../cpp/src/aztec3/circuits/apps/.test.cpp | 4 +- .../cpp/src/aztec3/circuits/apps/contract.hpp | 10 ++--- .../cpp/src/aztec3/circuits/apps/contract.tpp | 18 ++++---- .../apps/function_execution_context.hpp | 19 ++++---- .../circuits/apps/notes/note_interface.hpp | 2 +- .../circuits/apps/test_apps/escrow/.test.cpp | 6 +-- .../.test.cpp | 7 ++- .../aztec3/circuits/kernel/private/.test.cpp | 12 ++--- .../kernel/private/private_kernel_circuit.cpp | 4 +- circuits/cpp/src/aztec3/constants.hpp | 2 +- circuits/cpp/src/aztec3/oracle/oracle.hpp | 16 +++---- .../app-circuits/public-input-abis.md | 4 +- .../src/architecture/contracts/contracts.md | 2 +- .../architecture/contracts/transactions.md | 26 +++++------ .../contract-deployment-kernel.md | 16 +++---- .../kernel-circuits/private-kernel.md | 24 +++++----- .../kernel-circuits/public-kernel.md | 44 +++++++++---------- .../rollup-circuits/base-rollup.md | 18 ++++---- .../rollup-circuits/merge-rollup.md | 2 +- .../erc20/appendix/portal-contract.md | 10 ++--- .../erc20/appendix/rollup-processor.md | 4 +- .../specs/src/examples/erc20/deployment.md | 2 +- circuits/specs/src/examples/erc20/deposit.md | 4 +- .../specs/src/noir-stuff/extremes/call-l1.md | 10 ++--- .../src/noir-stuff/extremes/call-private.md | 6 +-- .../noir-stuff/extremes/call-public-same.md | 6 +-- .../src/noir-stuff/extremes/call-public.md | 6 +-- .../noir-stuff/extremes/deploy-contract.md | 2 +- .../src/noir-stuff/extremes/emit-event.md | 4 +- 37 files changed, 202 insertions(+), 204 deletions(-) rename circuits/cpp/src/aztec3/circuits/abis/{function_signature.hpp => function_data.hpp} (61%) diff --git a/circuits/cpp/src/aztec3/circuits/abis/.test.cpp b/circuits/cpp/src/aztec3/circuits/abis/.test.cpp index 6d593035634..921d25a9395 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/abis/.test.cpp @@ -13,36 +13,36 @@ using NT = plonk::stdlib::types::NativeTypes; class abi_tests : public ::testing::Test {}; -TEST(abi_tests, test_native_function_signature) +TEST(abi_tests, test_native_function_data) { - FunctionSignature function_signature = { + FunctionData function_data = { .function_encoding = 11, .is_private = false, .is_constructor = false, }; - info("function signature: ", function_signature); + info("function data: ", function_data); - auto buffer = to_buffer(function_signature); - auto function_signature_2 = from_buffer>(buffer.data()); + auto buffer = to_buffer(function_data); + auto function_data_2 = from_buffer>(buffer.data()); - EXPECT_EQ(function_signature, function_signature_2); + EXPECT_EQ(function_data, function_data_2); } -TEST(abi_tests, test_native_to_circuit_function_signature) +TEST(abi_tests, test_native_to_circuit_function_data) { - FunctionSignature native_function_signature = { + FunctionData native_function_data = { .function_encoding = 11, .is_private = false, .is_constructor = false, }; - info("function signature: ", native_function_signature); + info("function data: ", native_function_data); Composer composer = Composer("../barretenberg/cpp/srs_db/ignition"); - FunctionSignature circuit_function_signature = native_function_signature.to_circuit_type(composer); + FunctionData circuit_function_data = native_function_data.to_circuit_type(composer); - info("function signature: ", circuit_function_signature); + info("function data: ", circuit_function_data); } TEST(abi_tests, test_native_call_context) @@ -130,7 +130,7 @@ TEST(abi_tests, test_native_to_circuit_call_context) // }; // CallStackItem call_stack_item = { -// .function_signature = { +// .function_data = { // // .contract_address = 10, // .function_encoding = 11, // .is_private = false, @@ -163,7 +163,7 @@ TEST(abi_tests, test_native_to_circuit_call_context) // }; // CallStackItem native_call_stack_item = { -// .function_signature = { +// .function_data = { // // .contract_address = 10, // .function_encoding = 11, // .is_private = false, diff --git a/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp b/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp index a9852fac5b6..047b2caa63d 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp @@ -45,7 +45,7 @@ TEST(abi_tests, hash_tx_request) TxRequest tx_request = TxRequest{ .from = engine.get_random_uint256(), .to = engine.get_random_uint256(), - .function_signature = FunctionSignature(), + .function_data = FunctionData(), .args = args, .nonce = engine.get_random_uint256(), .tx_context = TxContext(), diff --git a/circuits/cpp/src/aztec3/circuits/abis/call_stack_item.hpp b/circuits/cpp/src/aztec3/circuits/abis/call_stack_item.hpp index c32f9a79b48..f70b401b15b 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/call_stack_item.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/call_stack_item.hpp @@ -1,5 +1,5 @@ #pragma once -#include "function_signature.hpp" +#include "function_data.hpp" #include "private_circuit_public_inputs.hpp" #include "public_circuit_public_inputs.hpp" @@ -36,14 +36,14 @@ template struct CallStackItem { // `contract_address` _does not change_. Amongst other things, it's used as a lookup for // getting the correct code from the tree. There is a separate `storage_contract_address` // within a CallStackItem which varies depending on whether this is a call or delegatecall. - FunctionSignature function_signature; + FunctionData function_data; PublicInputs public_inputs; bool operator==(CallStackItem const&) const = default; template static CallStackItem empty() { - return { 0, FunctionSignature::empty(), PublicInputs::empty() }; + return { 0, FunctionData::empty(), PublicInputs::empty() }; }; template @@ -56,7 +56,7 @@ template struct CallStackItem { CallStackItem, call_type> call_stack_item = { to_ct(contract_address), - function_signature.to_circuit_type(composer), + function_data.to_circuit_type(composer), public_inputs.to_circuit_type(composer), }; @@ -67,7 +67,7 @@ template struct CallStackItem { { std::vector inputs = { contract_address.to_field(), - function_signature.hash(), + function_data.hash(), public_inputs.hash(), }; @@ -83,7 +83,7 @@ void read(uint8_t const*& it, CallStackItem& call_stack_item) using serialize::read; read(it, call_stack_item.contract_address); - read(it, call_stack_item.function_signature); + read(it, call_stack_item.function_data); read(it, call_stack_item.public_inputs_hash); }; @@ -93,7 +93,7 @@ void write(std::vector& buf, CallStackItem const& call_ using serialize::write; write(buf, call_stack_item.contract_address); - write(buf, call_stack_item.function_signature); + write(buf, call_stack_item.function_data); write(buf, call_stack_item.public_inputs_hash); }; @@ -101,7 +101,7 @@ template std::ostream& operator<<(std::ostream& os, CallStackItem const& call_stack_item) { return os << "contract_address: " << call_stack_item.contract_address << "\n" - << "function_signature: " << call_stack_item.function_signature << "\n" + << "function_data: " << call_stack_item.function_data << "\n" << "public_inputs: " << call_stack_item.public_inputs << "\n"; } diff --git a/circuits/cpp/src/aztec3/circuits/abis/function_signature.hpp b/circuits/cpp/src/aztec3/circuits/abis/function_data.hpp similarity index 61% rename from circuits/cpp/src/aztec3/circuits/abis/function_signature.hpp rename to circuits/cpp/src/aztec3/circuits/abis/function_data.hpp index 541f2b1c511..257ab2832e7 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/function_signature.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/function_data.hpp @@ -14,7 +14,7 @@ using plonk::stdlib::types::CircuitTypes; using plonk::stdlib::types::NativeTypes; using std::is_same; -template struct FunctionSignature { +template struct FunctionData { // typedef typename NCT::address address; typedef typename NCT::uint32 uint32; typedef typename NCT::boolean boolean; @@ -25,38 +25,38 @@ template struct FunctionSignature { boolean is_private = false; boolean is_constructor = false; - bool operator==(FunctionSignature const&) const = default; + bool operator==(FunctionData const&) const = default; - static FunctionSignature empty() { return { 0, 0, 0 }; }; + static FunctionData empty() { return { 0, 0, 0 }; }; - template FunctionSignature> to_circuit_type(Composer& composer) const + template FunctionData> to_circuit_type(Composer& composer) const { static_assert((std::is_same::value)); // Capture the composer: auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; - FunctionSignature> function_signature = { + FunctionData> function_data = { to_ct(function_encoding), to_ct(is_private), to_ct(is_constructor), }; - return function_signature; + return function_data; }; - template FunctionSignature to_native_type() const + template FunctionData to_native_type() const { static_assert(std::is_same, NCT>::value); auto to_nt = [&](auto& e) { return plonk::stdlib::types::to_nt(e); }; - FunctionSignature fs = { + FunctionData function_data = { to_nt(function_encoding), to_nt(is_private), to_nt(is_constructor), }; - return fs; + return function_data; }; void set_public() @@ -77,33 +77,33 @@ template struct FunctionSignature { fr(is_constructor), }; - return NCT::compress(inputs, GeneratorIndex::FUNCTION_SIGNATURE); + return NCT::compress(inputs, GeneratorIndex::FUNCTION_DATA); } }; -template void read(uint8_t const*& it, FunctionSignature& function_signature) +template void read(uint8_t const*& it, FunctionData& function_data) { using serialize::read; - read(it, function_signature.function_encoding); - read(it, function_signature.is_private); - read(it, function_signature.is_constructor); + read(it, function_data.function_encoding); + read(it, function_data.is_private); + read(it, function_data.is_constructor); }; -template void write(std::vector& buf, FunctionSignature const& function_signature) +template void write(std::vector& buf, FunctionData const& function_data) { using serialize::write; - write(buf, function_signature.function_encoding); - write(buf, function_signature.is_private); - write(buf, function_signature.is_constructor); + write(buf, function_data.function_encoding); + write(buf, function_data.is_private); + write(buf, function_data.is_constructor); }; -template std::ostream& operator<<(std::ostream& os, FunctionSignature const& function_signature) +template std::ostream& operator<<(std::ostream& os, FunctionData const& function_data) { - return os << "function_encoding: " << function_signature.function_encoding << "\n" - << "is_private: " << function_signature.is_private << "\n" - << "is_constructor: " << function_signature.is_constructor << "\n"; + return os << "function_encoding: " << function_data.function_encoding << "\n" + << "is_private: " << function_data.is_private << "\n" + << "is_constructor: " << function_data.is_constructor << "\n"; } } // namespace aztec3::circuits::abis \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/abis/index.hpp b/circuits/cpp/src/aztec3/circuits/abis/index.hpp index 7d845630ff7..1c6769333bc 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/index.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/index.hpp @@ -1,6 +1,6 @@ #include "call_context.hpp" #include "call_stack_item.hpp" -#include "function_signature.hpp" +#include "function_data.hpp" #include "private_circuit_public_inputs.hpp" #include "private_circuit_public_inputs.hpp" #include "state_read.hpp" diff --git a/circuits/cpp/src/aztec3/circuits/abis/optionally_revealed_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/optionally_revealed_data.hpp index be82da31608..2b860c9d5af 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/optionally_revealed_data.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/optionally_revealed_data.hpp @@ -1,5 +1,5 @@ #pragma once -#include "function_signature.hpp" +#include "function_data.hpp" #include #include #include @@ -15,7 +15,7 @@ template struct OptionallyRevealedData { typedef typename NCT::fr fr; fr call_stack_item_hash; - FunctionSignature function_signature; + FunctionData function_data; std::array emitted_events; fr vk_hash; fr portal_contract_address; // an ETH address @@ -33,7 +33,7 @@ template struct OptionallyRevealedData { auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; OptionallyRevealedData> data = { - to_ct(call_stack_item_hash), function_signature.to_circuit_type(composer), + to_ct(call_stack_item_hash), function_data.to_circuit_type(composer), to_ct(emitted_events), to_ct(vk_hash), to_ct(portal_contract_address), to_ct(pay_fee_from_l1), to_ct(pay_fee_from_public_l2), to_ct(called_from_l1), @@ -50,7 +50,7 @@ template struct OptionallyRevealedData { auto to_native_type = [](T& e) { return e.template to_native_type(); }; OptionallyRevealedData data = { - to_nt(call_stack_item_hash), to_native_type(function_signature), + to_nt(call_stack_item_hash), to_native_type(function_data), to_nt(emitted_events), to_nt(vk_hash), to_nt(portal_contract_address), to_nt(pay_fee_from_l1), to_nt(pay_fee_from_public_l2), to_nt(called_from_l1), @@ -65,7 +65,7 @@ template struct OptionallyRevealedData { static_assert(!(std::is_same::value)); call_stack_item_hash.set_public(); - function_signature.set_public(); + function_data.set_public(); set_array_public(emitted_events); vk_hash.set_public(); portal_contract_address.set_public(); diff --git a/circuits/cpp/src/aztec3/circuits/abis/tx_context.hpp b/circuits/cpp/src/aztec3/circuits/abis/tx_context.hpp index 2823f659fc6..a4cacf561e0 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/tx_context.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/tx_context.hpp @@ -1,6 +1,6 @@ #pragma once #include "contract_deployment_data.hpp" -#include "function_signature.hpp" +#include "function_data.hpp" #include #include #include diff --git a/circuits/cpp/src/aztec3/circuits/abis/tx_request.hpp b/circuits/cpp/src/aztec3/circuits/abis/tx_request.hpp index 99943cf51ae..9c3cff89a0f 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/tx_request.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/tx_request.hpp @@ -1,5 +1,5 @@ #pragma once -#include "function_signature.hpp" +#include "function_data.hpp" #include "tx_context.hpp" #include #include @@ -20,7 +20,7 @@ template struct TxRequest { address from; address to; - FunctionSignature function_signature; + FunctionData function_data; std::array args; fr nonce; TxContext tx_context; @@ -35,7 +35,7 @@ template struct TxRequest { auto to_circuit_type = [&](auto& e) { return e.to_circuit_type(composer); }; TxRequest> tx_request = { - to_ct(from), to_ct(to), to_circuit_type(function_signature), + to_ct(from), to_ct(to), to_circuit_type(function_data), to_ct(args), to_ct(nonce), to_circuit_type(tx_context), to_ct(chain_id), }; @@ -48,7 +48,7 @@ template struct TxRequest { std::vector inputs; inputs.push_back(fr(from)); inputs.push_back(fr(to)); - inputs.push_back(function_signature.hash()); + inputs.push_back(function_data.hash()); spread_arr_into_vec(args, inputs); inputs.push_back(nonce); inputs.push_back(tx_context.hash()); @@ -69,7 +69,7 @@ template void read(uint8_t const*& it, TxRequest& tx_request read(it, tx_request.from); read(it, tx_request.to); - read(it, tx_request.function_signature); + read(it, tx_request.function_data); read(it, tx_request.args); read(it, tx_request.nonce); read(it, tx_request.tx_context); @@ -82,7 +82,7 @@ template void write(std::vector& buf, TxRequest con write(buf, tx_request.from); write(buf, tx_request.to); - write(buf, tx_request.function_signature); + write(buf, tx_request.function_data); write(buf, tx_request.args); write(buf, tx_request.nonce); write(buf, tx_request.tx_context); @@ -93,7 +93,7 @@ template std::ostream& operator<<(std::ostream& os, TxRequest function_signature{ + FunctionData function_data{ .function_encoding = 1, // TODO: deduce this from the contract, somehow. .is_private = true, .is_constructor = false, @@ -111,7 +111,7 @@ class state_var_tests : public ::testing::Test { .reference_block_num = 0, }; - return NativeOracle(db, contract_address, function_signature, call_context, msg_sender_private_key); + return NativeOracle(db, contract_address, function_data, call_context, msg_sender_private_key); }; }; diff --git a/circuits/cpp/src/aztec3/circuits/apps/contract.hpp b/circuits/cpp/src/aztec3/circuits/apps/contract.hpp index d6d17fce9b7..bcd125aaafa 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/contract.hpp +++ b/circuits/cpp/src/aztec3/circuits/apps/contract.hpp @@ -3,13 +3,13 @@ #include "function_declaration.hpp" #include "l1_function_interface.hpp" -#include +#include #include namespace aztec3::circuits::apps { -using aztec3::circuits::abis::FunctionSignature; +using aztec3::circuits::abis::FunctionData; using plonk::stdlib::witness_t; using plonk::stdlib::types::CircuitTypes; @@ -30,7 +30,7 @@ template class Contract { std::map start_slots_by_state_var_name; - std::map> function_signatures; + std::map> function_datas; std::map> l1_functions; @@ -55,9 +55,9 @@ template class Contract { } // TODO: return some Function class which has a `call` method... - // FunctionSignature get_function(std::string name) { return function_signature[name]; } + // FunctionData get_function(std::string name) { return function_data[name]; } - FunctionSignature get_function_signature_by_name(std::string const& name); + FunctionData get_function_data_by_name(std::string const& name); void import_l1_function(L1FunctionInterfaceStruct const& l1_function_struct); diff --git a/circuits/cpp/src/aztec3/circuits/apps/contract.tpp b/circuits/cpp/src/aztec3/circuits/apps/contract.tpp index 60e36d1d806..cc335d5cd0a 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/contract.tpp +++ b/circuits/cpp/src/aztec3/circuits/apps/contract.tpp @@ -7,7 +7,7 @@ #include -#include +#include #include @@ -16,17 +16,17 @@ namespace aztec3::circuits::apps { using plonk::stdlib::witness_t; using plonk::stdlib::types::CircuitTypes; using NT = plonk::stdlib::types::NativeTypes; -using aztec3::circuits::abis::FunctionSignature; +using aztec3::circuits::abis::FunctionData; // using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; template void Contract::set_functions(std::vector> const& functions) { for (uint32_t i = 0; i < functions.size(); ++i) { const auto& function = functions[i]; - if (function_signatures.contains(function.name)) { + if (function_datas.contains(function.name)) { throw_or_abort("Name already exists"); } - function_signatures[function.name] = FunctionSignature{ + function_datas[function.name] = FunctionData{ .function_encoding = uint32(i), .is_private = function.is_private, .is_constructor = function.is_constructor, @@ -53,14 +53,14 @@ void Contract::import_contracts(std::vector get_function(std::string name) { return function_signature[name]; } +// FunctionData get_function(std::string name) { return function_data[name]; } -template FunctionSignature Contract::get_function_signature_by_name(std::string const& name) +template FunctionData Contract::get_function_data_by_name(std::string const& name) { - if (!function_signatures.contains(name)) { - throw_or_abort("function signature not found"); + if (!function_datas.contains(name)) { + throw_or_abort("function data not found"); } - return function_signatures[name]; + return function_datas[name]; } template void Contract::import_l1_function(L1FunctionInterfaceStruct const& l1_function_struct) diff --git a/circuits/cpp/src/aztec3/circuits/apps/function_execution_context.hpp b/circuits/cpp/src/aztec3/circuits/apps/function_execution_context.hpp index 01ebdf4bed2..2216f38b23a 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/function_execution_context.hpp +++ b/circuits/cpp/src/aztec3/circuits/apps/function_execution_context.hpp @@ -10,7 +10,7 @@ #include #include -#include +#include #include #include @@ -23,7 +23,7 @@ namespace aztec3::circuits::apps { using aztec3::circuits::abis::CallStackItem; using aztec3::circuits::abis::CallType; -using aztec3::circuits::abis::FunctionSignature; +using aztec3::circuits::abis::FunctionData; using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; using aztec3::circuits::abis::PrivateCircuitPublicInputs; @@ -115,11 +115,11 @@ template class FunctionExecutionContext { CallStackItem get_call_stack_item() { const NT::address& actual_contract_address = oracle.native_oracle.get_actual_contract_address(); - const FunctionSignature& function_signature = oracle.native_oracle.get_function_signature(); + const FunctionData& function_data = oracle.native_oracle.get_function_data(); return CallStackItem{ .contract_address = actual_contract_address, - .function_signature = function_signature, + .function_data = function_data, .public_inputs = get_final_private_circuit_public_inputs(), }; } @@ -136,12 +136,11 @@ template class FunctionExecutionContext { if (nested_exec_ctx != nullptr) { const NT::address& actual_contract_address = nested_exec_ctx->oracle.native_oracle.get_actual_contract_address(); - const FunctionSignature& function_signature = - nested_exec_ctx->oracle.native_oracle.get_function_signature(); + const FunctionData& function_data = nested_exec_ctx->oracle.native_oracle.get_function_data(); result[i] = CallStackItem{ .contract_address = actual_contract_address, - .function_signature = function_signature, + .function_data = function_data, .public_inputs = nested_exec_ctx->get_final_private_circuit_public_inputs(), }; } @@ -179,7 +178,7 @@ template class FunctionExecutionContext { // fr alternative_f_encoding_ct = fr(to_ct(composer, f_encoding)); // alternative_f_encoding_ct.fix_witness(); - const FunctionSignature f_function_signature_ct{ + const FunctionData f_function_data_ct{ // Note: we MUST .function_encoding = f_encoding_ct, .is_private = true, @@ -198,7 +197,7 @@ template class FunctionExecutionContext { NativeOracle f_oracle(oracle.native_oracle.db, f_contract_address.get_value(), - f_function_signature_ct.template to_native_type(), + f_function_data_ct.template to_native_type(), f_call_context_ct.template to_native_type(), oracle.get_msg_sender_private_key() .get_value() // TODO: consider whether a nested function should even be able to access @@ -242,7 +241,7 @@ template class FunctionExecutionContext { CallStackItem f_call_stack_item_ct{ .contract_address = f_contract_address, - .function_signature = f_function_signature_ct, + .function_data = f_function_data_ct, .public_inputs = f_public_inputs_ct, }; diff --git a/circuits/cpp/src/aztec3/circuits/apps/notes/note_interface.hpp b/circuits/cpp/src/aztec3/circuits/apps/notes/note_interface.hpp index c09510aff55..1ab3bed2ca0 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/notes/note_interface.hpp +++ b/circuits/cpp/src/aztec3/circuits/apps/notes/note_interface.hpp @@ -32,7 +32,7 @@ template class NoteInterface { // `note_preimage` members here (although that would require a NotePreimage template param). // This is all because the Opcodes actually _assume_ a particular constructor layout for each Note, as well as // _assume_ those two data members are always present. Having said that, there's still no way to actually enforce a - // constructor function signature of a derived class. + // constructor function data of a derived class. virtual void remove() = 0; diff --git a/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp b/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp index ebc47acca7e..f17cf148426 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp @@ -2,7 +2,7 @@ #include "contract.hpp" // #include -// #include +// #include // #include @@ -23,7 +23,7 @@ class escrow_tests : public ::testing::Test { const NT::address msg_sender = NT::fr( uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); - FunctionSignature function_signature{ + FunctionData function_data{ .function_encoding = 1, // TODO: deduce this from the contract, somehow. .is_private = true, .is_constructor = false, @@ -39,7 +39,7 @@ class escrow_tests : public ::testing::Test { .reference_block_num = 0, }; - return NativeOracle(db, contract_address, function_signature, call_context, msg_sender_private_key); + return NativeOracle(db, contract_address, function_data, call_context, msg_sender_private_key); }; }; diff --git a/circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp b/circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp index 2267a70a18c..e93f68566dd 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp @@ -1,7 +1,7 @@ #include "index.hpp" #include -#include +#include // #include @@ -23,7 +23,7 @@ TEST(private_to_private_function_call_tests, test_private_to_private_function_ca const NT::address msg_sender = uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL); - const FunctionSignature function_signature{ + const FunctionData function_data{ .function_encoding = 1, // TODO: deduce this from the contract, somehow. .is_private = true, .is_constructor = false, @@ -39,8 +39,7 @@ TEST(private_to_private_function_call_tests, test_private_to_private_function_ca .reference_block_num = 0, }; - NativeOracle fn1_oracle = - NativeOracle(db, contract_address, function_signature, call_context, msg_sender_private_key); + NativeOracle fn1_oracle = NativeOracle(db, contract_address, function_data, call_context, msg_sender_private_key); OracleWrapper fn1_oracle_wrapper = OracleWrapper(fn1_composer, fn1_oracle); FunctionExecutionContext fn1_exec_ctx(fn1_composer, fn1_oracle_wrapper); diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/.test.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/.test.cpp index 06c6ad426d3..1be1f52c2a0 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/.test.cpp @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include @@ -44,7 +44,7 @@ using aztec3::circuits::abis::CallContext; using aztec3::circuits::abis::CallStackItem; using aztec3::circuits::abis::CallType; using aztec3::circuits::abis::ContractDeploymentData; -using aztec3::circuits::abis::FunctionSignature; +using aztec3::circuits::abis::FunctionData; using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; using aztec3::circuits::abis::PrivateCircuitPublicInputs; using aztec3::circuits::abis::SignedTxRequest; @@ -89,7 +89,7 @@ TEST(private_kernel_tests, test_deposit) Composer deposit_composer = Composer("../barretenberg/cpp/srs_db/ignition"); DB db; - FunctionSignature function_signature{ + FunctionData function_data{ .function_encoding = 1, // TODO: deduce this from the contract, somehow. .is_private = true, .is_constructor = false, @@ -106,7 +106,7 @@ TEST(private_kernel_tests, test_deposit) }; NativeOracle deposit_oracle = - NativeOracle(db, escrow_contract_address, function_signature, call_context, msg_sender_private_key); + NativeOracle(db, escrow_contract_address, function_data, call_context, msg_sender_private_key); OracleWrapper deposit_oracle_wrapper = OracleWrapper(deposit_composer, deposit_oracle); FunctionExecutionContext deposit_ctx(deposit_composer, deposit_oracle_wrapper); @@ -132,7 +132,7 @@ TEST(private_kernel_tests, test_deposit) TxRequest deposit_tx_request = TxRequest{ .from = tx_origin, .to = escrow_contract_address, - .function_signature = function_signature, + .function_data = function_data, .args = deposit_public_inputs.args, .nonce = 0, .tx_context = @@ -167,7 +167,7 @@ TEST(private_kernel_tests, test_deposit) const CallStackItem deposit_call_stack_item{ .contract_address = deposit_tx_request.to, - .function_signature = deposit_tx_request.function_signature, + .function_data = deposit_tx_request.function_data, .public_inputs = deposit_public_inputs, }; diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp index 26b8eb15b33..5c27af89317 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp @@ -141,7 +141,7 @@ void validate_inputs(PrivateInputs const& private_inputs) { const auto& this_call_stack_item = private_inputs.private_call.call_stack_item; - this_call_stack_item.function_signature.is_private.assert_equal( + this_call_stack_item.function_data.is_private.assert_equal( true, "Cannot execute a non-private function with the private kernel circuit"); const auto& start = private_inputs.previous_kernel.public_inputs.end; @@ -185,7 +185,7 @@ void validate_inputs(PrivateInputs const& private_inputs) std::vector> recursive_case_conditions{ { private_inputs.previous_kernel.public_inputs.is_private == true, "Cannot verify a non-private kernel snark in the private kernel circuit" }, - { this_call_stack_item.function_signature.is_constructor == false, + { this_call_stack_item.function_data.is_constructor == false, "A constructor must be executed as the first tx in the recursion" }, { start_private_call_stack_length != 0, "Cannot execute private kernel circuit with an empty private call stack" } diff --git a/circuits/cpp/src/aztec3/constants.hpp b/circuits/cpp/src/aztec3/constants.hpp index 43a4284c08b..84c8aa9d028 100644 --- a/circuits/cpp/src/aztec3/constants.hpp +++ b/circuits/cpp/src/aztec3/constants.hpp @@ -44,7 +44,7 @@ enum GeneratorIndex { STATE_READ, STATE_TRANSITION, CONTRACT_ADDRESS, - FUNCTION_SIGNATURE, + FUNCTION_DATA, CALL_CONTEXT, CALL_STACK_ITEM, CALL_STACK_ITEM_2, // see function where it's used for explanation diff --git a/circuits/cpp/src/aztec3/oracle/oracle.hpp b/circuits/cpp/src/aztec3/oracle/oracle.hpp index 8c4dc6804b1..6fef0525997 100644 --- a/circuits/cpp/src/aztec3/oracle/oracle.hpp +++ b/circuits/cpp/src/aztec3/oracle/oracle.hpp @@ -3,7 +3,7 @@ #include "fake_db.hpp" #include -#include +#include #include @@ -15,7 +15,7 @@ namespace aztec3::oracle { using aztec3::circuits::abis::CallContext; -using aztec3::circuits::abis::FunctionSignature; +using aztec3::circuits::abis::FunctionData; using aztec3::circuits::apps::UTXOSLoadDatum; @@ -30,12 +30,12 @@ template class NativeOracleInterface { NativeOracleInterface(DB& db, NT::address const& actual_contract_address, - FunctionSignature const& function_signature, + FunctionData const& function_data, CallContext const& call_context, std::optional const& msg_sender_private_key = std::nullopt) : db(db) , actual_contract_address(actual_contract_address) - , function_signature(function_signature) + , function_data(function_data) , call_context(call_context) // , portal_contract_address(portal_contract_address) , msg_sender_private_key(msg_sender_private_key){}; @@ -63,7 +63,7 @@ template class NativeOracleInterface { NT::address get_actual_contract_address() { return actual_contract_address; }; - FunctionSignature get_function_signature() { return function_signature; }; + FunctionData get_function_data() { return function_data; }; CallContext get_call_context() { @@ -103,10 +103,10 @@ template class NativeOracleInterface { // untrustworthy oracle could give two different pieces of information. As long as this (trusted) oracle catches // double-queries, we can ensure the circuit we build doesn't query twice. - // Note: actual_contract_address and function_signature are NOT to be provided to the circuit, so don't include + // Note: actual_contract_address and function_data are NOT to be provided to the circuit, so don't include // getter methods for these in the OracleWrapper. NT::address actual_contract_address; // not to be confused with call_context.storage_contract_address; - FunctionSignature function_signature; + FunctionData function_data; CallContext call_context; // NT::fr portal_contract_address; @@ -114,7 +114,7 @@ template class NativeOracleInterface { // Ensure functions called only once: bool actual_contract_address_already_got = false; - bool function_signature_already_got = false; + bool function_data_already_got = false; bool call_context_already_got = false; // bool portal_contract_address_already_got = false; bool msg_sender_private_key_already_got = false; diff --git a/circuits/specs/src/architecture/app-circuits/public-input-abis.md b/circuits/specs/src/architecture/app-circuits/public-input-abis.md index f072342f6c9..3123aa145a4 100644 --- a/circuits/specs/src/architecture/app-circuits/public-input-abis.md +++ b/circuits/specs/src/architecture/app-circuits/public-input-abis.md @@ -154,9 +154,9 @@ PROBLEM: we might wish to _prove_ that a set of ACIR++ opcodes compiles to a par | Data Type | Description | | -------- | -------- | -| `privateConstructorPublicInputsHash` | So that vested parties (with access to the underlying public inputs) can confirm the constructor was executed with the correct params. Note: a user (or contract) cannot provide a conventional callStackItem to make a call to a private constructor, because the constructor's function signature isn't known until the contract address is known, but the contract address needs to contain the constructor arguments (i.e. the privateConstructorPublicInputsHash), so we'd get a cyclic dependency. | +| `privateConstructorPublicInputsHash` | So that vested parties (with access to the underlying public inputs) can confirm the constructor was executed with the correct params. Note: a user (or contract) cannot provide a conventional callStackItem to make a call to a private constructor, because the constructor's function data isn't known until the contract address is known, but the contract address needs to contain the constructor arguments (i.e. the privateConstructorPublicInputsHash), so we'd get a cyclic dependency. | | `publicConstructorPublicInputsHash` | As above, but public. | -| `privateConstructorVKHash` | The hash of the vk that was used to verify the private constructor, so that vested parties can confirm the correct function was run as a constructor (the vk itself may OPTIONALLY be submitted on-chain as calldata (for data availability), but some users might want to keep that private).
(Note, we can't use function signatures here, because the contract hasn't yet been deployed, so no contract address exists!) | +| `privateConstructorVKHash` | The hash of the vk that was used to verify the private constructor, so that vested parties can confirm the correct function was run as a constructor (the vk itself may OPTIONALLY be submitted on-chain as calldata (for data availability), but some users might want to keep that private).
(Note, we can't use function datas here, because the contract hasn't yet been deployed, so no contract address exists!) | | `publicConstructorVKHash` | As above, but public. | | `contractAddress` | The proposed contract address that this new contract will be deployed to. | | `salt` | The salt used in the preimage of the contractAddress derivation - to have some control over the contract address | diff --git a/circuits/specs/src/architecture/contracts/contracts.md b/circuits/specs/src/architecture/contracts/contracts.md index 56f18859669..ec5d9eefcc4 100644 --- a/circuits/specs/src/architecture/contracts/contracts.md +++ b/circuits/specs/src/architecture/contracts/contracts.md @@ -12,7 +12,7 @@ In the 'conventional' world of Ethereum, a transaction is completed when the ori As you might have guessed, 'functions' in Aztec's L2 will actually be circuits. Execution of a function will be performed by generating a zk-snark to prove its correct execution with a particular set of inputs. If a function makes a call to another function, a proof of each function's execution must be made _separately_. We need to then 'connect' those two proofs in a way which says "this function made a call to this other function, it passed-in these arguments and received these values in return". To do this, we make use of zk-snark recursion and a special 'callstack'. Notice that if each function must be executed as a standalone lego brick (a proof), then all input arguments and return values of every function call in a transaction must be known ahead of time, so that each proof can be generated separately. That'll be a fun engineering challenge! -This is all expanded-on later in this book. When a function calls another function, we'll add details of the function _being called_ to a callstack[^1]: the contract address, the function signature, arguments, return values and a call context. We describe a 'Kernel Snark' which: pops the first proof off the callstack, verifies it, then adds new callstack items for any functions which the first function called. Kernel Snark execution proceeds recursively: the next Kernel Snark will verify the previous Kernel Snark's correctness, then will pop the next proof off the callstack, and add even more callstack items for any functions which this latest function has called. The 'stitching together' of arguments passed to functions and values returned from functions is implicit in this process, since each callstack item contains this information. +This is all expanded-on later in this book. When a function calls another function, we'll add details of the function _being called_ to a callstack[^1]: the contract address, the function data, arguments, return values and a call context. We describe a 'Kernel Snark' which: pops the first proof off the callstack, verifies it, then adds new callstack items for any functions which the first function called. Kernel Snark execution proceeds recursively: the next Kernel Snark will verify the previous Kernel Snark's correctness, then will pop the next proof off the callstack, and add even more callstack items for any functions which this latest function has called. The 'stitching together' of arguments passed to functions and values returned from functions is implicit in this process, since each callstack item contains this information. This protocol describes 'private states' (a state whose value is known by a single user) and 'public states' (states whose values are visible to everyone). To edit these different states, we need two different kinds of circuits: private circuits and public circuits. diff --git a/circuits/specs/src/architecture/contracts/transactions.md b/circuits/specs/src/architecture/contracts/transactions.md index 71e407611a6..be3b818d611 100644 --- a/circuits/specs/src/architecture/contracts/transactions.md +++ b/circuits/specs/src/architecture/contracts/transactions.md @@ -3,7 +3,7 @@ A transaction always comes from a user account, and must be signed by that user's aztec private key. A transaction represents a call to some function of some contract, passing some parameters, and specifying some fee. - + Contracts can be deployed with a special type of call (a contractDeploymentCall). @@ -14,8 +14,8 @@ Contracts can be deployed with a special type of call (a contractDeploymentCall) | Value | Description | | --- | --- | | `from`: `aztecAddress` | The aztec address of the user signing the tx. | -| `to`: [`contractAddress`](#contractaddress) | The contract address of the contract being called.
For calls which deploy a contract, this is `0` (context will be understood from the fact this will be popped of a contractDeploymentCallStack).
For calls to private constructors, this is not known when generating the private kernel proof which verifies the private constructor (as the contract won't yet have been assigned an address), so is `0` (in combination with `functionSignature.isConstructor == true`). | -| `functionSignature`: [`FunctionSignature`](#functionsignature) | An identifier for the function being called. | +| `to`: [`contractAddress`](#contractaddress) | The contract address of the contract being called.
For calls which deploy a contract, this is `0` (context will be understood from the fact this will be popped of a contractDeploymentCallStack).
For calls to private constructors, this is not known when generating the private kernel proof which verifies the private constructor (as the contract won't yet have been assigned an address), so is `0` (in combination with `functionData.isConstructor == true`). | +| `functionData`: [`FunctionData`](#functiondata) | An identifier for the function being called. | | `args`: `Array[Field]` | Arguments being passed into the function by this tx. | | `nonce`: `Field` | Useful for overriding a tx which has already been sent to the pool. Note: for private function calls, this _must not_ be incremented sequentially, but should be random-looking.
`0` if this is a fee-paying tx to accompany a 'proper' tx. | | `txContext`: [`TxContext`](#txcontext) | Miscellaneous data relating to this tx, which might be useful for all subsequent nested function calls, and kernel circuits of this tx. | @@ -28,13 +28,13 @@ Contracts can be deployed with a special type of call (a contractDeploymentCall) | --- | --- | | `contractAddress`: `Field` | See [here](deployment.md#l2-contract-address) for contract address derivation. | -## `FunctionSignature` +## `FunctionData` | Value | Description | | --- | --- | | `vkIndex`: `Field` | The position of the vk (i.e. its leaf index) in this contract's `vkTree`. This is used to identify the function being called. It is derived as the first 4 bytes of the hash of the abi encoding of the function, similar to Solidity. The reason we do this, is so that a vkIndex can be derived from a contract interface, regardless of the ordering of that interface's functions. | | `isPrivate`: `Bool` | A bit describing if this function is public or private. | -| `isConstructor`: `Bool` | If a function is a constructor, it's going to be called by the Contract Deployment Kernel circuit. This flag notifies the kernel circuit that this private circuit is being executed as a constructor for the deployment of a new contract, and so the following public inputs of this private circuit MUST be revealed to the public kernel circuit (so that the Contract Deployment kernel circuit may validate them):
  • `callStackItemHash` - so that the Contract Deployment kernel circuit (and interested parties) can be convinced that the constructor was run with the correct set of inputs (this might need to exposed all the way to L1)
  • `vkHash` - so that the Contract Deplyment constructor can validate that the correct function was executed. (Notice, we don't use a conventional `functionSignature` because we won't be adding constructor vkHashes to the vkTree). Notice, by design, this doesn't reveal any details to observers about the nature of the executed function. We might want to optionally allow the underlying vk to be broadcast (and hence we might need to expose this vkHash all the way to L1).
  • `emittedPublicInputs` - to pass particular inputs to L1.
| +| `isConstructor`: `Bool` | If a function is a constructor, it's going to be called by the Contract Deployment Kernel circuit. This flag notifies the kernel circuit that this private circuit is being executed as a constructor for the deployment of a new contract, and so the following public inputs of this private circuit MUST be revealed to the public kernel circuit (so that the Contract Deployment kernel circuit may validate them):
  • `callStackItemHash` - so that the Contract Deployment kernel circuit (and interested parties) can be convinced that the constructor was run with the correct set of inputs (this might need to exposed all the way to L1)
  • `vkHash` - so that the Contract Deplyment constructor can validate that the correct function was executed. (Notice, we don't use a conventional `functionData` because we won't be adding constructor vkHashes to the vkTree). Notice, by design, this doesn't reveal any details to observers about the nature of the executed function. We might want to optionally allow the underlying vk to be broadcast (and hence we might need to expose this vkHash all the way to L1).
  • `emittedPublicInputs` - to pass particular inputs to L1.
| _Note_: the `contractTree` is append-only, so individual verification keys can't be 'replaced' for bug-fixes etc.; the entire contract (a `vkTree`) would need to be re-deployed to the next available slot in the `contractTree`. Such re-deployments, of course, would change the contract address, unless using a proxy pattern. @@ -64,11 +64,11 @@ Currently, the fee model is inspired by EIP-1559. | Value | Description | | --- | --- | -| `calledFromL1`: `Bool` | Is this tx being sent as a continuation of some L1 tx which made a call to L2? If the L1 contract wants to call a specific L2 circuit, then the function signature needs to be revealed on-chain so that it can be checked that the correct, intended function was executed.

Notifies the private kernel circuit that an L1 contract wants to call this specific private L2 circuit, and so the following MUST be revealed to the public kernel circuit:
  • `functionSignature` - needed so the L1 contract can confirm the intended function was executed on L2. Although a callHash contains the functionSignature, the L1 contract wouldn't (cheaply) be able to unpack the callHash. So we expose the function signature as well to keep costs down. Although this leaks the function which was called, there's no way around that; this is an L1 -> L2 call after all.
  • `callHash` - used as a 'lookup' key. The RollupProcessor will store this `callHash`, and await an L2 tx with this `callHash` before triggering a callback to the L1 contract which made this L1 -> L2 call in the first place.
  • `emittedPublicInputs` - needed so that a set of values can be emitted by an L2 function and exposed to L1. It would be too expensive to unpack the callHash and extract all of the custom public inputs of a circuit. This is much cheaper, and is very similar to how the EVM exposes only a few values (via event emissions) to JavaScript (for example).


We need this convoluted process, because the RollupProcessor has to be _sure_ an L1 fee has been set-aside for them, before they add any corresponding L2 states. | +| `calledFromL1`: `Bool` | Is this tx being sent as a continuation of some L1 tx which made a call to L2? If the L1 contract wants to call a specific L2 circuit, then the function data needs to be revealed on-chain so that it can be checked that the correct, intended function was executed.

Notifies the private kernel circuit that an L1 contract wants to call this specific private L2 circuit, and so the following MUST be revealed to the public kernel circuit:
  • `functionData` - needed so the L1 contract can confirm the intended function was executed on L2. Although a callHash contains the functionData, the L1 contract wouldn't (cheaply) be able to unpack the callHash. So we expose the function data as well to keep costs down. Although this leaks the function which was called, there's no way around that; this is an L1 -> L2 call after all.
  • `callHash` - used as a 'lookup' key. The RollupProcessor will store this `callHash`, and await an L2 tx with this `callHash` before triggering a callback to the L1 contract which made this L1 -> L2 call in the first place.
  • `emittedPublicInputs` - needed so that a set of values can be emitted by an L2 function and exposed to L1. It would be too expensive to unpack the callHash and extract all of the custom public inputs of a circuit. This is much cheaper, and is very similar to how the EVM exposes only a few values (via event emissions) to JavaScript (for example).


We need this convoluted process, because the RollupProcessor has to be _sure_ an L1 fee has been set-aside for them, before they add any corresponding L2 states. | | `calledFromPublicL2`: `Bool` | Is this tx being sent as a continuation of some public L2 tx which made a call to Private L2? | | `isCallback`: `Bool` | Is this tx being sent as a continuation of some L2 --> L1 call, which now needs to continue L2 execution? | | `resultsTreeLeafIndex`: `Field` | Not sure if we want this or some kind of tx hash. If executing a callback, the user/dapp needs to feed-in info about the original call they made, so that the Private Client can find the right results tree leaf to use. | -| `isFeePaymentTx`: `Bool` | Is this tx the 'fee payment' component of some other tx? Notifies the kernel circuit that the following public inputs of this private circuit MUST be revealed to the public kernel circuit:
  • `functionSignature` - so that the rollup provider can see how they're to be paid
  • `emittedPublicInputs` - so that the rollup provider can validate the amount they'll be paid (they'll need to be provided with the underlying public inputs separately, to validate the hash).
| +| `isFeePaymentTx`: `Bool` | Is this tx the 'fee payment' component of some other tx? Notifies the kernel circuit that the following public inputs of this private circuit MUST be revealed to the public kernel circuit:
  • `functionData` - so that the rollup provider can see how they're to be paid
  • `emittedPublicInputs` - so that the rollup provider can validate the amount they'll be paid (they'll need to be provided with the underlying public inputs separately, to validate the hash).
| | `feeData`: [`FeeData`](#feedata) | Empty if `isFeePaymentTx == false`. Conveys information about the fee being paid for this tx. | | `referenceRollupNum`: `Field` | The rollup number which should be used if referring to any historic tree values. Useful if the proof needs to use a particular tree state snapshot of a particular historic rollup. | @@ -103,7 +103,7 @@ The format varies, depending on the type of call being made. | Data | Description | | -------- | -------- | | `contractAddress`: [`ContractAddress`](#contractaddress) | The address of the contract being called. | -| `functionSignature`: [`FunctionSignature`](#functionsignature) | The 'function signature' of the circuit being called. | +| `functionData`: [`FunctionData`](#functiondata) | The 'function data' of the circuit being called. | | `publicInputs`: [`PrivateCircuitPublicInputs`](../app-circuits/public-input-abis.md#privatecircuitpublicinputs) | The public inputs of the call, which can be calculated in advanced through simulation. | ### `PublicCallStackItem` @@ -111,7 +111,7 @@ The format varies, depending on the type of call being made. | Data | Description | | -------- | -------- | | `contractAddress`: [`ContractAddress`](#contractaddress) | The address of the contract being called. | -| `functionSignature`: [`FunctionSignature`](#functionsignature) | The 'function signature' of the circuit being called. | +| `functionData`: [`FunctionData`](#functiondata) | The 'function data' of the circuit being called. | | `publicInputs`: [`PublicCircuitPublicInputs`](../app-circuits/public-input-abis.md#publiccircuitpublicinputs) | The public inputs of the call, which can be calculated in advanced through simulation.
**Note:** for the public circuit ABI, _not all_ public inputs can be included in `publicInputs`, since variables read/written from/to the publicDataTree are not known at the time the call is made by the user (or by another circuit). See the Public Circuit ABI section. | > Note: A `proof` is not included in the call stack item. For public calls, the proof is not known at the time the call is made, because public proofs are generated by the rollup provider. For private calls, the proof isn't needed for a call stack item to be unique; the input nullifiers and output commitments ensure uniqueness of calls. :question: Q: is a private call which doesn't read/modify state nonsensical (if so, that's good - we can reject such calls (they won't have any nullifiers or commitments), thereby ensuring uniqueness of private callStack items)? @@ -120,11 +120,11 @@ The format varies, depending on the type of call being made. > Note: Certain public inputs are omitted when calculating the publicInputsHash for a callback's call stack item, because such inputs will depend on the L1 Result. -> Note: The `contractAddress` is sometimes set to `0` in the `functionSignature` if a function is calling another function of the same contract. (Functions cannot know their own contract address, since it is set after the function's circuit has been compiled). The kernel circuits are capable of interpreting this. Examples of a function calling another function of the same contract are: a private-to-public call; and a call to a callback function. +> Note: The `contractAddress` is sometimes set to `0` in the `functionData` if a function is calling another function of the same contract. (Functions cannot know their own contract address, since it is set after the function's circuit has been compiled). The kernel circuits are capable of interpreting this. Examples of a function calling another function of the same contract are: a private-to-public call; and a call to a callback function. ### `ContractDeploymentCallStackItem` -An instruction to deploy a contract is also expressed through a call, but the call stack item's data is slightly abbreviated (no function signature): +An instruction to deploy a contract is also expressed through a call, but the call stack item's data is slightly abbreviated (no function data): | Data | Description | | -------- | -------- | @@ -162,7 +162,7 @@ When a function makes a call to another 'layer', it can specify a success or fai #### `callStackItemHash` -`callStackItemHash := hash(functionSignature, publicInputsHash, callContext, etc.)` +`callStackItemHash := hash(functionData, publicInputsHash, callContext, etc.)` a.k.a. `callHash` - similar to Ethereum's notion of a txHash. We also use the term `callbackCallHash` to refer to the `callHash` of a callback function (which has certain public inputs omitted when calculating the call stack item). @@ -181,7 +181,7 @@ So to call F1, F0 adds a callstack item to its public inputs representing a call ``` callStackItem = { - functionSignature, + functionData, publicInputsHash, callContext, etc. diff --git a/circuits/specs/src/architecture/kernel-circuits/contract-deployment-kernel.md b/circuits/specs/src/architecture/kernel-circuits/contract-deployment-kernel.md index fe1e43d3f38..8756c01e16a 100644 --- a/circuits/specs/src/architecture/kernel-circuits/contract-deployment-kernel.md +++ b/circuits/specs/src/architecture/kernel-circuits/contract-deployment-kernel.md @@ -78,7 +78,7 @@ You'll notice that the private/public inputs for this kernel circuit are a super | `}],` | | | `- optionallyRevealedData: [{` | Some values from a public call can be optionally revealed to the Contract Deployment kernel circuit / L1, depending on bools of the public circuit ABI. For some/every public call, each 'object' in this 'array' contains the following fields (some of which might be 0, depending on the bools) (note: there might be more efficient ways to encode this data - this is just for illustration): | | `- - callStackItemHash,` | Serves as a 'lookup key' of sorts. | -| `- - functionSignature,` | | +| `- - functionData,` | | | `- - emittedPublicInputs: [_, _, _, _],` | | | `- - vkHash,` | | | `- - portalContractAddress,` | | @@ -171,7 +171,7 @@ Validate the next call on the contractDeploymentCallStack: * Verify `start.contractDeploymentCallStack.length > 0` and (if not already done during the 'Base Case' logic above), pop 1 item off of `start.contractDeploymentCallStack` - call it `contractDeploymentCall`. * Validate that this newly-popped `contractDeploymentCallStackItemHash` corresponds to the `contractDeploymentCall` data passed into this circuit: * Calculate `contractDeploymentCallPublicInputsHash := hash(contractDeploymentCall.publicInputs);` - * Verify that `contractDeploymentCallStackItemHash == hash(contractDeploymentCall.functionSignature, contractDeploymentCallPublicInputsHash, contractDeploymentCall.callContext, etc...)` + * Verify that `contractDeploymentCallStackItemHash == hash(contractDeploymentCall.functionData, contractDeploymentCallPublicInputsHash, contractDeploymentCall.callContext, etc...)` Deploy the contract: - Let `deployerAddress := contractDeploymentCall.callContext.msgSender` @@ -208,12 +208,12 @@ Verify the private constructor's kernel snark: - We need to reconcile the exposed callStackItemHash of the actually-executed constructor of the private kernel snark, with what we'd expect: - Let `actualCallStackItemHash = privateConstructorKernel.publicInputs.end.optionallyRevealedData[0].callStackItemHash;` (the `0`-th value will be the constructor's callStack item, otherwise something has gone wrong). - Let's try to reconcile that `actualCallStackItemHash` with the hash we'd expect: `expectedCallStackItemHash`: - - Let `expectedFunctionSignature := concat(newContractAddress, 0, false, true, false)`. Note: the `0` in the 2nd parameter might suggest we want to call the function whose vkIndex is at position `0` - but the `isConstructor = true` tells the kernel circuit that we're calling a constructor; not looking up a deployed function. Note: this line is justification for `isConstructor` being part of the functionSignature. If it were alternatively part of the `privateConstructorPublicInputsHash`, we'd have to do _much_ more hashing to extract its value here. + - Let `expectedFunctionData := concat(newContractAddress, 0, false, true, false)`. Note: the `0` in the 2nd parameter might suggest we want to call the function whose vkIndex is at position `0` - but the `isConstructor = true` tells the kernel circuit that we're calling a constructor; not looking up a deployed function. Note: this line is justification for `isConstructor` being part of the functionData. If it were alternatively part of the `privateConstructorPublicInputsHash`, we'd have to do _much_ more hashing to extract its value here. - Let `expectedPublicInputsHash := contractDeploymentCall.publicInputs.privateConstructorPublicInputsHash` - Let `expectedCallContext := { msgSender: contractDeploymentCall.callContext.msgSender, storageContractAddress: newContractAddress }`. Notice: The calling of a constructor is as though called by the person/contract who called to deploy the contract in the first place. - Let `expectedIsDelegateCall = false`, `expectedIsStaticCall = false`. - Hash it all together: - - `expectedCallStackItemHash = hash(expectedFunctionSignature, expectedPublicInputsHash, expectedCallContext, false, false)` + - `expectedCallStackItemHash = hash(expectedFunctionData, expectedPublicInputsHash, expectedCallContext, false, false)` - Assert `actualCallStackItemHash == expectedCallStackItemHash`. - We need to reconcile the exposed `privateConstructorVKHash` of the actually-executed constructor of the private kernel snark, with what we'd expect: - Let `actualPrivateConstructorVKHash = privateConstructorKernel.publicInputs.end.optionallyRevealedData[0].vkHash` (the `0`-th value will be the constructor's callStack item, otherwise something has gone wrong). @@ -235,12 +235,12 @@ Verify the public constructor's kernel snark: - We need to reconcile the exposed callStackItemHash of the actually-executed constructor of the public kernel snark, with what we'd expect: - Let `actualCallStackItemHash = publicConstructorKernel.publicInputs.end.optionallyRevealedData[0].callStackItemHash;` (the `0`-th value will be the constructor's callStack item, otherwise something has gone wrong). - Let's try to reconcile that `actualCallStackItemHash` with the hash we'd expect: `expectedCallStackItemHash`: - - Let `expectedFunctionSignature := concat(newContractAddress, 0, false, true, false)`. Note: the `0` in the 2nd parameter might suggest we want to call the function whose vkIndex is at position `0` - but the `isConstructor = true` tells the kernel circuit that we're calling a constructor; not looking up a deployed function. Note: this line is justification for `isConstructor` being part of the functionSignature. If it were alternatively part of the `publicConstructorPublicInputsHash`, we'd have to do _much_ more hashing to extract its value here. + - Let `expectedFunctionData := concat(newContractAddress, 0, false, true, false)`. Note: the `0` in the 2nd parameter might suggest we want to call the function whose vkIndex is at position `0` - but the `isConstructor = true` tells the kernel circuit that we're calling a constructor; not looking up a deployed function. Note: this line is justification for `isConstructor` being part of the functionData. If it were alternatively part of the `publicConstructorPublicInputsHash`, we'd have to do _much_ more hashing to extract its value here. - Let `expectedPublicInputsHash := contractDeploymentCall.publicInputs.publicConstructorPublicInputsHash` - Let `expectedCallContext := { msgSender: contractDeploymentCall.callContext.msgSender, storageContractAddress: newContractAddress }`. Notice: The calling of a constructor is as though called by the person/contract who called to deploy the contract in the first place. - Let `expectedIsDelegateCall = false`, `expectedIsStaticCall = false`. - Hash it all together: - - `expectedCallStackItemHash = hash(expectedFunctionSignature, expectedPublicInputsHash, expectedCallContext, false, false)` + - `expectedCallStackItemHash = hash(expectedFunctionData, expectedPublicInputsHash, expectedCallContext, false, false)` - Assert `actualCallStackItemHash == expectedCallStackItemHash`. - We need to reconcile the exposed `publicConstructorVKHash` of the actually-executed constructor of the public kernel snark, with what we'd expect: - Let `actualPublicConstructorVKHash = publicConstructorKernel.publicInputs.end.optionallyRevealedData[0].vkHash` (the `0`-th value will be the constructor's callStack item, otherwise something has gone wrong). @@ -282,8 +282,8 @@ Update the `end` values: - If `newCallStackItem.isDelegateCall == true`: - Assert `newCallStackItem.callContext == contractDeploymentCall.callContext` - Else: - - Assert `newCallStackItem.callContext.msgSender == contractDeploymentCall.functionSignature.contractAddress` - - Assert `newCallStackItem.callContext.storageContractAddress == newCallStackItem.functionSignature.contractAddress` + - Assert `newCallStackItem.callContext.msgSender == contractDeploymentCall.functionData.contractAddress` + - Assert `newCallStackItem.callContext.storageContractAddress == newCallStackItem.functionData.contractAddress` - Push the contents of these call stacks onto the kernel circuit's `end.contractDeploymentCallStack` and `end.l1CallStack`. - It would be nice if these 'pushes' could result in tightly-packed stacks. diff --git a/circuits/specs/src/architecture/kernel-circuits/private-kernel.md b/circuits/specs/src/architecture/kernel-circuits/private-kernel.md index 538dda27980..ee75d5423e0 100644 --- a/circuits/specs/src/architecture/kernel-circuits/private-kernel.md +++ b/circuits/specs/src/architecture/kernel-circuits/private-kernel.md @@ -55,7 +55,7 @@ Some values from a private call can be optionally revealed to the 'public world' | Value | Description | | -------- | -------- | | `callStackItemHash`: `Field` | Serves as a 'lookup key' of sorts, for when an L1 function has made a call to a L2 function, and will need to validate that the correct call was made. | -| `functionSignature`: [`FunctionSignature`](../contracts/transactions.md#functionsignature) | | +| `functionData`: [`FunctionData`](../contracts/transactions.md#functiondata) | | | `emittedEvents` | Emitting data to another layer. | | `vkHash` | | | `portalContractAddress` | Needed when making a call from L2 to L1. | @@ -132,7 +132,7 @@ Base case: - TBD: to allow the option of a fee payment, we might require `start.privateCallStack.length` to be "1" or "2, where one tx has an `isFeePayment` indicator". ✅ * Pop the only (TBD) `privateCallHash` off the `start.privateCallStack`. ✅ - Validate that `hash(privateCall.callStackItem) == privateCallHash` ✅ - - If `privateCall.callStackItem.functionSignature.isConstructor == true`: ❌ + - If `privateCall.callStackItem.functionData.isConstructor == true`: ❌ - THIS SECTION IS OUT OF DATE - IGNORE! - then we don't need a signature from the user, since this entire 'callstack' has been instantiated by a Contract Deployment kernel snark (which itself will have been signed by the user). - Set `constants.recursionContext.isConstructor := true` - This public input will percolate to -- and be checked by -- the Contract Deployment Kernel Circuit which calls this constructor. This check is required to prevent a person from circumventing the ECDSA signature check by simply setting `isConstructor = true` when making a private call. If this aggregated kernel snark reaches the rollup circuit without this flag being reset to `false` by the Contract Deployment Kernel Circuit (to say "yes, this kernel was indeed a constructor for a Contract Deployment Kernel Circuit"), then the entire tx will be rejected by the rollup circuit. @@ -147,7 +147,7 @@ Base case: Recursion: * If `previousKernel.publicInputs.isPrivate && start.privateCallCount > 0`: ✅ - - If `privateCall.callStackItem.functionSignature.isConstructor == true`: + - If `privateCall.callStackItem.functionData.isConstructor == true`: - Revert - only the first call in the kernel recursion can be a constructor. * Verify the `previousKernel.proof` using the `previousKernel.vk` ✅ * Validate that the `previousKernel.vk` is a valid private kernel VK with a membership check: @@ -163,14 +163,14 @@ Recursion: Verify the next call on the callstack: * Verify `start.privateCallStack.length > 0` and (if not already done during the 'Base Case' logic above, depending on how we do the implementation), pop 1 item off of `start.privateCallStack` (a `privateCallStackItemHash`) -* Validate that `privateCall.callStackItem.functionSignature.isPrivate == true` (otherwise this is the wrong type of kernel circuit to be using). +* Validate that `privateCall.callStackItem.functionData.isPrivate == true` (otherwise this is the wrong type of kernel circuit to be using). * Validate that this newly-popped `privateCallStackItemHash` corresponds to the `privateCall` data passed into this circuit: * Calculate `privateCallPublicInputsHash := hash(privateCall.callStackItem.publicInputs);` * Verify that `privateCallStackItemHash == hash(privateCall.callStackItem)` * Recall, the structure of a [callstack item](../contracts/transactions.md#privatecallstackitem). * Verify the correctness of `(proof, privateCallPublicInputsHash)` using the `vk`. * Validate the `vk` actually represents the function that is purportedly being executed: - * Extract the `contractAddress` and `vkIndex` from `privateCall.functionSignature`. + * Extract the `contractAddress` and `vkIndex` from `privateCall.functionData`. * Compute `vkHash := hash(vk)` * Compute the `vkRoot` of this function's contract using the `vkIndex`, `vkPath`, and `vkHash`. * Compute the contract's leaf in the `contractTree`: @@ -201,15 +201,15 @@ Update the `end` values: * Extract the private call's `privateCallStack`, `publicCallStack`, `contractDeploymentCallStack`. - Validate the call contexts of these calls: - For each `newCallStackItem` in `privateCallStack`, `publicCallStack`, `contractDeploymentCallStack` and `partialL1CallStack`. - - If `newCallStackItem.functionSignature.contractAddress == 0`: + - If `newCallStackItem.functionData.contractAddress == 0`: - Then this `0` is understood to be a call to `address(this)`, which cannot be populated by the app's circuit itself. - We must mutate the contract address to be that of the `privateCall`. - - Mutation: Set `newCallStackItem.functionSignature.contractAddress = privateCall.functionSignature.contractAddress` + - Mutation: Set `newCallStackItem.functionData.contractAddress = privateCall.functionData.contractAddress` - If `newCallStackItem.isDelegateCall == true`: - Assert `newCallStackItem.callContext == publicCall.callContext` - Else: - - Assert `newCallStackItem.callContext.msgSender == publicCall.functionSignature.contractAddress` - - Assert `newCallStackItem.callContext.storageContractAddress == newCallStackItem.functionSignature.contractAddress` + - Assert `newCallStackItem.callContext.msgSender == publicCall.functionData.contractAddress` + - Assert `newCallStackItem.callContext.storageContractAddress == newCallStackItem.functionData.contractAddress` - For each `partialL1CallStackItem` in the `partialL1CallStack` (index `i`): - Ensure that the call is being sent to the associated portal contract address, by adding the `portalContractAddress` here: - Let `l1CallStackItem := keccak(portalContractAddress, partialL1CallStackItem)` @@ -217,19 +217,19 @@ Update the `end` values: - As per the commitments/nullifiers bullet immediately above, it would be nice if these 'pushes' could result in tightly-packed stacks. - Determine whether any values need to be optionally revealed to the 'public world', by referring to the `publicCall`'s booleans: - Let `optionallyRevealedData = {};` - - If `privateCall.functionSignature.isConstructor`, set: + - If `privateCall.functionData.isConstructor`, set: - `optionallyRevealedData.callStackItemHash = privateCallStackItemHash;` - `optionallyRevealedData.vkHash = vkHash;` - `optionallyRevealedData.emittedPublicInputs = privateCall.publicInputs.emittedPublicInputs;` - If `isFeePayment`, set: - `optionallyRevealedData.callStackItemHash = privateCallStackItemHash;` - - `optionallyRevealedData.functionSignature = privateCall.functionSignature;` + - `optionallyRevealedData.functionData = privateCall.functionData;` - `optionallyRevealedData.emittedPublicInputs = privateCall.publicInputs.emittedPublicInputs;` - If `payFeeFromL1`, set: - `optionallyRevealedData.callStackItemHash = privateCallStackItemHash;` - If `calledFromL1`, set: - `optionallyRevealedData.callStackItemHash = privateCallStackItemHash;` - - `optionallyRevealedData.functionSignature = privateCall.functionSignature;` + - `optionallyRevealedData.functionData = privateCall.functionData;` - `optionallyRevealedData.emittedPublicInputs = privateCall.publicInputs.emittedPublicInputs;` - `optionallyRevealedData.portalContractAddress = portalContractAddress;` // TODO: we need to check this portal contract address is the correct one within this kernel circuit (with a membership check). We need to decide where in L2 this should be stored: either in the contract tree or in the public data tree (e.g. at storage slot 0 for each contract). Argh, it cannot be in the public data tree, because the private kernel circuit cannot access that :heavy_exclamation_mark: - Push the `optionallyRevealedData` onto the `optionallyRevealedData`. diff --git a/circuits/specs/src/architecture/kernel-circuits/public-kernel.md b/circuits/specs/src/architecture/kernel-circuits/public-kernel.md index f96fb878fe8..69192568950 100644 --- a/circuits/specs/src/architecture/kernel-circuits/public-kernel.md +++ b/circuits/specs/src/architecture/kernel-circuits/public-kernel.md @@ -39,7 +39,7 @@ Public kernel proofs are generated recursively until `end.publicCallStack.length | `- vkPath` | We can support multiple 'sizes' of kernel circuit (i.e. kernel circuits with varying numbers of public inputs) if we store all of the VKs of such circuits as vkHashes in a little Merkle tree. This path is the sibling path from the `previousKernel.vk`'s leaf to the root of such a tree. | | `}` | | | `publicCall: {` | Data relating to the next public callstack item that we're going to pop off the callstack and verify within this snark. Recall we're representing items in the callstack as a `callStackItemHash`. We'll pass the unpacked data here, for validation within this kernel circuit. | -| `- functionSignature,` | 64-bits (see earlier section) | +| `- functionData,` | 64-bits (see earlier section) | | `- publicInputs: {...},` | Rather than pass in the `publicInputsHash`, we pass in its preimage here (we'll hash it within this kernel circuit). This is _all_ of the data listed in the Public Circuit ABI's table of public inputs (see earlier section). | | `- callContext: {...},` | | | `- isDelegateCall,` | | @@ -72,7 +72,7 @@ Public kernel proofs are generated recursively until `end.publicCallStack.length | `}],` | | | `- optionallyRevealedData: [{` | Some values from a public call can be optionally revealed to the Contract Deployment kernel circuit / L1, depending on bools of the public circuit ABI. For some/every public call, each 'object' in this 'array' contains the following fields (some of which might be 0, depending on the bools) (note: there might be more efficient ways to encode this data - this is just for illustration): | | `- - callStackItemHash,` | Serves as a 'lookup key' of sorts. | -| `- - functionSignature,` | | +| `- - functionData,` | | | `- - emittedPublicInputs: [_, _, _, _],` | | | `- - vkHash,` | | | `- - portalContractAddress,` | | @@ -121,7 +121,7 @@ Public kernel proofs are generated recursively until `end.publicCallStack.length * `require(start.publicCallStack.length > 0)` Base case (verifying a private kernel snark): * if `(previousKernel.proof && previousKernel.publicInputs.isPrivate)` - - `require(privateCall.functionSignature.isConstructor == false && privateCall.functionSignature.isCallback == false)`: + - `require(privateCall.functionData.isConstructor == false && privateCall.functionData.isCallback == false)`: - only the first call in the kernel recursion can be a constructor or a callback. * Verify the (`previousKernel.proof`, `previousKernel.publicInputs`) using the `previousKernel.vk`. * Validate that the `previousKernel.vk` is a valid _private_ kernel VK with a membership check: @@ -140,7 +140,7 @@ Base case (verifying a private kernel snark): * Validate that `start.publicCallStack.length == 1 && start.contractDeploymentCallStack.length == 0 && start.l1CallStack.length == 0` - TBD: to allow the option of a fee payment, we might require `start.publicCallStack.length` to be "1" or "2, where one tx has an `isFeePayment` indicator". We could even allow any number of initial private calls on the stack, but that's a pretty big deviation from the ethereum tx model. * Pop the only (TBD) `publicCallStackItemHash` off the `start.publicCallStack`. - - If `publicCall.functionSignature.isConstructor == true`: + - If `publicCall.functionData.isConstructor == true`: - then we don't need a signature from the user, since this entire 'callstack' has been instantiated by a Contract Deployment kernel snark (which itself will have been signed by the user). - Set `isConstructorRecursion := true` - This public input will percolate to, and be checked by. the Contract Deployment Kernel Circuit which calls this constructor. This check is required to prevent a person from circumventing the ECDSA signature check by simply setting `isConstructor = true` when making a private call. If this aggregated kernel snark reaches the rollup circuit without this flag being reset to `false` by the Contract Deployment Kernel Circuit (to say "yes, this kernel was indeed a constructor for a Contract Deployment Kernel Circuit"), then the entire tx will be rejected by the rollup circuit. - Else: @@ -150,8 +150,8 @@ Base case (verifying a private kernel snark): - If `publicCall.isDelegateCall == true || publicCall.isStaticCall == true`: - Revert - a user cannot make a delegateCall or staticCall. - Else: - - Assert `publicCall.callContext.storageContractAddress == publicCall.functionSignature.contractAddress` - - If `publicCall.functionSignature.isCallback == true`: + - Assert `publicCall.callContext.storageContractAddress == publicCall.functionData.contractAddress` + - If `publicCall.functionData.isCallback == true`: - Set `isCallbackRecursion = true;` - this can only be set in the _first_ call of a recursion. - Assert `l1ResultHash != 0` - Copy over the `publicCall.publicInputs.executedCallback` data to this snark's output: `constants.executedCallback`. @@ -163,7 +163,7 @@ Base case (verifying a private kernel snark): Recursion (of public kernel snarks): * If `previousKernel.publicInputs.isPublic && start.publicCallCount > 0`: - - `require(privateCall.functionSignature.isConstructor == false && privateCall.functionSignature.isCallback == false)`: + - `require(privateCall.functionData.isConstructor == false && privateCall.functionData.isCallback == false)`: - only the first call in the kernel recursion can be a constructor or a callback. * Verify the `previousKernel.proof` using the `previousKernel.vk` * Validate that the `previousKernel.vk` is a valid _public_ kernel VK with a membership check: @@ -178,16 +178,16 @@ Recursion (of public kernel snarks): Verify the next call on the callstack: * Verify `start.publicCallStack.length > 0` and (if not already done during the 'Base Case' logic above), pop 1 item off of `start.publicCallStack`. -* Validate that `publicCall.functionSignature.isPrivate == false` (otherwise this is the wrong type of kernel circuit to be using). +* Validate that `publicCall.functionData.isPrivate == false` (otherwise this is the wrong type of kernel circuit to be using). * Validate that this newly-popped `publiceCallStackItemHash` corresponds to the `publicCall` data passed into this circuit: - Calculate the `publicInputsHashPreimage`, given the complexity that 'current' public data wasn't known to the caller at the time they made the call: - Include all data from `publicCall.publicInputs`, except for the data documented earlier in the Public Circuit ABI section. * Calculate `publicCallPublicInputsHash := hash(publicInputsHashPreimage);` - * Verify that `publicCallStackItemHash == hash(publicCall.functionSignature, publicCallPublicInputsHash, publicCall.callContext, etc...)` + * Verify that `publicCallStackItemHash == hash(publicCall.functionData, publicCallPublicInputsHash, publicCall.callContext, etc...)` * Recall, the structure of a callstack item: * ```js publicCall = { - functionSignature: { + functionData: { contractAddress, vkIndex, isPrivate, @@ -202,7 +202,7 @@ Verify the next call on the callstack: ``` * Verify the correctness of `(proof, publicCallPublicInputsHash)` using the `vk`. * Validate the `vk` actually represents the function that is purportedly being executed: - * Extract the `contractAddress` and `vkIndex` from `publicCall.functionSignature`. + * Extract the `contractAddress` and `vkIndex` from `publicCall.functionData`. * Compute `vkHash := hash(vk)` * Compute the `vkRoot` of this function's contract using the `vkIndex`, `vkPath`, and `vkHash`. * Compute the contract's leaf in the `contractTree`: @@ -260,8 +260,8 @@ Update the `end` values: - If `newCallStackItem.isDelegateCall == true`: - Assert `newCallStackItem.callContext == publicCall.callContext` - Else: - - Assert `newCallStackItem.callContext.msgSender == publicCall.functionSignature.contractAddress` - - Assert `newCallStackItem.callContext.storageContractAddress == newCallStackItem.functionSignature.contractAddress` + - Assert `newCallStackItem.callContext.msgSender == publicCall.functionData.contractAddress` + - Assert `newCallStackItem.callContext.storageContractAddress == newCallStackItem.functionData.contractAddress` - Validate `partialL1CallStack` and `callbackStack` lengths: - `require(partialL1CallStack.length == callbackStack.length)` - every L1 call must have a callback entry (even if the callbacks are zeroes). - For each `partialL1CallStackItem` in the `partialL1CallStack` (index `i`): @@ -271,33 +271,33 @@ Update the `end` values: - Let `successCallback = publicCall.callbackStack[i].successCallback` - Let `failureCallback = publicCall.callbackStack[i].failureCallback` - Ensure the contract address of each of the two callbacks matches that of the public call: - - `require(successCallback.functionSignature.contractAddress == publicCall.functionSignature.contractAddress)`; - - `require(failureCallback.functionSignature.contractAddress == publicCall.functionSignature.contractAddress)`; + - `require(successCallback.functionData.contractAddress == publicCall.functionData.contractAddress)`; + - `require(failureCallback.functionData.contractAddress == publicCall.functionData.contractAddress)`; - Calculate the callbackHashes: - - Let `successCallbackHash = hash(successCallback.functionSignature, etc...)` - - Let `failureCallbackHash = hash(failureCallback.functionSignature, etc...)` + - Let `successCallbackHash = hash(successCallback.functionData, etc...)` + - Let `failureCallbackHash = hash(failureCallback.functionData, etc...)` - Push the contents of these call stacks onto the kernel circuit's `end.publicCallStack`, `end.contractDeploymentCallStack` and `end.l1CallStack`. - Also push the each `{callbackPublicKey, successCallbackHash, failureCallbackHash}` onto `end.callbackStack`. - As per the commitments/nullifiers bullet above, it would be nice if these 'pushes' could result in tightly-packed stacks. - Determine whether any values need to be optionally revealed to the Contract Deployment kernel circuit, or to L1, by referring to the `publicCall`'s booleans: - Let `optionallyRevealedData = {};` - - If `publicCall.functionSignature.isConstructor`, set: + - If `publicCall.functionData.isConstructor`, set: - `optionallyRevealedData.callStackItemHash = publicCallStackItemHash;` - `optionallyRevealedData.vkHash = vkHash;` - `optionallyRevealedData.emittedPublicInputs = publicCall.publicInputs.emittedPublicInputs;` - - If `publicCall.functionSignature.isCallback`, set: - - `optionallyRevealedData.functionSignature = publicCall.functionSignature;` + - If `publicCall.functionData.isCallback`, set: + - `optionallyRevealedData.functionData = publicCall.functionData;` - `optionallyRevealedData.emittedPublicInputs = publicCall.publicInputs.emittedPublicInputs;` - TODO: consider whether we can get rid of the emittedPublicInputs being emitted by a callback. More [here](../contracts/l1-calls.md#more-details). - If `isFeePayment`, set: - `optionallyRevealedData.callStackItemHash = publicCallStackItemHash;` - - `optionallyRevealedData.functionSignature = publicCall.functionSignature;` + - `optionallyRevealedData.functionData = publicCall.functionData;` - `optionallyRevealedData.emittedPublicInputs = publicCall.publicInputs.emittedPublicInputs;` - If `payFeeFromL1`, set: - `optionallyRevealedData.callStackItemHash = publicCallStackItemHash;` - If `calledFromL1`, set: - `optionallyRevealedData.callStackItemHash = publicCallStackItemHash;` - - `optionallyRevealedData.functionSignature = publicCall.functionSignature;` + - `optionallyRevealedData.functionData = publicCall.functionData;` - `optionallyRevealedData.emittedPublicInputs = publicCall.publicInputs.emittedPublicInputs;` - Push the `optionallyRevealedData` onto the `optionallyRevealedData`. * If `end.publicCallStack.length == 0`, set `end.publicCallCount = 0`, else `end.publicCallCount = start.publicCallCount + 1` diff --git a/circuits/specs/src/architecture/rollup-circuits/base-rollup.md b/circuits/specs/src/architecture/rollup-circuits/base-rollup.md index bc60fb9137d..5d4111c419f 100644 --- a/circuits/specs/src/architecture/rollup-circuits/base-rollup.md +++ b/circuits/specs/src/architecture/rollup-circuits/base-rollup.md @@ -106,7 +106,7 @@ membershipWitnesses: { // because if a nonzero callbackPublicKey is included, // then this callback must be validated only by the private // kernel circuit (not by this circuit). - // Also, we need to validate the function signature of the callback. + // Also, we need to validate the function data of the callback. callbackPublicKey, successCallback, failureCallback, @@ -240,7 +240,7 @@ constants: { l1CallStack: [...], // combined from both input kernel snarks' public inputs optionallyRevealedData: [{ callStackItemHash, - functionSignature, + functionData, emittedPublicInputs: [_, _, _, _], vkHash, portalContractAddress, @@ -329,17 +329,17 @@ This logic MUST come before the 'nullifier insertion' logic, because we add a ne - `require(l1ResultHash != 0)` to prevent a user executing a callback which refers to a _pending_ result. - Extract `{ l1ResultHash, l1ResultsTreeLeafIndex } = kernelSnarks[i].publicInputs.constants.executedCallback;` - Extract `{ callbackStackItem: { callbackPublicKey, successCallback, failureCallbac } } = membershipWitnesses.executedCallbacks[i];` - - Extract the function signature of the callback which was called (this will always be at the 0th position of the optionallyRevealedData): - - Let `executedCallbackFunctionSignature = kernelSnarks[i].publicInputs.end.optionallyRevealedData[0].functionSelector`. - - `require(executedCallbackFunctionSignature != 0)` + - Extract the function data of the callback which was called (this will always be at the 0th position of the optionallyRevealedData): + - Let `executedCallbackFunctionData = kernelSnarks[i].publicInputs.end.optionallyRevealedData[0].functionSelector`. + - `require(executedCallbackFunctionData != 0)` - Let `executedCallbackEmittedPublicInputs = kernelSnarks[i].publicInputs.end.optionallyRevealedData[0].emittedPublicInputs`. - If `l1ResultHash != 0` (success): - - Check the successCallback's `functionSignature` matches the kernel snark's: - - `require(successCallbackHash.functionSignature == executedCallbackFunctionSignature)` + - Check the successCallback's `functionData` matches the kernel snark's: + - `require(successCallbackHash.functionData == executedCallbackFunctionData)` - In fact, check the entire successCallbackCallHash - Else: - - Check the failureCallbackHash's `functionSignature` matches the kernel snark's: - - `require(failureCallbackHash.functionSignature == executedCallbackFunctionSignature)` + - Check the failureCallbackHash's `functionData` matches the kernel snark's: + - `require(failureCallbackHash.functionData == executedCallbackFunctionData)` - In fact, check the entire successCallbackCallHash - `require(callbackPublicKey == 0)`, otherwise this callback should have been processed in the private kernel snark. - Let `callbackStackItemHash := hash(callbackPublicKey, callbackStackItem.successCallbackHash, callbackStackItem.failureCallbackHash)` diff --git a/circuits/specs/src/architecture/rollup-circuits/merge-rollup.md b/circuits/specs/src/architecture/rollup-circuits/merge-rollup.md index 71d7f8429e4..5ad15fac047 100644 --- a/circuits/specs/src/architecture/rollup-circuits/merge-rollup.md +++ b/circuits/specs/src/architecture/rollup-circuits/merge-rollup.md @@ -98,7 +98,7 @@ constants: { l1CallStack: [...], // combined from both input kernel snarks' public inputs optionallyRevealedData: [{ callStackItemHash, - functionSignature, + functionData, emittedPublicInputs: [_, _, _, _], vkHash, portalContractAddress, diff --git a/circuits/specs/src/examples/erc20/appendix/portal-contract.md b/circuits/specs/src/examples/erc20/appendix/portal-contract.md index 4096e19c9af..5f9604959ea 100644 --- a/circuits/specs/src/examples/erc20/appendix/portal-contract.md +++ b/circuits/specs/src/examples/erc20/appendix/portal-contract.md @@ -20,7 +20,7 @@ contract ERC20Shield { IRollupProcessor rollupProcessor; uint32 public immutable l2ContractAddress; - bytes public immutable l2DepositFunctionSignature; + bytes public immutable l2DepositFunctionData; struct PendingDepositDatum { address depositorAddress; @@ -42,11 +42,11 @@ contract ERC20Shield { constructor ( address _rollupProcessorAddress, uint32 _l2ContractAddress, - bytes _l2DepositFunctionSignature + bytes _l2DepositFunctionData ) { rollupProcessor = IRollupProcessor(rollupProcessorAddress); l2ContractAddress = _l2ContractAddress; - l2DepositFunctionSignature = _l2DepositFunctionSignature; + l2DepositFunctionData = _l2DepositFunctionData; } @@ -114,14 +114,14 @@ contract ERC20Shield { function depositCallback( uint256 l2CallHash, uint256 callIndex, - bytes functionSignature, + bytes functionData, uint256[4] emittedPublicInputs, ) external onlyRollupProcessor { // First check that the function which was executed on L2 was _actually_ // the 'deposit' circuit of the L2 contract which is actually associated with // this portal contract: require( - functionSignature == l2DepositFunctionSignature, + functionData == l2DepositFunctionData, "The wrong function was executed on L2!" ); diff --git a/circuits/specs/src/examples/erc20/appendix/rollup-processor.md b/circuits/specs/src/examples/erc20/appendix/rollup-processor.md index 81bbe7f2e84..cb105076677 100644 --- a/circuits/specs/src/examples/erc20/appendix/rollup-processor.md +++ b/circuits/specs/src/examples/erc20/appendix/rollup-processor.md @@ -142,7 +142,7 @@ contract RollupProcessor is IRollupProcessor { function executeCallbackAndPayFee( uint256 l2CallHash, uint256 callIndex, - bytes functionSignature, + bytes functionData, uint256[4] emittedPublicInputs, address rollupProvider, ) private { @@ -156,7 +156,7 @@ contract RollupProcessor is IRollupProcessor { tx.callback( l2CallHash, callIndex, - functionSignature, + functionData, emittedPublicInputs, { tx.callbackGasLimit } ); diff --git a/circuits/specs/src/examples/erc20/deployment.md b/circuits/specs/src/examples/erc20/deployment.md index f700ac780ed..3c63520edff 100644 --- a/circuits/specs/src/examples/erc20/deployment.md +++ b/circuits/specs/src/examples/erc20/deployment.md @@ -91,7 +91,7 @@ The `publicConstructorCallstackItem` looks like: ```js publicConstructorCallstackItem: { - functionSignature: concat( + functionData: concat( contractAddress, vkIndex = 0, // Constructor vks won't be added to the contract's vkTree. // This `0` is treated as 'null' when `isConstructor = true`. diff --git a/circuits/specs/src/examples/erc20/deposit.md b/circuits/specs/src/examples/erc20/deposit.md index 5a10358f039..43cecbc8174 100644 --- a/circuits/specs/src/examples/erc20/deposit.md +++ b/circuits/specs/src/examples/erc20/deposit.md @@ -35,8 +35,8 @@ A 'deposit' is an example of an [L1 function making a call to an L2 function](.. - In our example, the callback will call the Portal Contract's `depositCallback` function. - Once the L2 circuit is executed, it will be added to a rollup, and the rollup will be submitted by the rollup provider to `RollupProcessor.processRollup`. - The RollupProcessor will be able to identify from the rollup calldata any 'event data' emitted by functions which were 'called' by L1. - - In this example, the RollupProcessor will be able to extract the `l2CallHash`, `functionSignature`, and `emittedPublicInputs` of the L2 'deposit' circuit. -- The `l2CallHash`, `functionSignature`, and `emittedPublicInputs` will all be validated against what was previously stored when the L1 `deposit` function was called. + - In this example, the RollupProcessor will be able to extract the `l2CallHash`, `functionData`, and `emittedPublicInputs` of the L2 'deposit' circuit. +- The `l2CallHash`, `functionData`, and `emittedPublicInputs` will all be validated against what was previously stored when the L1 `deposit` function was called. - In particular, the `emittedPublicInputs` of this example's 'deposit' circuit will contain the `amount` deposited, as a way of reconciling the L1 call with the L2 call. It might also contain the `msg.sender`. - If all of the checks reconcile, then the rollup provider will be paid a fee (if one was provided as part of the initial L1 call). diff --git a/circuits/specs/src/noir-stuff/extremes/call-l1.md b/circuits/specs/src/noir-stuff/extremes/call-l1.md index da50796e2e3..4ecd31ebec3 100644 --- a/circuits/specs/src/noir-stuff/extremes/call-l1.md +++ b/circuits/specs/src/noir-stuff/extremes/call-l1.md @@ -77,14 +77,14 @@ fn swap_a_for_b( unpacked_callback_stack: [ { success_callback_call: { - function_signature, + function_data, public_inputs, call_context, is_delegate_call, is_static_call, }, failure_callback_call: { - function_signature, + function_data, public_inputs, call_context, is_delegate_call, @@ -174,7 +174,7 @@ fn swap_a_for_b( require( success_callback_call == { - function_signature: { + function_data: { contract_address: 0, // Special meaning: address(this) vk_index: 1, // hide_amount_b() is_private: true, @@ -231,7 +231,7 @@ fn swap_a_for_b( } }, failure_callback_call == { - function_signature: { + function_data: { contract_address: 0, // Special meaning: address(this) vk_index: 2, // hide_amount_a() is_private: true, @@ -287,7 +287,7 @@ fn swap_a_for_b( let failure_callback = PUBLIC_INPUTS.callback_stack.failure_callback; assert( - failure_callback.function_signature == { + failure_callback.function_data == { contract_address: 0, // special meaning: address(this) vk_index: 2, // hide_amount_a() is_private: true, diff --git a/circuits/specs/src/noir-stuff/extremes/call-private.md b/circuits/specs/src/noir-stuff/extremes/call-private.md index 20af37dad18..207c91ecd27 100644 --- a/circuits/specs/src/noir-stuff/extremes/call-private.md +++ b/circuits/specs/src/noir-stuff/extremes/call-private.md @@ -38,7 +38,7 @@ fn my_private_function( unpacked_private_call_stack: [ { // Here's the call stack item for the call to `other_private_function` - function_signature: { + function_data: { contract_address: 0xabc123, vk_index: 0, is_private: true, @@ -124,11 +124,11 @@ fn my_private_function( let call_stack_item = PRIVATE_INPUTS.unpacked_private_call_stack[0]; // Check the correct contract address is being called. - assert(call_stack_item.function_signature.contract_address == 0x123abc); + assert(call_stack_item.function_data.contract_address == 0x123abc); // Check the vkIndex (which can be inferred from the ordering of functions in // the Other_Contract): - assert(call_stack_item.function_signature.vk_index == 0); + assert(call_stack_item.function_data.vk_index == 0); // Check the correct parameters are being passed to the function: assert(call_stack_item.public_inputs.args[0] == a); diff --git a/circuits/specs/src/noir-stuff/extremes/call-public-same.md b/circuits/specs/src/noir-stuff/extremes/call-public-same.md index c3476274d63..5ff5c086048 100644 --- a/circuits/specs/src/noir-stuff/extremes/call-public-same.md +++ b/circuits/specs/src/noir-stuff/extremes/call-public-same.md @@ -32,7 +32,7 @@ fn my_private_function( unpacked_public_call_stack: [ { // Here's the call stack item for the call to `my_public_function` - function_signature: { + function_data: { contract_address: 0, // `0` is understood by the private kernel // snark to mean `address(this)`. The // correct address will be inserted here @@ -121,11 +121,11 @@ fn my_private_function( // Check the correct contract address is being called. // address(this) is a special case: we put 0 in this circuit, and the kernel // circuit will insert the correct address. - assert(call_stack_item.function_signature.contract_address == 0); + assert(call_stack_item.function_data.contract_address == 0); // Check the vkIndex (which can be inferred from the ordering of functions in // this contract). - assert(call_stack_item.function_signature.vkIndex == 0); + assert(call_stack_item.function_data.vkIndex == 0); // Check the correct parameters are being passed to the function: assert(call_stack_item.public_inputs.args[0] == a); diff --git a/circuits/specs/src/noir-stuff/extremes/call-public.md b/circuits/specs/src/noir-stuff/extremes/call-public.md index daec436d398..c99d3e35f67 100644 --- a/circuits/specs/src/noir-stuff/extremes/call-public.md +++ b/circuits/specs/src/noir-stuff/extremes/call-public.md @@ -37,7 +37,7 @@ fn my_private_function( unpacked_public_call_stack: [ { // Here's the call stack item for the call to `my_public_function` - function_signature: { + function_data: { contract_address: 0xabc123, vk_index: 0, is_private: false, @@ -121,11 +121,11 @@ fn my_private_function( let call_stack_item = PRIVATE_INPUTS.unpacked_public_call_stack[0]; // Check the correct contract address is being called. - assert(call_stack_item.function_signature.contract_address == 0xabc123); + assert(call_stack_item.function_data.contract_address == 0xabc123); // Check the vkIndex (which can be inferred from the ordering of functions in // this contract). - assert(call_stack_item.function_signature.vkIndex == 0); + assert(call_stack_item.function_data.vkIndex == 0); // Check the correct parameters are being passed to the function: assert(call_stack_item.public_inputs.args[0] == a); diff --git a/circuits/specs/src/noir-stuff/extremes/deploy-contract.md b/circuits/specs/src/noir-stuff/extremes/deploy-contract.md index b5f26beb8b1..43b4fd1c6de 100644 --- a/circuits/specs/src/noir-stuff/extremes/deploy-contract.md +++ b/circuits/specs/src/noir-stuff/extremes/deploy-contract.md @@ -64,7 +64,7 @@ fn deploy( }, call_stack_item: { // Here's the call stack item for the contract deployment call. - // Notice: no function signature for contract deployment calls. + // Notice: no function data for contract deployment calls. public_inputs: { private_constructor_public_inputs_hash, // TODO: consider having the unpacked public inputs here instead, for ease. public_constructor_public_inputs_hash, diff --git a/circuits/specs/src/noir-stuff/extremes/emit-event.md b/circuits/specs/src/noir-stuff/extremes/emit-event.md index 419e367c8f3..f9c16399ba7 100644 --- a/circuits/specs/src/noir-stuff/extremes/emit-event.md +++ b/circuits/specs/src/noir-stuff/extremes/emit-event.md @@ -28,10 +28,10 @@ contract L1_Contract { function callback_after_l2_function_executed( uint256 l2CallHash, uint256 callIndex, - bytes functionSignature, + bytes functionData, uint256[4] emittedPublicInputs, // THIS IS EVENT DATA FROM L2! ) { - // Logic to validate the functionSignature, emittedPublicInputs were as + // Logic to validate the functionData, emittedPublicInputs were as // expected. E.g.: require(emittedPublicInputs[0] == 123); require(emittedPublicInputs[1] == 456); From 3708a8b76df03df44812628485b6c7d7ccb57d18 Mon Sep 17 00:00:00 2001 From: Charlie Lye Date: Mon, 20 Mar 2023 14:18:58 +0000 Subject: [PATCH 073/166] Use build context. --- circuits/.circleci/config.yml | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/circuits/.circleci/config.yml b/circuits/.circleci/config.yml index 7a47092bf20..28e83ba795c 100644 --- a/circuits/.circleci/config.yml +++ b/circuits/.circleci/config.yml @@ -35,11 +35,6 @@ checkout: &checkout chmod 0700 .ssh ssh-keyscan -t rsa github.com >> .ssh/known_hosts - # A read only key for cloning the repository. - echo $GIT_CHECKOUT_KEY | base64 -d > .ssh/id_rsa - - chmod 0600 .ssh/id_rsa - # IF YOU'RE CHANGING THIS, YOU ALSO WANT TO CHANGE: build-system/remote_build/remote_build # Shallow checkout this commit. mkdir -p project @@ -177,29 +172,28 @@ jobs: # Repeatable config for defining the workflow below. tag_regex: &tag_regex /v[0-9]+(\.[0-9]+)*(-[a-zA-Z-]+\.[0-9]+)?/ -tag_filter: &tag_filter - tags: - only: *tag_regex +defaults: &defaults + context: + - build + filters: + tags: + only: *tag_regex a3_wasm_test: &a3_wasm_test requires: - wasm-linux-clang-assert - filters: *tag_filter + <<: *defaults a3_test: &a3_test requires: - x86_64-linux-clang-assert - filters: *tag_filter + <<: *defaults workflows: system: jobs: - - wasm-linux-clang: - filters: *tag_filter - - wasm-linux-clang-assert: - filters: *tag_filter - - x86_64-linux-clang: - filters: *tag_filter - - x86_64-linux-clang-assert: - filters: *tag_filter + - wasm-linux-clang: *defaults + - wasm-linux-clang-assert: *defaults + - x86_64-linux-clang: *defaults + - x86_64-linux-clang-assert: *defaults - aztec3-circuits-wasm-tests: *a3_wasm_test - aztec3-circuits-tests: *a3_test - #- aztec3-circuit--tests: *a3_test \ No newline at end of file + #- aztec3-circuit--tests: *a3_test From fc0181578d743e2d1eeb857053ec7b2c22b68166 Mon Sep 17 00:00:00 2001 From: Suyash Bagad Date: Mon, 20 Mar 2023 17:21:57 +0100 Subject: [PATCH 074/166] Move `CT` and `NT` types to `aztec3/utils` (#67) * [Squashed] Move CT and NT types. Initial commit. Better to create `utils/types` Use aztec3 ct and nt. Point to `bb/sb/remove-a3-types`. switch. Switch to latest aztec3. Fix bb inclues. Update bb. Revert to `bb/aztec3` fix wasm build in cci. * Fix wasm with assert build. * Use `<..>` for bb includes. * Remove `tx_signature` (uncooked) file. --- circuits/cpp/barretenberg | 2 +- circuits/cpp/cmake/barretenberg.cmake | 2 +- .../dockerfiles/Dockerfile.wasm-linux-clang | 2 +- .../Dockerfile.wasm-linux-clang-assert | 2 +- circuits/cpp/src/aztec3/CMakeLists.txt | 3 +- .../cpp/src/aztec3/circuits/abis/.test.cpp | 12 +- .../cpp/src/aztec3/circuits/abis/README.md | 3 +- .../cpp/src/aztec3/circuits/abis/c_bind.cpp | 8 +- .../src/aztec3/circuits/abis/c_bind.test.cpp | 4 +- .../src/aztec3/circuits/abis/call_context.hpp | 20 +- .../aztec3/circuits/abis/call_stack_item.hpp | 14 +- .../abis/contract_deployment_data.hpp | 20 +- .../aztec3/circuits/abis/function_data.hpp | 20 +- .../circuits/abis/function_leaf_preimage.hpp | 14 +- .../abis/optionally_revealed_data.hpp | 16 +- .../abis/private_circuit_public_inputs.hpp | 26 +- .../abis/private_kernel/accumulated_data.hpp | 18 +- .../call_context_reconciliation_data.hpp | 16 +- .../abis/private_kernel/constant_data.hpp | 12 +- .../circuits/abis/private_kernel/globals.hpp | 14 +- .../abis/private_kernel/old_tree_roots.hpp | 16 +- .../private_kernel/previous_kernel_data.hpp | 14 +- .../abis/private_kernel/private_call_data.hpp | 16 +- .../abis/private_kernel/private_inputs.hpp | 12 +- .../abis/private_kernel/public_inputs.hpp | 16 +- .../abis/public_circuit_public_inputs.hpp | 14 +- .../circuits/abis/signed_tx_request.hpp | 14 +- .../src/aztec3/circuits/abis/state_read.hpp | 14 +- .../aztec3/circuits/abis/state_transition.hpp | 14 +- .../src/aztec3/circuits/abis/tx_context.hpp | 20 +- .../src/aztec3/circuits/abis/tx_request.hpp | 14 +- .../cpp/src/aztec3/circuits/apps/.test.cpp | 22 +- .../cpp/src/aztec3/circuits/apps/contract.hpp | 6 +- .../cpp/src/aztec3/circuits/apps/contract.tpp | 8 +- .../circuits/apps/function_declaration.hpp | 12 +- .../apps/function_execution_context.hpp | 14 +- .../cpp/src/aztec3/circuits/apps/l1_call.hpp | 14 +- .../circuits/apps/l1_function_interface.hpp | 12 +- .../circuits/apps/l1_function_interface.tpp | 12 +- .../apps/notes/default_private_note/note.hpp | 8 +- .../apps/notes/default_private_note/note.tpp | 20 +- .../default_private_note/note_preimage.hpp | 20 +- .../nullifier_preimage.hpp | 18 +- .../default_singleton_private_note/note.hpp | 8 +- .../default_singleton_private_note/note.tpp | 20 +- .../note_preimage.hpp | 20 +- .../nullifier_preimage.hpp | 18 +- .../circuits/apps/notes/note_interface.hpp | 8 +- .../aztec3/circuits/apps/opcodes/opcodes.hpp | 10 +- .../aztec3/circuits/apps/opcodes/opcodes.tpp | 10 +- .../aztec3/circuits/apps/oracle_wrapper.hpp | 22 +- .../circuits/apps/private_state.test.cpp | 18 +- .../apps/state_vars/field_state_var.hpp | 8 +- .../apps/state_vars/mapping_state_var.hpp | 8 +- .../apps/state_vars/mapping_state_var.tpp | 22 +- .../apps/state_vars/state_var_base.hpp | 8 +- .../apps/state_vars/state_var_base.tpp | 10 +- .../apps/state_vars/utxo_set_state_var.hpp | 8 +- .../apps/state_vars/utxo_set_state_var.tpp | 4 +- .../apps/state_vars/utxo_state_var.hpp | 8 +- .../apps/state_vars/utxo_state_var.tpp | 4 +- .../circuits/apps/test_apps/escrow/.test.cpp | 8 +- .../circuits/apps/test_apps/escrow/init.hpp | 14 +- .../.test.cpp | 2 +- .../private_to_private_function_call/init.hpp | 14 +- .../src/aztec3/circuits/apps/utxo_datum.hpp | 12 +- .../aztec3/circuits/kernel/private/.test.cpp | 14 +- .../aztec3/circuits/kernel/private/init.hpp | 14 +- .../kernel/private/private_kernel_circuit.cpp | 2 +- .../src/aztec3/circuits/mock/mock_circuit.hpp | 6 +- .../circuits/mock/mock_kernel_circuit.hpp | 18 +- .../aztec3/circuits/recursion/aggregator.hpp | 18 +- .../aztec3/circuits/recursion/play.test.cpp | 8 +- .../circuits/recursion/play_app_circuit.hpp | 2 +- .../recursion/play_recursive_circuit.hpp | 12 +- .../cpp/src/aztec3/dbs/private_state_db.hpp | 6 +- circuits/cpp/src/aztec3/oracle/fake_db.hpp | 6 +- circuits/cpp/src/aztec3/oracle/oracle.hpp | 6 +- circuits/cpp/src/aztec3/utils/CMakeLists.txt | 1 + .../cpp/src/aztec3/utils/types/CMakeLists.txt | 4 + .../src/aztec3/utils/types/circuit_types.hpp | 91 +++++++ .../cpp/src/aztec3/utils/types/convert.hpp | 254 ++++++++++++++++++ .../src/aztec3/utils/types/native_types.hpp | 89 ++++++ 83 files changed, 907 insertions(+), 466 deletions(-) create mode 100644 circuits/cpp/src/aztec3/utils/CMakeLists.txt create mode 100644 circuits/cpp/src/aztec3/utils/types/CMakeLists.txt create mode 100644 circuits/cpp/src/aztec3/utils/types/circuit_types.hpp create mode 100644 circuits/cpp/src/aztec3/utils/types/convert.hpp create mode 100644 circuits/cpp/src/aztec3/utils/types/native_types.hpp diff --git a/circuits/cpp/barretenberg b/circuits/cpp/barretenberg index a67b5aa243a..9aae3b4fcbd 160000 --- a/circuits/cpp/barretenberg +++ b/circuits/cpp/barretenberg @@ -1 +1 @@ -Subproject commit a67b5aa243ad55b364dd4976766613af337447bc +Subproject commit 9aae3b4fcbda51e36782e22108880e48da977af6 diff --git a/circuits/cpp/cmake/barretenberg.cmake b/circuits/cpp/cmake/barretenberg.cmake index 12cb0140181..9a2793e99b4 100644 --- a/circuits/cpp/cmake/barretenberg.cmake +++ b/circuits/cpp/cmake/barretenberg.cmake @@ -36,7 +36,7 @@ ExternalProject_Add(Barretenberg # byproducts needed by ninja generator (not needed by make) BUILD_BYPRODUCTS ${BBERG_BUILD_DIR}/lib/libbarretenberg.a ${BBERG_BUILD_DIR}/lib/libenv.a) -include_directories(${BBERG_DIR}/src/aztec) +include_directories(${BBERG_DIR}/src) # Add the imported barretenberg and env libraries, point to their library archives, # and add a dependency of these libraries on the imported project diff --git a/circuits/cpp/dockerfiles/Dockerfile.wasm-linux-clang b/circuits/cpp/dockerfiles/Dockerfile.wasm-linux-clang index 51037fadd4b..244f5e293b2 100644 --- a/circuits/cpp/dockerfiles/Dockerfile.wasm-linux-clang +++ b/circuits/cpp/dockerfiles/Dockerfile.wasm-linux-clang @@ -1,5 +1,5 @@ FROM ubuntu:kinetic AS builder -RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y build-essential wget git libssl-dev cmake curl binaryen +RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y build-essential wget git libssl-dev cmake ninja-build curl binaryen WORKDIR /usr/src/aztec3-circuits/cpp/barretenberg/cpp/src RUN curl -s -L https://github.com/CraneStation/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-linux.tar.gz | tar zxfv - WORKDIR /usr/src/aztec3-circuits/cpp diff --git a/circuits/cpp/dockerfiles/Dockerfile.wasm-linux-clang-assert b/circuits/cpp/dockerfiles/Dockerfile.wasm-linux-clang-assert index 917c467482c..abce9c5f8e1 100644 --- a/circuits/cpp/dockerfiles/Dockerfile.wasm-linux-clang-assert +++ b/circuits/cpp/dockerfiles/Dockerfile.wasm-linux-clang-assert @@ -1,5 +1,5 @@ FROM ubuntu:kinetic AS builder -RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y build-essential git libssl-dev cmake curl binaryen +RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y build-essential git libssl-dev cmake ninja-build curl binaryen WORKDIR /usr/src/aztec3-circuits/cpp/barretenberg/cpp/src RUN curl -s -L https://github.com/CraneStation/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-linux.tar.gz | tar zxfv - WORKDIR /usr/src/aztec3-circuits/cpp diff --git a/circuits/cpp/src/aztec3/CMakeLists.txt b/circuits/cpp/src/aztec3/CMakeLists.txt index c3f0d8fc73a..110cca7692c 100644 --- a/circuits/cpp/src/aztec3/CMakeLists.txt +++ b/circuits/cpp/src/aztec3/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory(circuits) add_subdirectory(oracle) -add_subdirectory(dbs) \ No newline at end of file +add_subdirectory(dbs) +add_subdirectory(utils) \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/abis/.test.cpp b/circuits/cpp/src/aztec3/circuits/abis/.test.cpp index 921d25a9395..17e110655f0 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/abis/.test.cpp @@ -1,15 +1,15 @@ #include -#include -#include -// #include +#include +#include +// #include #include "index.hpp" -#include +#include namespace aztec3::circuits::abis { using Composer = plonk::stdlib::types::Composer; -using CT = plonk::stdlib::types::CircuitTypes; -using NT = plonk::stdlib::types::NativeTypes; +using CT = aztec3::utils::types::CircuitTypes; +using NT = aztec3::utils::types::NativeTypes; class abi_tests : public ::testing::Test {}; diff --git a/circuits/cpp/src/aztec3/circuits/abis/README.md b/circuits/cpp/src/aztec3/circuits/abis/README.md index c9d52a2dda6..26acdf5f58f 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/README.md +++ b/circuits/cpp/src/aztec3/circuits/abis/README.md @@ -1,8 +1,9 @@ # aztec3::circuits::abis Contains all ABIs for use by: + - Test app circuits - Kernel circuits - Rollup circuits -All ABIs are generalised by an `NCT` template parameter (meaning `NativeOrCircuitTypes`). `NCT` can be either `plonk::stdlib::types::NativeTypes` or `plonk::stdlib::types::CircuitTypes` for some `Composer`. The idea being, there's a single implementation of every struct/class for native and circuit types. NativeType structs can be switched to CircuitType with the `to_circuit_type()` method. \ No newline at end of file +All ABIs are generalised by an `NCT` template parameter (meaning `NativeOrCircuitTypes`). `NCT` can be either `aztec3::utils::types::NativeTypes` or `aztec3::utils::types::CircuitTypes` for some `Composer`. The idea being, there's a single implementation of every struct/class for native and circuit types. NativeType structs can be switched to CircuitType with the `to_circuit_type()` method. diff --git a/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp b/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp index 2ebd1fe3f55..b63a2be5527 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp +++ b/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp @@ -4,15 +4,15 @@ #include -#include -#include -#include +#include +#include +#include namespace { using aztec3::GeneratorIndex; using aztec3::circuits::abis::FunctionLeafPreimage; using aztec3::circuits::abis::TxRequest; -using NT = plonk::stdlib::types::NativeTypes; +using NT = aztec3::utils::types::NativeTypes; } // namespace #define WASM_EXPORT __attribute__((visibility("default"))) diff --git a/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp b/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp index 047b2caa63d..3904d3279ba 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp @@ -3,12 +3,12 @@ #include "tx_request.hpp" #include "function_leaf_preimage.hpp" -#include +#include #include namespace { -using NT = plonk::stdlib::types::NativeTypes; +using NT = aztec3::utils::types::NativeTypes; auto& engine = numeric::random::get_debug_engine(); /** diff --git a/circuits/cpp/src/aztec3/circuits/abis/call_context.hpp b/circuits/cpp/src/aztec3/circuits/abis/call_context.hpp index 2fb2a3c9f73..1f9dfb3e38d 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/call_context.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/call_context.hpp @@ -1,18 +1,18 @@ #pragma once -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include namespace aztec3::circuits::abis { +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; using plonk::stdlib::witness_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; template struct CallContext { typedef typename NCT::address address; @@ -45,7 +45,7 @@ template struct CallContext { static_assert((std::is_same::value)); // Capture the composer: - auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(composer, e); }; CallContext> call_context = { to_ct(msg_sender), to_ct(storage_contract_address), to_ct(tx_origin), to_ct(is_delegate_call), @@ -59,7 +59,7 @@ template struct CallContext { template CallContext to_native_type() const { static_assert(std::is_same, NCT>::value); - auto to_nt = [&](auto& e) { return plonk::stdlib::types::to_nt(e); }; + auto to_nt = [&](auto& e) { return aztec3::utils::types::to_nt(e); }; CallContext call_context = { to_nt(msg_sender), to_nt(storage_contract_address), to_nt(tx_origin), to_nt(is_delegate_call), diff --git a/circuits/cpp/src/aztec3/circuits/abis/call_stack_item.hpp b/circuits/cpp/src/aztec3/circuits/abis/call_stack_item.hpp index f70b401b15b..5711fc51893 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/call_stack_item.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/call_stack_item.hpp @@ -3,16 +3,16 @@ #include "private_circuit_public_inputs.hpp" #include "public_circuit_public_inputs.hpp" -#include -#include -#include -#include +#include +#include +#include +#include namespace aztec3::circuits::abis { +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; using plonk::stdlib::witness_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; using std::conditional; using std::is_same; @@ -52,7 +52,7 @@ template struct CallStackItem { static_assert((std::is_same::value)); // Capture the composer: - auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(composer, e); }; CallStackItem, call_type> call_stack_item = { to_ct(contract_address), diff --git a/circuits/cpp/src/aztec3/circuits/abis/contract_deployment_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/contract_deployment_data.hpp index 67174306552..856b7f15dbc 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/contract_deployment_data.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/contract_deployment_data.hpp @@ -1,16 +1,16 @@ #pragma once -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include namespace aztec3::circuits::abis { +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; using plonk::stdlib::witness_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; using std::is_same; template struct ContractDeploymentData { @@ -33,7 +33,7 @@ template struct ContractDeploymentData { static_assert((std::is_same::value)); // Capture the composer: - auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(composer, e); }; ContractDeploymentData> data = { to_ct(contract_data_hash), to_ct(function_tree_root), to_ct(constructor_hash), @@ -46,7 +46,7 @@ template struct ContractDeploymentData { template ContractDeploymentData to_native_type() const { static_assert(std::is_same, NCT>::value); - auto to_nt = [&](auto& e) { return plonk::stdlib::types::to_nt(e); }; + auto to_nt = [&](auto& e) { return aztec3::utils::types::to_nt(e); }; ContractDeploymentData call_context = { to_nt(contract_data_hash), to_nt(function_tree_root), to_nt(constructor_hash), diff --git a/circuits/cpp/src/aztec3/circuits/abis/function_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/function_data.hpp index 257ab2832e7..487c5bf3849 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/function_data.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/function_data.hpp @@ -1,17 +1,17 @@ #pragma once -//#include -#include -//#include -#include -#include -#include +// #include +#include +// #include +#include +#include +#include #include namespace aztec3::circuits::abis { // using plonk::stdlib::witness_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; using std::is_same; template struct FunctionData { @@ -34,7 +34,7 @@ template struct FunctionData { static_assert((std::is_same::value)); // Capture the composer: - auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(composer, e); }; FunctionData> function_data = { to_ct(function_encoding), @@ -48,7 +48,7 @@ template struct FunctionData { template FunctionData to_native_type() const { static_assert(std::is_same, NCT>::value); - auto to_nt = [&](auto& e) { return plonk::stdlib::types::to_nt(e); }; + auto to_nt = [&](auto& e) { return aztec3::utils::types::to_nt(e); }; FunctionData function_data = { to_nt(function_encoding), diff --git a/circuits/cpp/src/aztec3/circuits/abis/function_leaf_preimage.hpp b/circuits/cpp/src/aztec3/circuits/abis/function_leaf_preimage.hpp index efc9890e533..625621bf6a2 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/function_leaf_preimage.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/function_leaf_preimage.hpp @@ -1,13 +1,13 @@ #pragma once -#include -#include -#include +#include +#include +#include #include namespace aztec3::circuits::abis { -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; using std::is_same; /** @@ -44,7 +44,7 @@ template struct FunctionLeafPreimage { static_assert((std::is_same::value)); // Capture the composer: - auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(composer, e); }; FunctionLeafPreimage> preimage = { to_ct(function_selector), @@ -59,7 +59,7 @@ template struct FunctionLeafPreimage { template FunctionLeafPreimage to_native_type() const { static_assert(std::is_same, NCT>::value); - auto to_nt = [&](auto& e) { return plonk::stdlib::types::to_nt(e); }; + auto to_nt = [&](auto& e) { return aztec3::utils::types::to_nt(e); }; FunctionLeafPreimage preimage = { to_nt(function_selector), diff --git a/circuits/cpp/src/aztec3/circuits/abis/optionally_revealed_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/optionally_revealed_data.hpp index 2b860c9d5af..d9a5b613b31 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/optionally_revealed_data.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/optionally_revealed_data.hpp @@ -1,14 +1,14 @@ #pragma once #include "function_data.hpp" -#include -#include -#include -#include +#include +#include +#include +#include namespace aztec3::circuits::abis { +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; using plonk::stdlib::witness_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; template struct OptionallyRevealedData { typedef typename NCT::boolean boolean; @@ -30,7 +30,7 @@ template struct OptionallyRevealedData { static_assert((std::is_same::value)); // Capture the composer: - auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(composer, e); }; OptionallyRevealedData> data = { to_ct(call_stack_item_hash), function_data.to_circuit_type(composer), @@ -46,7 +46,7 @@ template struct OptionallyRevealedData { template OptionallyRevealedData to_native_type() const { static_assert(std::is_same, NCT>::value); - auto to_nt = [&](auto& e) { return plonk::stdlib::types::to_nt(e); }; + auto to_nt = [&](auto& e) { return aztec3::utils::types::to_nt(e); }; auto to_native_type = [](T& e) { return e.template to_native_type(); }; OptionallyRevealedData data = { diff --git a/circuits/cpp/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp index 1ff8d1f24ad..78b27ca771a 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp @@ -4,19 +4,19 @@ #include "contract_deployment_data.hpp" #include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include namespace aztec3::circuits::abis { +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; using plonk::stdlib::witness_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; template class PrivateCircuitPublicInputs { typedef typename NCT::fr fr; @@ -49,7 +49,7 @@ template class PrivateCircuitPublicInputs { static_assert((std::is_same::value)); // Capture the composer: - auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(composer, e); }; auto to_circuit_type = [&](auto& e) { return e.to_circuit_type(composer); }; PrivateCircuitPublicInputs> pis = { @@ -80,7 +80,7 @@ template class PrivateCircuitPublicInputs { template PrivateCircuitPublicInputs to_native_type() const { static_assert(std::is_same, NCT>::value); - auto to_nt = [&](auto& e) { return plonk::stdlib::types::to_nt(e); }; + auto to_nt = [&](auto& e) { return aztec3::utils::types::to_nt(e); }; auto to_native_type = [](T& e) { return e.template to_native_type(); }; PrivateCircuitPublicInputs pis = { @@ -386,7 +386,7 @@ template class OptionalPrivateCircuitPublicInputs { static_assert((std::is_same::value)); // Capture the composer: - auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(composer, e); }; auto to_circuit_type = [&](auto& e) { return e ? std::make_optional((*e).to_circuit_type(composer)) : std::nullopt; }; @@ -419,7 +419,7 @@ template class OptionalPrivateCircuitPublicInputs { template OptionalPrivateCircuitPublicInputs to_native_type() const { static_assert(std::is_same, NCT>::value); - auto to_nt = [&](auto& e) { return plonk::stdlib::types::to_nt(e); }; + auto to_nt = [&](auto& e) { return aztec3::utils::types::to_nt(e); }; auto to_native_type = [](const std::optional& e) { return e ? std::make_optional((*e).template to_native_type()) : std::nullopt; }; diff --git a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/accumulated_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/accumulated_data.hpp index ca3d05b8da9..230675af784 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/accumulated_data.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/accumulated_data.hpp @@ -1,16 +1,16 @@ #pragma once #include "../optionally_revealed_data.hpp" -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include namespace aztec3::circuits::abis::private_kernel { +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; using plonk::stdlib::witness_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; using std::is_same; template struct AccumulatedData { @@ -36,7 +36,7 @@ template struct AccumulatedData { static_assert((std::is_same::value)); // Capture the composer: - auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(composer, e); }; auto to_circuit_type = [&](auto& e) { return e.to_circuit_type(composer); }; AccumulatedData acc_data = { @@ -66,7 +66,7 @@ template struct AccumulatedData { template AccumulatedData to_native_type() const { static_assert(std::is_same, NCT>::value); - auto to_nt = [&](auto& e) { return plonk::stdlib::types::to_nt(e); }; + auto to_nt = [&](auto& e) { return aztec3::utils::types::to_nt(e); }; auto to_native_type = [](T& e) { return e.template to_native_type(); }; AccumulatedData acc_data = { diff --git a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/call_context_reconciliation_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/call_context_reconciliation_data.hpp index 154fc4f62fa..3635b44e611 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/call_context_reconciliation_data.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/call_context_reconciliation_data.hpp @@ -2,17 +2,17 @@ // #include "../call_context.hpp" -// #include -// #include -// #include -// #include -// #include +// #include +// #include +// #include +// #include +// #include // namespace aztec3::circuits::abis::private_kernel { // using plonk::stdlib::witness_t; -// using plonk::stdlib::types::CircuitTypes; -// using plonk::stdlib::types::NativeTypes; +// using aztec3::utils::types::CircuitTypes; +// using aztec3::utils::types::NativeTypes; // using std::is_same; // template struct CallContextReconciliationData { @@ -39,7 +39,7 @@ // static_assert((std::is_same::value)); // // Capture the composer: -// auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; +// auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(composer, e); }; // auto to_circuit_type = [&](auto& e) { return e.to_circuit_type(composer); }; // CallContextReconciliationData> data = { diff --git a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/constant_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/constant_data.hpp index 06f7b9e25ef..3d5e9e4b757 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/constant_data.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/constant_data.hpp @@ -3,16 +3,16 @@ #include "old_tree_roots.hpp" #include "../tx_context.hpp" -#include -#include -#include -#include +#include +#include +#include +#include namespace aztec3::circuits::abis::private_kernel { +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; using plonk::stdlib::witness_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; using std::is_same; template struct ConstantData { diff --git a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/globals.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/globals.hpp index eb06ab4cb85..a2dcf1e180f 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/globals.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/globals.hpp @@ -1,14 +1,14 @@ #pragma once -#include -#include -#include -#include +#include +#include +#include +#include namespace aztec3::circuits::abis::private_kernel { +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; using plonk::stdlib::witness_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; using std::is_same; template struct Globals { @@ -21,7 +21,7 @@ template struct Globals { static_assert((std::is_same::value)); // Capture the composer: - auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(composer, e); }; Globals> global_data = { to_ct(min_timestamp) }; diff --git a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/old_tree_roots.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/old_tree_roots.hpp index c53a227e2ef..8e686da4521 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/old_tree_roots.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/old_tree_roots.hpp @@ -1,14 +1,14 @@ #pragma once -#include -#include -#include -#include +#include +#include +#include +#include namespace aztec3::circuits::abis::private_kernel { +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; using plonk::stdlib::witness_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; using std::is_same; template struct OldTreeRoots { @@ -24,7 +24,7 @@ template struct OldTreeRoots { static_assert((std::is_same::value)); // Capture the composer: - auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(composer, e); }; OldTreeRoots> data = { to_ct(private_data_tree_root), @@ -39,7 +39,7 @@ template struct OldTreeRoots { template OldTreeRoots to_native_type() const { static_assert(std::is_same, NCT>::value); - auto to_nt = [&](auto& e) { return plonk::stdlib::types::to_nt(e); }; + auto to_nt = [&](auto& e) { return aztec3::utils::types::to_nt(e); }; OldTreeRoots data = { to_nt(private_data_tree_root), diff --git a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp index 42c6af2ac7d..803084b4f84 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp @@ -1,15 +1,15 @@ #pragma once #include "public_inputs.hpp" -#include -#include -#include -#include +#include +#include +#include +#include namespace aztec3::circuits::abis::private_kernel { +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; using plonk::stdlib::witness_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; using std::is_same; template struct PreviousKernelData { @@ -32,7 +32,7 @@ template struct PreviousKernelData { static_assert((std::is_same::value)); // Capture the composer: - auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(composer, e); }; PreviousKernelData> data = { public_inputs.to_circuit_type(composer), diff --git a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/private_call_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/private_call_data.hpp index 5512431deaa..8944f942c94 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/private_call_data.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/private_call_data.hpp @@ -3,17 +3,17 @@ #include "call_context_reconciliation_data.hpp" #include "../call_stack_item.hpp" -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include namespace aztec3::circuits::abis::private_kernel { +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; using plonk::stdlib::witness_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; using std::is_same; template struct PrivateCallData { @@ -47,7 +47,7 @@ template struct PrivateCallData { static_assert((std::is_same::value)); // Capture the composer: - auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(composer, e); }; auto to_circuit_type = [&](auto& e) { return e.to_circuit_type(composer); }; PrivateCallData> data = { diff --git a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/private_inputs.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/private_inputs.hpp index 3a4e696f7da..a28f4e475bd 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/private_inputs.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/private_inputs.hpp @@ -5,16 +5,16 @@ #include "private_call_data.hpp" #include "../signed_tx_request.hpp" -#include -#include -#include -#include +#include +#include +#include +#include namespace aztec3::circuits::abis::private_kernel { +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; using plonk::stdlib::witness_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; using std::is_same; template struct PrivateInputs { diff --git a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/public_inputs.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/public_inputs.hpp index 6e3a85ae248..b36541e02e6 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/public_inputs.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/public_inputs.hpp @@ -1,16 +1,16 @@ #pragma once #include "accumulated_data.hpp" #include "constant_data.hpp" -#include -#include -#include -#include +#include +#include +#include +#include namespace aztec3::circuits::abis::private_kernel { +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; using plonk::stdlib::witness_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; using std::is_same; template struct PublicInputs { @@ -27,7 +27,7 @@ template struct PublicInputs { static_assert((std::is_same::value)); // Capture the composer: - auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(composer, e); }; PublicInputs> private_inputs = { end.to_circuit_type(composer), @@ -42,7 +42,7 @@ template struct PublicInputs { template PublicInputs to_native_type() const { static_assert(std::is_same, NCT>::value); - auto to_nt = [&](auto& e) { return plonk::stdlib::types::to_nt(e); }; + auto to_nt = [&](auto& e) { return aztec3::utils::types::to_nt(e); }; auto to_native_type = [](T& e) { return e.template to_native_type(); }; PublicInputs pis = { diff --git a/circuits/cpp/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp b/circuits/cpp/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp index e178da3d123..4db22b90109 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp @@ -5,16 +5,16 @@ #include "state_read.hpp" #include "../../constants.hpp" -#include -#include -#include -#include +#include +#include +#include +#include namespace aztec3::circuits::abis { +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; using plonk::stdlib::witness_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; template struct PublicCircuitPublicInputs { typedef typename NCT::fr fr; @@ -70,7 +70,7 @@ template struct PublicCircuitPublicInputs { static_assert((std::is_same::value)); // Capture the composer: - auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(composer, e); }; auto to_circuit_type = [&](auto& e) { return e.to_circuit_type(composer); }; PublicCircuitPublicInputs> pis = { diff --git a/circuits/cpp/src/aztec3/circuits/abis/signed_tx_request.hpp b/circuits/cpp/src/aztec3/circuits/abis/signed_tx_request.hpp index 1be3f6b4f8f..1892d58ae3d 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/signed_tx_request.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/signed_tx_request.hpp @@ -2,16 +2,16 @@ #include "tx_request.hpp" -#include -#include -#include -#include +#include +#include +#include +#include namespace aztec3::circuits::abis { +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; using plonk::stdlib::witness_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; template struct SignedTxRequest { TxRequest tx_request; @@ -22,7 +22,7 @@ template struct SignedTxRequest { static_assert((std::is_same::value)); // Capture the composer: - // auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + // auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(composer, e); }; auto to_circuit_type = [&](auto& e) { return e.to_circuit_type(composer); }; SignedTxRequest> signed_tx_request = { diff --git a/circuits/cpp/src/aztec3/circuits/abis/state_read.hpp b/circuits/cpp/src/aztec3/circuits/abis/state_read.hpp index 2c7167ab540..de45f65cc09 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/state_read.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/state_read.hpp @@ -1,14 +1,14 @@ #pragma once -#include -#include -#include -#include +#include +#include +#include +#include namespace aztec3::circuits::abis { +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; using plonk::stdlib::witness_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; template struct StateRead { typedef typename NCT::fr fr; @@ -25,7 +25,7 @@ template struct StateRead { static_assert((std::is_same::value)); // Capture the composer: - auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(composer, e); }; StateRead> state_read = { to_ct(storage_slot), diff --git a/circuits/cpp/src/aztec3/circuits/abis/state_transition.hpp b/circuits/cpp/src/aztec3/circuits/abis/state_transition.hpp index ecafc975754..410e547ac19 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/state_transition.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/state_transition.hpp @@ -1,14 +1,14 @@ #pragma once -#include -#include -#include -#include +#include +#include +#include +#include namespace aztec3::circuits::abis { +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; using plonk::stdlib::witness_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; template struct StateTransition { typedef typename NCT::fr fr; @@ -26,7 +26,7 @@ template struct StateTransition { static_assert((std::is_same::value)); // Capture the composer: - auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(composer, e); }; StateTransition> state_transition = { to_ct(storage_slot), diff --git a/circuits/cpp/src/aztec3/circuits/abis/tx_context.hpp b/circuits/cpp/src/aztec3/circuits/abis/tx_context.hpp index a4cacf561e0..98f0573e34f 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/tx_context.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/tx_context.hpp @@ -1,18 +1,18 @@ #pragma once #include "contract_deployment_data.hpp" #include "function_data.hpp" -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include namespace aztec3::circuits::abis { +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; using plonk::stdlib::witness_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; template struct TxContext { typedef typename NCT::address address; @@ -33,7 +33,7 @@ template struct TxContext { static_assert((std::is_same::value)); // Capture the composer: - auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(composer, e); }; // auto to_circuit_type = [&](auto& e) { return e.to_circuit_type(composer); }; TxContext> tx_context = { @@ -48,7 +48,7 @@ template struct TxContext { template TxContext to_native_type() const { static_assert(std::is_same, NCT>::value); - auto to_nt = [&](auto& e) { return plonk::stdlib::types::to_nt(e); }; + auto to_nt = [&](auto& e) { return aztec3::utils::types::to_nt(e); }; auto to_native_type = [](T& e) { return e.template to_native_type(); }; TxContext tx_context = { diff --git a/circuits/cpp/src/aztec3/circuits/abis/tx_request.hpp b/circuits/cpp/src/aztec3/circuits/abis/tx_request.hpp index 9c3cff89a0f..ce177ea293e 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/tx_request.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/tx_request.hpp @@ -1,16 +1,16 @@ #pragma once #include "function_data.hpp" #include "tx_context.hpp" -#include -#include -#include -#include +#include +#include +#include +#include namespace aztec3::circuits::abis { +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; using plonk::stdlib::witness_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; template struct TxRequest { typedef typename NCT::address address; @@ -31,7 +31,7 @@ template struct TxRequest { static_assert((std::is_same::value)); // Capture the composer: - auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(composer, e); }; auto to_circuit_type = [&](auto& e) { return e.to_circuit_type(composer); }; TxRequest> tx_request = { diff --git a/circuits/cpp/src/aztec3/circuits/apps/.test.cpp b/circuits/cpp/src/aztec3/circuits/apps/.test.cpp index 4fb28eb6814..2a9bdb917a2 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/apps/.test.cpp @@ -1,10 +1,10 @@ -// #include -// #include -// #include +// #include +// #include +// #include #include -#include +#include // #include "utxo_state_var.hpp" @@ -28,19 +28,19 @@ #include -#include -#include -#include -#include +#include +#include +#include +#include namespace { // Composer using C = plonk::stdlib::types::Composer; // Types -using CT = plonk::stdlib::types::CircuitTypes; -using NT = plonk::stdlib::types::NativeTypes; -using plonk::stdlib::types::to_ct; +using CT = aztec3::utils::types::CircuitTypes; +using NT = aztec3::utils::types::NativeTypes; +using aztec3::utils::types::to_ct; // exec_ctx // using aztec3::circuits::apps::FunctionExecutionContext; diff --git a/circuits/cpp/src/aztec3/circuits/apps/contract.hpp b/circuits/cpp/src/aztec3/circuits/apps/contract.hpp index bcd125aaafa..e7741e0f262 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/contract.hpp +++ b/circuits/cpp/src/aztec3/circuits/apps/contract.hpp @@ -5,15 +5,15 @@ #include -#include +#include namespace aztec3::circuits::apps { using aztec3::circuits::abis::FunctionData; +using aztec3::utils::types::CircuitTypes; using plonk::stdlib::witness_t; -using plonk::stdlib::types::CircuitTypes; -using NT = plonk::stdlib::types::NativeTypes; +using NT = aztec3::utils::types::NativeTypes; // template class FunctionExecutionContext; diff --git a/circuits/cpp/src/aztec3/circuits/apps/contract.tpp b/circuits/cpp/src/aztec3/circuits/apps/contract.tpp index cc335d5cd0a..495ea4187c4 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/contract.tpp +++ b/circuits/cpp/src/aztec3/circuits/apps/contract.tpp @@ -3,19 +3,19 @@ #include "function_declaration.hpp" #include "l1_function_interface.hpp" -#include +#include #include #include -#include +#include namespace aztec3::circuits::apps { +using aztec3::utils::types::CircuitTypes; using plonk::stdlib::witness_t; -using plonk::stdlib::types::CircuitTypes; -using NT = plonk::stdlib::types::NativeTypes; +using NT = aztec3::utils::types::NativeTypes; using aztec3::circuits::abis::FunctionData; // using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; diff --git a/circuits/cpp/src/aztec3/circuits/apps/function_declaration.hpp b/circuits/cpp/src/aztec3/circuits/apps/function_declaration.hpp index 7289204d3e4..8519953727a 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/function_declaration.hpp +++ b/circuits/cpp/src/aztec3/circuits/apps/function_declaration.hpp @@ -1,14 +1,14 @@ #pragma once -#include -#include -#include -#include +#include +#include +#include +#include namespace aztec3::circuits::apps { +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; using plonk::stdlib::witness_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; // This exists just so that designated initialisers can be used when passing this info to a function, for readability. template struct FunctionDeclaration { diff --git a/circuits/cpp/src/aztec3/circuits/apps/function_execution_context.hpp b/circuits/cpp/src/aztec3/circuits/apps/function_execution_context.hpp index 2216f38b23a..1b5169d5155 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/function_execution_context.hpp +++ b/circuits/cpp/src/aztec3/circuits/apps/function_execution_context.hpp @@ -13,11 +13,11 @@ #include #include -#include +#include -#include +#include -#include +#include namespace aztec3::circuits::apps { @@ -32,11 +32,11 @@ using aztec3::circuits::apps::opcodes::Opcodes; using plonk::stdlib::array_push; +using aztec3::utils::types::CircuitTypes; using plonk::stdlib::witness_t; -using plonk::stdlib::types::CircuitTypes; -using NT = plonk::stdlib::types::NativeTypes; -using plonk::stdlib::types::to_ct; -using plonk::stdlib::types::to_nt; +using NT = aztec3::utils::types::NativeTypes; +using aztec3::utils::types::to_ct; +using aztec3::utils::types::to_nt; template class FunctionExecutionContext { typedef NativeTypes NT; diff --git a/circuits/cpp/src/aztec3/circuits/apps/l1_call.hpp b/circuits/cpp/src/aztec3/circuits/apps/l1_call.hpp index 005bef3eba3..e7f22fbcdd1 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/l1_call.hpp +++ b/circuits/cpp/src/aztec3/circuits/apps/l1_call.hpp @@ -2,16 +2,16 @@ #include "l1_function_interface.hpp" -#include -#include -#include -#include +#include +#include +#include +#include namespace aztec3::circuits::apps { +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; using plonk::stdlib::witness_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; template class L1Call { typedef typename CircuitTypes::fr fr; @@ -44,7 +44,7 @@ template class L1Call { static_assert((std::is_same::value)); // Capture the composer: - auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(composer, e); }; L1Call> l1_call = { l1_function.to_circuit_type(composer), to_ct(args), diff --git a/circuits/cpp/src/aztec3/circuits/apps/l1_function_interface.hpp b/circuits/cpp/src/aztec3/circuits/apps/l1_function_interface.hpp index b388c85cdea..70c665dcc1f 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/l1_function_interface.hpp +++ b/circuits/cpp/src/aztec3/circuits/apps/l1_function_interface.hpp @@ -1,14 +1,14 @@ #pragma once -#include -#include -#include -#include +#include +#include +#include +#include namespace aztec3::circuits::apps { +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; using plonk::stdlib::witness_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; template class Contract; diff --git a/circuits/cpp/src/aztec3/circuits/apps/l1_function_interface.tpp b/circuits/cpp/src/aztec3/circuits/apps/l1_function_interface.tpp index c22c2f1f92c..81f3a5ec34e 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/l1_function_interface.tpp +++ b/circuits/cpp/src/aztec3/circuits/apps/l1_function_interface.tpp @@ -1,7 +1,7 @@ -// #include -// #include -// #include -// #include +// #include +// #include +// #include +// #include // #include "contract.hpp" // #include "l1_promise.hpp" // #include "l1_result.hpp" @@ -9,8 +9,8 @@ // namespace aztec3::circuits::apps { // using plonk::stdlib::witness_t; -// using plonk::stdlib::types::CircuitTypes; -// using plonk::stdlib::types::NativeTypes; +// using aztec3::utils::types::CircuitTypes; +// using aztec3::utils::types::NativeTypes; // template // std::pair, L1Result> L1FunctionInterface::call(std::vector args) diff --git a/circuits/cpp/src/aztec3/circuits/apps/notes/default_private_note/note.hpp b/circuits/cpp/src/aztec3/circuits/apps/notes/default_private_note/note.hpp index 10e571a5a94..4f89ac10620 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/notes/default_private_note/note.hpp +++ b/circuits/cpp/src/aztec3/circuits/apps/notes/default_private_note/note.hpp @@ -5,8 +5,8 @@ #include "note_preimage.hpp" #include "nullifier_preimage.hpp" -#include -#include +#include +#include // Forward-declare from this namespace in particular: namespace aztec3::circuits::apps::state_vars { @@ -17,8 +17,8 @@ namespace aztec3::circuits::apps::notes { using aztec3::circuits::apps::state_vars::StateVar; // Don't #include it! -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; template class DefaultPrivateNote : public NoteInterface { public: diff --git a/circuits/cpp/src/aztec3/circuits/apps/notes/default_private_note/note.tpp b/circuits/cpp/src/aztec3/circuits/apps/notes/default_private_note/note.tpp index 3c614eb9cdd..f34bd115202 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/notes/default_private_note/note.tpp +++ b/circuits/cpp/src/aztec3/circuits/apps/notes/default_private_note/note.tpp @@ -8,16 +8,16 @@ #include "../../state_vars/state_var_base.hpp" -#include +#include -#include +#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include namespace { using aztec3::circuits::apps::opcodes::Opcodes; @@ -30,9 +30,9 @@ using aztec3::GeneratorIndex; using crypto::generators::generator_index_t; +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; using plonk::stdlib::witness_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; template void DefaultPrivateNote::remove() { diff --git a/circuits/cpp/src/aztec3/circuits/apps/notes/default_private_note/note_preimage.hpp b/circuits/cpp/src/aztec3/circuits/apps/notes/default_private_note/note_preimage.hpp index 519bf02dc00..fb01629bf70 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/notes/default_private_note/note_preimage.hpp +++ b/circuits/cpp/src/aztec3/circuits/apps/notes/default_private_note/note_preimage.hpp @@ -1,19 +1,19 @@ #pragma once -#include -#include +#include +#include -#include +#include -#include -#include -#include +#include +#include +#include namespace aztec3::circuits::apps::notes { +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; using crypto::generators::generator_index_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; template struct DefaultPrivateNotePreimage { typedef typename NCT::fr fr; @@ -40,7 +40,7 @@ template struct DefaultPrivateNotePreimage { static_assert((std::is_same::value)); // Capture the composer: - auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(composer, e); }; // Depending on whether the _circuit_ type version of `V` is from the stdlib, or some custom type, the // conversion method will be different. @@ -77,7 +77,7 @@ template struct DefaultPrivateNotePreimage { static_assert(!std::is_same::value); - auto to_nt = [&](auto& e) { return plonk::stdlib::types::to_nt(e); }; + auto to_nt = [&](auto& e) { return aztec3::utils::types::to_nt(e); }; // See `to_circuit_type()` for explanation of this code. const bool has_to_native_type = requires(V v) { v.to_native_type(); }; diff --git a/circuits/cpp/src/aztec3/circuits/apps/notes/default_private_note/nullifier_preimage.hpp b/circuits/cpp/src/aztec3/circuits/apps/notes/default_private_note/nullifier_preimage.hpp index e40478c2faf..a8d4cf802ea 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/notes/default_private_note/nullifier_preimage.hpp +++ b/circuits/cpp/src/aztec3/circuits/apps/notes/default_private_note/nullifier_preimage.hpp @@ -1,18 +1,18 @@ #pragma once -#include -#include +#include +#include -#include +#include -#include -#include -#include +#include +#include +#include namespace aztec3::circuits::apps::notes { +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; using crypto::generators::generator_index_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; template struct DefaultPrivateNoteNullifierPreimage { typedef typename NCT::fr fr; @@ -30,7 +30,7 @@ template struct DefaultPrivateNoteNullifierPreimage { static_assert((std::is_same::value)); // Capture the composer: - auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(composer, e); }; DefaultPrivateNoteNullifierPreimage> preimage = { to_ct(commitment), diff --git a/circuits/cpp/src/aztec3/circuits/apps/notes/default_singleton_private_note/note.hpp b/circuits/cpp/src/aztec3/circuits/apps/notes/default_singleton_private_note/note.hpp index 1888b1f0c19..375525f8995 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/notes/default_singleton_private_note/note.hpp +++ b/circuits/cpp/src/aztec3/circuits/apps/notes/default_singleton_private_note/note.hpp @@ -5,8 +5,8 @@ #include "note_preimage.hpp" #include "nullifier_preimage.hpp" -#include -#include +#include +#include // Forward-declare from this namespace in particular: namespace aztec3::circuits::apps::state_vars { @@ -17,8 +17,8 @@ namespace aztec3::circuits::apps::notes { using aztec3::circuits::apps::state_vars::StateVar; // Don't #include it! -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; template class DefaultSingletonPrivateNote : public NoteInterface { public: diff --git a/circuits/cpp/src/aztec3/circuits/apps/notes/default_singleton_private_note/note.tpp b/circuits/cpp/src/aztec3/circuits/apps/notes/default_singleton_private_note/note.tpp index 6d93efa868a..a2f253389a7 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/notes/default_singleton_private_note/note.tpp +++ b/circuits/cpp/src/aztec3/circuits/apps/notes/default_singleton_private_note/note.tpp @@ -8,16 +8,16 @@ #include "../../state_vars/state_var_base.hpp" -#include +#include -#include +#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include namespace { using aztec3::circuits::apps::opcodes::Opcodes; @@ -30,9 +30,9 @@ using aztec3::GeneratorIndex; using crypto::generators::generator_index_t; +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; using plonk::stdlib::witness_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; template void DefaultSingletonPrivateNote::remove() { diff --git a/circuits/cpp/src/aztec3/circuits/apps/notes/default_singleton_private_note/note_preimage.hpp b/circuits/cpp/src/aztec3/circuits/apps/notes/default_singleton_private_note/note_preimage.hpp index 884adffb96f..e01695fa787 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/notes/default_singleton_private_note/note_preimage.hpp +++ b/circuits/cpp/src/aztec3/circuits/apps/notes/default_singleton_private_note/note_preimage.hpp @@ -1,19 +1,19 @@ #pragma once -#include -#include +#include +#include -#include +#include -#include -#include -#include +#include +#include +#include namespace aztec3::circuits::apps::notes { +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; using crypto::generators::generator_index_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; template struct DefaultSingletonPrivateNotePreimage { typedef typename NCT::fr fr; @@ -36,7 +36,7 @@ template struct DefaultSingletonPrivateNotePreimage { static_assert((std::is_same::value)); // Capture the composer: - auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(composer, e); }; // Depending on whether the _circuit_ type version of `V` is from the stdlib, or some custom type, the // conversion method will be different. @@ -76,7 +76,7 @@ template struct DefaultSingletonPrivateNotePreimage { static_assert(!std::is_same::value); - auto to_nt = [&](auto& e) { return plonk::stdlib::types::to_nt(e); }; + auto to_nt = [&](auto& e) { return aztec3::utils::types::to_nt(e); }; // See `to_circuit_type()` for explanation of this code. const bool has_to_native_type = requires(V v) { v.to_native_type(); }; diff --git a/circuits/cpp/src/aztec3/circuits/apps/notes/default_singleton_private_note/nullifier_preimage.hpp b/circuits/cpp/src/aztec3/circuits/apps/notes/default_singleton_private_note/nullifier_preimage.hpp index 89de5176b70..83602d14eb7 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/notes/default_singleton_private_note/nullifier_preimage.hpp +++ b/circuits/cpp/src/aztec3/circuits/apps/notes/default_singleton_private_note/nullifier_preimage.hpp @@ -1,18 +1,18 @@ #pragma once -#include -#include +#include +#include -#include +#include -#include -#include -#include +#include +#include +#include namespace aztec3::circuits::apps::notes { +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; using crypto::generators::generator_index_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; template struct DefaultSingletonPrivateNoteNullifierPreimage { typedef typename NCT::fr fr; @@ -30,7 +30,7 @@ template struct DefaultSingletonPrivateNoteNullifierPreimage { static_assert((std::is_same::value)); // Capture the composer: - auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(composer, e); }; DefaultSingletonPrivateNoteNullifierPreimage> preimage = { to_ct(commitment), diff --git a/circuits/cpp/src/aztec3/circuits/apps/notes/note_interface.hpp b/circuits/cpp/src/aztec3/circuits/apps/notes/note_interface.hpp index 1ab3bed2ca0..a3ecb73cbd1 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/notes/note_interface.hpp +++ b/circuits/cpp/src/aztec3/circuits/apps/notes/note_interface.hpp @@ -1,12 +1,12 @@ #pragma once -#include -#include +#include +#include namespace aztec3::circuits::apps::notes { -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; /** * Note: The methods in this interface must be implemented by the derived Note types, even if such note types don't diff --git a/circuits/cpp/src/aztec3/circuits/apps/opcodes/opcodes.hpp b/circuits/cpp/src/aztec3/circuits/apps/opcodes/opcodes.hpp index 8d2e0c3f634..e75a1eca7b0 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/opcodes/opcodes.hpp +++ b/circuits/cpp/src/aztec3/circuits/apps/opcodes/opcodes.hpp @@ -1,8 +1,8 @@ #pragma once -#include -#include -#include +#include +#include +#include namespace aztec3::circuits::apps::state_vars { template class StateVar; @@ -16,9 +16,9 @@ using aztec3::circuits::apps::state_vars::StateVar; // Don't #include it! using aztec3::circuits::apps::state_vars::UTXOSetStateVar; // Don't #include it! using aztec3::circuits::apps::state_vars::UTXOStateVar; // Don't #include it! +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; using plonk::stdlib::witness_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; /** * @brief - These static methods are a suggestion for what ACIR++ 'Opcodes' might do. They can get diff --git a/circuits/cpp/src/aztec3/circuits/apps/opcodes/opcodes.tpp b/circuits/cpp/src/aztec3/circuits/apps/opcodes/opcodes.tpp index 958135f1b4b..5b0fba4055d 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/opcodes/opcodes.tpp +++ b/circuits/cpp/src/aztec3/circuits/apps/opcodes/opcodes.tpp @@ -7,9 +7,9 @@ #include "../state_vars/utxo_state_var.hpp" #include "../state_vars/utxo_set_state_var.hpp" -#include -#include -#include +#include +#include +#include namespace { // Declared here, so that `opcodes.hpp` doesn't see it; thereby preventing circular dependencies. @@ -22,9 +22,9 @@ namespace aztec3::circuits::apps::opcodes { using aztec3::circuits::apps::FunctionExecutionContext; +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; using plonk::stdlib::witness_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; template template diff --git a/circuits/cpp/src/aztec3/circuits/apps/oracle_wrapper.hpp b/circuits/cpp/src/aztec3/circuits/apps/oracle_wrapper.hpp index 20edde26f45..ed0453a4431 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/oracle_wrapper.hpp +++ b/circuits/cpp/src/aztec3/circuits/apps/oracle_wrapper.hpp @@ -2,18 +2,18 @@ #include #include -#include +#include -#include -#include -#include +#include +#include +#include namespace aztec3::circuits::apps { -using NT = plonk::stdlib::types::NativeTypes; +using NT = aztec3::utils::types::NativeTypes; using aztec3::circuits::abis::CallContext; using aztec3::oracle::NativeOracle; -using plonk::stdlib::types::CircuitTypes; +using aztec3::utils::types::CircuitTypes; /** * The main purpose of this wrapper is to: @@ -44,7 +44,7 @@ template class OracleWrapperInterface { if (msg_sender_private_key) { return *msg_sender_private_key; } - msg_sender_private_key = plonk::stdlib::types::to_ct(composer, native_oracle.get_msg_sender_private_key()); + msg_sender_private_key = aztec3::utils::types::to_ct(composer, native_oracle.get_msg_sender_private_key()); validate_msg_sender_private_key(); return *msg_sender_private_key; }; @@ -66,17 +66,17 @@ template class OracleWrapperInterface { address& get_tx_origin() { return get_call_context().tx_origin; }; - fr generate_salt() const { return plonk::stdlib::types::to_ct(composer, native_oracle.generate_salt()); } + fr generate_salt() const { return aztec3::utils::types::to_ct(composer, native_oracle.generate_salt()); } fr generate_random_element() const { - return plonk::stdlib::types::to_ct(composer, native_oracle.generate_random_element()); + return aztec3::utils::types::to_ct(composer, native_oracle.generate_random_element()); } template auto get_utxo_sload_datum(grumpkin_point const& storage_slot_point, NotePreimage const& advice) { - auto native_storage_slot_point = plonk::stdlib::types::to_nt(storage_slot_point); + auto native_storage_slot_point = aztec3::utils::types::to_nt(storage_slot_point); auto native_advice = advice.template to_native_type(); @@ -90,7 +90,7 @@ template class OracleWrapperInterface { size_t const& num_notes, NotePreimage const& advice) { - auto native_storage_slot_point = plonk::stdlib::types::to_nt(storage_slot_point); + auto native_storage_slot_point = aztec3::utils::types::to_nt(storage_slot_point); auto native_advice = advice.template to_native_type(); diff --git a/circuits/cpp/src/aztec3/circuits/apps/private_state.test.cpp b/circuits/cpp/src/aztec3/circuits/apps/private_state.test.cpp index e54251ad79b..0df65efc6a6 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/private_state.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/apps/private_state.test.cpp @@ -1,20 +1,20 @@ // #include "index.hpp" // #include -// #include -// #include -// // #include -// #include +// #include +// #include +// // #include +// #include // // #include -// // #include -// // #include +// // #include +// // #include // namespace aztec3::circuits::apps { // namespace { -// using Composer = plonk::stdlib::types::Composer; -// using CT = plonk::stdlib::types::CircuitTypes; -// using NT = plonk::stdlib::types::NativeTypes; +// using Composer = aztec3::utils::types:plonk::stdlib::types::Composer; +// using CT = aztec3::utils::types::CircuitTypes; +// using NT = aztec3::utils::types::NativeTypes; // // using plonk::stdlib::pedersen; // } // namespace diff --git a/circuits/cpp/src/aztec3/circuits/apps/state_vars/field_state_var.hpp b/circuits/cpp/src/aztec3/circuits/apps/state_vars/field_state_var.hpp index 21d450f75ad..37bdf9bfc54 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/state_vars/field_state_var.hpp +++ b/circuits/cpp/src/aztec3/circuits/apps/state_vars/field_state_var.hpp @@ -3,13 +3,13 @@ #include "state_var_base.hpp" #include "../function_execution_context.hpp" -#include -#include +#include +#include namespace aztec3::circuits::apps::state_vars { -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; // TODO: we can probably generalise this to be a PrimitiveStateVar for any stdlib primitive. template class FieldStateVar : public StateVar { diff --git a/circuits/cpp/src/aztec3/circuits/apps/state_vars/mapping_state_var.hpp b/circuits/cpp/src/aztec3/circuits/apps/state_vars/mapping_state_var.hpp index 0f3916345b9..e697f6e7923 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/state_vars/mapping_state_var.hpp +++ b/circuits/cpp/src/aztec3/circuits/apps/state_vars/mapping_state_var.hpp @@ -3,8 +3,8 @@ #include "state_var_base.hpp" // #include "../function_execution_context.hpp" -#include -#include +#include +#include // Forward-declare from this namespace in particular: namespace aztec3::circuits::apps { @@ -15,8 +15,8 @@ namespace aztec3::circuits::apps::state_vars { using aztec3::circuits::apps::FunctionExecutionContext; // Don't #include it! -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; /** * @tparam V - the value type being mapped-to by this mapping. diff --git a/circuits/cpp/src/aztec3/circuits/apps/state_vars/mapping_state_var.tpp b/circuits/cpp/src/aztec3/circuits/apps/state_vars/mapping_state_var.tpp index f60a29bd020..cf0f2ffe188 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/state_vars/mapping_state_var.tpp +++ b/circuits/cpp/src/aztec3/circuits/apps/state_vars/mapping_state_var.tpp @@ -1,5 +1,5 @@ #pragma once -// #include +// #include // #include "oracle_wrapper.hpp" // #include "private_state_note.hpp" // #include "private_state_note_preimage.hpp" @@ -7,15 +7,15 @@ #include "../function_execution_context.hpp" -#include "plonk/composer/turbo_composer.hpp" +#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include namespace { using aztec3::circuits::apps::FunctionExecutionContext; @@ -25,8 +25,8 @@ namespace aztec3::circuits::apps::state_vars { using crypto::generators::generator_index_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; // Fr: start_slot // diff --git a/circuits/cpp/src/aztec3/circuits/apps/state_vars/state_var_base.hpp b/circuits/cpp/src/aztec3/circuits/apps/state_vars/state_var_base.hpp index 3f311d6c446..2c425b3b563 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/state_vars/state_var_base.hpp +++ b/circuits/cpp/src/aztec3/circuits/apps/state_vars/state_var_base.hpp @@ -1,7 +1,7 @@ #pragma once -#include -#include +#include +#include // Forward-declare from this namespace in particular: namespace aztec3::circuits::apps { @@ -12,8 +12,8 @@ namespace aztec3::circuits::apps::state_vars { using aztec3::circuits::apps::FunctionExecutionContext; // Don't #include it! -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; /** * @brief StateVar is a base class from which contract state variables are derived. Its main purpose is deriving storage diff --git a/circuits/cpp/src/aztec3/circuits/apps/state_vars/state_var_base.tpp b/circuits/cpp/src/aztec3/circuits/apps/state_vars/state_var_base.tpp index d6db3ec3076..4592bf55006 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/state_vars/state_var_base.tpp +++ b/circuits/cpp/src/aztec3/circuits/apps/state_vars/state_var_base.tpp @@ -2,12 +2,12 @@ #include "../function_execution_context.hpp" -#include +#include -#include +#include -#include -#include +#include +#include namespace { using aztec3::circuits::apps::FunctionExecutionContext; @@ -15,8 +15,8 @@ using aztec3::circuits::apps::FunctionExecutionContext; namespace aztec3::circuits::apps::state_vars { +using aztec3::utils::types::CircuitTypes; using crypto::generators::generator_index_t; -using plonk::stdlib::types::CircuitTypes; template StateVar::StateVar(FunctionExecutionContext* exec_ctx, std::string const& state_var_name) diff --git a/circuits/cpp/src/aztec3/circuits/apps/state_vars/utxo_set_state_var.hpp b/circuits/cpp/src/aztec3/circuits/apps/state_vars/utxo_set_state_var.hpp index 56dc448035d..1209a3c277e 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/state_vars/utxo_set_state_var.hpp +++ b/circuits/cpp/src/aztec3/circuits/apps/state_vars/utxo_set_state_var.hpp @@ -2,8 +2,8 @@ #include "state_var_base.hpp" -#include -#include +#include +#include // Forward-declare from this namespace in particular: namespace aztec3::circuits::apps { @@ -14,8 +14,8 @@ namespace aztec3::circuits::apps::state_vars { using aztec3::circuits::apps::FunctionExecutionContext; // Don't #include it! -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; /** * @brief - A derived StateVar which represents an unordered set of UTXOs which live in the UTXO tree. diff --git a/circuits/cpp/src/aztec3/circuits/apps/state_vars/utxo_set_state_var.tpp b/circuits/cpp/src/aztec3/circuits/apps/state_vars/utxo_set_state_var.tpp index 850f888d8de..87ceac2ed5f 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/state_vars/utxo_set_state_var.tpp +++ b/circuits/cpp/src/aztec3/circuits/apps/state_vars/utxo_set_state_var.tpp @@ -2,8 +2,8 @@ #include "../opcodes/opcodes.hpp" -#include -#include +#include +#include namespace { using aztec3::circuits::apps::opcodes::Opcodes; diff --git a/circuits/cpp/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp b/circuits/cpp/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp index d3723691cd3..060821fdfaa 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp +++ b/circuits/cpp/src/aztec3/circuits/apps/state_vars/utxo_state_var.hpp @@ -2,8 +2,8 @@ #include "state_var_base.hpp" -#include -#include +#include +#include // Forward-declare from this namespace in particular: namespace aztec3::circuits::apps { @@ -14,8 +14,8 @@ namespace aztec3::circuits::apps::state_vars { using aztec3::circuits::apps::FunctionExecutionContext; // Don't #include it! -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; /** * @brief - A derived StateVar which represents a singleton UTXO type. I.e. a state which can only ever have at-most ONE diff --git a/circuits/cpp/src/aztec3/circuits/apps/state_vars/utxo_state_var.tpp b/circuits/cpp/src/aztec3/circuits/apps/state_vars/utxo_state_var.tpp index 1d5c757c0bc..e76b66af1be 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/state_vars/utxo_state_var.tpp +++ b/circuits/cpp/src/aztec3/circuits/apps/state_vars/utxo_state_var.tpp @@ -2,8 +2,8 @@ #include "../opcodes/opcodes.hpp" -#include -#include +#include +#include namespace { using aztec3::circuits::apps::opcodes::Opcodes; diff --git a/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp b/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp index f17cf148426..fac8f03d6c4 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp @@ -7,10 +7,10 @@ // #include #include -#include -// #include -// #include -// #include +#include +// #include +// #include +// #include namespace aztec3::circuits::apps::test_apps::escrow { diff --git a/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/init.hpp b/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/init.hpp index 8f7542d9c15..9673999342e 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/init.hpp +++ b/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/init.hpp @@ -9,17 +9,17 @@ #include #include -#include -#include -#include -#include +#include +#include +#include +#include namespace aztec3::circuits::apps::test_apps::escrow { using C = plonk::stdlib::types::Composer; -using CT = plonk::stdlib::types::CircuitTypes; -using NT = plonk::stdlib::types::NativeTypes; +using CT = aztec3::utils::types::CircuitTypes; +using NT = aztec3::utils::types::NativeTypes; using DB = oracle::FakeDB; using oracle::NativeOracle; @@ -28,7 +28,7 @@ using OracleWrapper = apps::OracleWrapperInterface; using Contract = apps::Contract; using FunctionExecutionContext = apps::FunctionExecutionContext; -using plonk::stdlib::types::to_ct; +using aztec3::utils::types::to_ct; // StateVars using apps::state_vars::MappingStateVar; diff --git a/circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp b/circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp index e93f68566dd..990d2e93de1 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp @@ -6,7 +6,7 @@ // #include #include -#include +#include namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { diff --git a/circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/init.hpp b/circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/init.hpp index 348ce4c3e47..fc7f51e21a2 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/init.hpp +++ b/circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/init.hpp @@ -8,16 +8,16 @@ #include -#include -#include -#include -#include +#include +#include +#include +#include namespace aztec3::circuits::apps::test_apps::private_to_private_function_call { using C = plonk::stdlib::types::Composer; -using CT = plonk::stdlib::types::CircuitTypes; -using NT = plonk::stdlib::types::NativeTypes; +using CT = aztec3::utils::types::CircuitTypes; +using NT = aztec3::utils::types::NativeTypes; using DB = oracle::FakeDB; using oracle::NativeOracle; @@ -26,7 +26,7 @@ using OracleWrapper = OracleWrapperInterface; using Contract = apps::Contract; using FunctionExecutionContext = apps::FunctionExecutionContext; -using plonk::stdlib::types::to_ct; +using aztec3::utils::types::to_ct; // StateVars using apps::state_vars::UTXOStateVar; diff --git a/circuits/cpp/src/aztec3/circuits/apps/utxo_datum.hpp b/circuits/cpp/src/aztec3/circuits/apps/utxo_datum.hpp index 26c66506bfd..fb9018c3191 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/utxo_datum.hpp +++ b/circuits/cpp/src/aztec3/circuits/apps/utxo_datum.hpp @@ -1,14 +1,14 @@ #pragma once -#include -#include -#include +#include +#include +#include namespace aztec3::circuits::apps { +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; using plonk::stdlib::witness_t; -using plonk::stdlib::types::CircuitTypes; -using plonk::stdlib::types::NativeTypes; /** * @tparam NCT - NativeTypes or CircuitTypes @@ -32,7 +32,7 @@ template struct UTXOSLoadDatum { static_assert(std::is_same::value); // Capture the composer: - auto to_ct = [&](auto& e) { return plonk::stdlib::types::to_ct(composer, e); }; + auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(composer, e); }; auto preimage_ct = preimage.to_circuit_type(composer); diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/.test.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/.test.cpp index 1be1f52c2a0..20abb061eb8 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/.test.cpp @@ -1,8 +1,8 @@ -// #include -// #include +// #include +// #include // #include // #include -// #include +// #include #include "index.hpp" #include "init.hpp" @@ -30,13 +30,13 @@ // #include #include -#include -#include +#include +#include #include // #include -// #include -// #include +// #include +// #include namespace { diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/init.hpp b/circuits/cpp/src/aztec3/circuits/kernel/private/init.hpp index 5e352e851e3..92d36e41da2 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/init.hpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/init.hpp @@ -7,10 +7,10 @@ #include -#include -#include -#include -#include +#include +#include +#include +#include namespace aztec3::circuits::kernel::private_kernel { @@ -21,9 +21,9 @@ using plonk::stdlib::types::Prover; using Aggregator = aztec3::circuits::recursion::Aggregator; // Generic: -using CT = plonk::stdlib::types::CircuitTypes; -using NT = plonk::stdlib::types::NativeTypes; -using plonk::stdlib::types::to_ct; +using CT = aztec3::utils::types::CircuitTypes; +using NT = aztec3::utils::types::NativeTypes; +using aztec3::utils::types::to_ct; using DB = oracle::FakeDB; using oracle::NativeOracle; diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp index 5c27af89317..26683d0f9f2 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp @@ -1,6 +1,6 @@ #include "init.hpp" -#include +#include #include #include diff --git a/circuits/cpp/src/aztec3/circuits/mock/mock_circuit.hpp b/circuits/cpp/src/aztec3/circuits/mock/mock_circuit.hpp index 548f6255b32..6cfa13c138b 100644 --- a/circuits/cpp/src/aztec3/circuits/mock/mock_circuit.hpp +++ b/circuits/cpp/src/aztec3/circuits/mock/mock_circuit.hpp @@ -1,7 +1,7 @@ #pragma once -#include -#include -#include +#include +#include +#include namespace aztec3::circuits::mock { diff --git a/circuits/cpp/src/aztec3/circuits/mock/mock_kernel_circuit.hpp b/circuits/cpp/src/aztec3/circuits/mock/mock_kernel_circuit.hpp index 9245a9cddf3..e1391330a67 100644 --- a/circuits/cpp/src/aztec3/circuits/mock/mock_kernel_circuit.hpp +++ b/circuits/cpp/src/aztec3/circuits/mock/mock_kernel_circuit.hpp @@ -1,11 +1,11 @@ #pragma once -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include // #include @@ -16,10 +16,10 @@ auto& engine = numeric::random::get_debug_engine(); namespace aztec3::circuits::mock { using aztec3::circuits::abis::private_kernel::PublicInputs; -using NT = plonk::stdlib::types::NativeTypes; +using NT = aztec3::utils::types::NativeTypes; +using aztec3::utils::types::CircuitTypes; using plonk::stdlib::pedersen_commitment; using plonk::stdlib::witness_t; -using plonk::stdlib::types::CircuitTypes; template void mock_kernel_circuit(Composer& composer, PublicInputs const& _public_inputs) { diff --git a/circuits/cpp/src/aztec3/circuits/recursion/aggregator.hpp b/circuits/cpp/src/aztec3/circuits/recursion/aggregator.hpp index 41523c02f27..5e4e7dbf22e 100644 --- a/circuits/cpp/src/aztec3/circuits/recursion/aggregator.hpp +++ b/circuits/cpp/src/aztec3/circuits/recursion/aggregator.hpp @@ -1,9 +1,9 @@ -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include namespace aztec3::circuits::recursion { @@ -12,10 +12,10 @@ namespace aztec3::circuits::recursion { using plonk::stdlib::types::recursive_inner_verifier_settings; // using plonk::stdlib::recursion::verification_key; using plonk::stdlib::recursion::verify_proof; -// using plonk::stdlib::types::bn254; +// using aztec3::utils::types::bn254; using plonk::stdlib::types::Composer; -using CT = plonk::stdlib::types::CircuitTypes; -using NT = plonk::stdlib::types::NativeTypes; +using CT = aztec3::utils::types::CircuitTypes; +using NT = aztec3::utils::types::NativeTypes; using transcript::Manifest; // class Aggregator { diff --git a/circuits/cpp/src/aztec3/circuits/recursion/play.test.cpp b/circuits/cpp/src/aztec3/circuits/recursion/play.test.cpp index 979f48632c3..3ff08d718f2 100644 --- a/circuits/cpp/src/aztec3/circuits/recursion/play.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/recursion/play.test.cpp @@ -1,11 +1,11 @@ #include "index.hpp" -#include -// #include -#include +#include +// #include +#include namespace aztec3::circuits::recursion { -using namespace plonk::stdlib::types; +using namespace aztec3::utils::types; using plonk::stdlib::recursion::recursion_output; // namespace { diff --git a/circuits/cpp/src/aztec3/circuits/recursion/play_app_circuit.hpp b/circuits/cpp/src/aztec3/circuits/recursion/play_app_circuit.hpp index 0c3446d6286..4dfbda9e13b 100644 --- a/circuits/cpp/src/aztec3/circuits/recursion/play_app_circuit.hpp +++ b/circuits/cpp/src/aztec3/circuits/recursion/play_app_circuit.hpp @@ -1,4 +1,4 @@ -#include +#include namespace aztec3::circuits::recursion { diff --git a/circuits/cpp/src/aztec3/circuits/recursion/play_recursive_circuit.hpp b/circuits/cpp/src/aztec3/circuits/recursion/play_recursive_circuit.hpp index f43b0455899..a6d2db8c623 100644 --- a/circuits/cpp/src/aztec3/circuits/recursion/play_recursive_circuit.hpp +++ b/circuits/cpp/src/aztec3/circuits/recursion/play_recursive_circuit.hpp @@ -1,13 +1,13 @@ -// #include -// #include -// #include -// #include +// #include +// #include +// #include +// #include namespace aztec3::circuits::recursion { using plonk::stdlib::types::Composer; -using CT = plonk::stdlib::types::CircuitTypes; -using NT = plonk::stdlib::types::NativeTypes; +using CT = aztec3::utils::types::CircuitTypes; +using NT = aztec3::utils::types::NativeTypes; CT::AggregationObject play_recursive_circuit(Composer& composer, std::shared_ptr const& app_vk, diff --git a/circuits/cpp/src/aztec3/dbs/private_state_db.hpp b/circuits/cpp/src/aztec3/dbs/private_state_db.hpp index b01e364439a..e2c87218163 100644 --- a/circuits/cpp/src/aztec3/dbs/private_state_db.hpp +++ b/circuits/cpp/src/aztec3/dbs/private_state_db.hpp @@ -1,7 +1,7 @@ // // TODO: move the leveldb_store to a more neutral module. -// #include -// #include -// #include +// #include +// #include +// #include // #include "../constants.hpp" // namespace aztec3::db { diff --git a/circuits/cpp/src/aztec3/oracle/fake_db.hpp b/circuits/cpp/src/aztec3/oracle/fake_db.hpp index a37ed8be0ed..4d791f7e5f4 100644 --- a/circuits/cpp/src/aztec3/oracle/fake_db.hpp +++ b/circuits/cpp/src/aztec3/oracle/fake_db.hpp @@ -7,7 +7,7 @@ #include #include -#include +#include namespace aztec3::oracle { @@ -19,8 +19,8 @@ using aztec3::circuits::apps::notes::DefaultPrivateNotePreimage; using aztec3::circuits::apps::notes::DefaultSingletonPrivateNotePreimage; -using plonk::stdlib::types::CircuitTypes; -using NT = plonk::stdlib::types::NativeTypes; +using aztec3::utils::types::CircuitTypes; +using NT = aztec3::utils::types::NativeTypes; // A temporary stub, whilst building other things first. class FakeDB { diff --git a/circuits/cpp/src/aztec3/oracle/oracle.hpp b/circuits/cpp/src/aztec3/oracle/oracle.hpp index 6fef0525997..15dcbcc061d 100644 --- a/circuits/cpp/src/aztec3/oracle/oracle.hpp +++ b/circuits/cpp/src/aztec3/oracle/oracle.hpp @@ -10,7 +10,7 @@ #include #include -#include +#include namespace aztec3::oracle { @@ -19,8 +19,8 @@ using aztec3::circuits::abis::FunctionData; using aztec3::circuits::apps::UTXOSLoadDatum; -using plonk::stdlib::types::CircuitTypes; -using NT = plonk::stdlib::types::NativeTypes; +using aztec3::utils::types::CircuitTypes; +using NT = aztec3::utils::types::NativeTypes; /// Note: the server will always serve NATIVE types to the circuit, since eventually we'll be passing data to Noir (so /// won't be handling circuit types at all from the Aztec3 end). diff --git a/circuits/cpp/src/aztec3/utils/CMakeLists.txt b/circuits/cpp/src/aztec3/utils/CMakeLists.txt new file mode 100644 index 00000000000..71cd1e4057a --- /dev/null +++ b/circuits/cpp/src/aztec3/utils/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(types) \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/utils/types/CMakeLists.txt b/circuits/cpp/src/aztec3/utils/types/CMakeLists.txt new file mode 100644 index 00000000000..0fff1d17e9b --- /dev/null +++ b/circuits/cpp/src/aztec3/utils/types/CMakeLists.txt @@ -0,0 +1,4 @@ +barretenberg_module( + aztec3_types + barretenberg +) \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/utils/types/circuit_types.hpp b/circuits/cpp/src/aztec3/utils/types/circuit_types.hpp new file mode 100644 index 00000000000..308b89485d4 --- /dev/null +++ b/circuits/cpp/src/aztec3/utils/types/circuit_types.hpp @@ -0,0 +1,91 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "native_types.hpp" + +namespace aztec3::utils::types { + +template struct CircuitTypes { + typedef stdlib::bool_t boolean; + + typedef stdlib::uint8 uint8; + typedef stdlib::uint16 uint16; + typedef stdlib::uint32 uint32; + typedef stdlib::uint64 uint64; + + typedef stdlib::field_t fr; // of altbn + typedef stdlib::safe_uint_t safe_fr; + typedef stdlib::address_t address; + + typedef stdlib::bigfield fq; // of altbn + + // typedef fq grumpkin_fr; + // typedef fr grumpkin_fq; + typedef stdlib::point grumpkin_point; // affine + typedef stdlib::group grumpkin_group; + + typedef stdlib::bn254 bn254; + // typedef bn254::g1_ct bn254_point; + typedef stdlib::element bn254_point; // affine + + typedef stdlib::bit_array bit_array; + typedef stdlib::byte_array byte_array; + typedef stdlib::packed_byte_array packed_byte_array; + + typedef stdlib::schnorr::signature_bits schnorr_signature; + typedef stdlib::ecdsa::signature ecdsa_signature; + + typedef stdlib::recursion::recursion_output AggregationObject; + typedef stdlib::recursion::verification_key VK; + // Notice: no CircuitType for a Proof: we only ever handle native; the verify_proof() function swallows the + // 'circuit-type-ness' of the proof. + + /// TODO: lots of these compress / commit functions aren't actually used: remove them. + + // Define the 'circuit' version of the function `compress`, with the name `compress`: + static fr compress(std::vector const& inputs, const size_t hash_index = 0) + { + return plonk::stdlib::pedersen_commitment::compress(inputs, hash_index); + } + + static fr compress(std::vector const& inputs, + std::vector const& hash_sub_indices, + const size_t hash_index = 0) + { + return plonk::stdlib::pedersen_commitment::compress(inputs, hash_sub_indices, hash_index); + } + + static fr compress(const std::vector>& input_pairs) + { + return plonk::stdlib::pedersen_commitment::compress(input_pairs); + }; + + static grumpkin_point commit(const std::vector& inputs, const size_t hash_index = 0) + { + return plonk::stdlib::pedersen_commitment::commit(inputs, hash_index); + }; + + static grumpkin_point commit(const std::vector>& input_pairs) + { + return plonk::stdlib::pedersen_commitment::commit(input_pairs); + }; + + static byte_array blake2s(const byte_array& input) { return plonk::stdlib::blake2s(input); } +}; + +} // namespace aztec3::utils::types \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/utils/types/convert.hpp b/circuits/cpp/src/aztec3/utils/types/convert.hpp new file mode 100644 index 00000000000..73094c2ecd6 --- /dev/null +++ b/circuits/cpp/src/aztec3/utils/types/convert.hpp @@ -0,0 +1,254 @@ +#pragma once + +#include +#include +#include +#include "native_types.hpp" +#include "circuit_types.hpp" + +namespace aztec3::utils::types { + +using plonk::stdlib::witness_t; + +namespace { + +template using CT = aztec3::utils::types::CircuitTypes; +using NT = aztec3::utils::types::NativeTypes; + +} // namespace + +/// TODO: Lots of identical functions here (but for their in/out types). Can we use templates? I couldn't figure out how +/// to keep the NT:: or CT:: prefixes with templates. +template typename CT::boolean to_ct(Composer& composer, typename NT::boolean const& e) +{ + return typename CT::boolean(witness_t(&composer, e)); +}; + +template typename CT::fr to_ct(Composer& composer, typename NT::fr const& e) +{ + return typename CT::fr(witness_t(&composer, e)); +}; + +template typename CT::fq to_ct(Composer& composer, typename NT::fq const& e) +{ + return typename CT::fq(witness_t(&composer, e)); +}; + +template typename CT::address to_ct(Composer& composer, typename NT::address const& e) +{ + return typename CT::address(witness_t(&composer, e)); +}; + +template typename CT::uint32 to_ct(Composer& composer, typename NT::uint32 const& e) +{ + return typename CT::uint32(witness_t(&composer, e)); +}; + +template +typename CT::grumpkin_point to_ct(Composer& composer, typename NT::grumpkin_point const& e) +{ + return plonk::stdlib::create_point_witness(composer, e, true); +}; + +template +typename CT::bn254_point to_ct(Composer& composer, typename NT::bn254_point const& e) +{ + return CT::bn254_point::from_witness(&composer, e); +}; + +template +typename CT::ecdsa_signature to_ct(Composer& composer, typename NT::ecdsa_signature const& e) +{ + return CT::ecdsa_signature::template from_witness(&composer, e); +}; + +template +std::optional::boolean> to_ct(Composer& composer, std::optional const& e) +{ + return e ? std::make_optional::boolean>(to_ct(composer, *e)) : std::nullopt; +}; + +template +std::optional::fr> to_ct(Composer& composer, std::optional const& e) +{ + return e ? std::make_optional::fr>(to_ct(composer, *e)) : std::nullopt; +}; + +template +std::optional::address> to_ct(Composer& composer, std::optional const& e) +{ + return e ? std::make_optional::address>(to_ct(composer, *e)) : std::nullopt; +}; + +template +std::optional::grumpkin_point> to_ct(Composer& composer, + std::optional const& e) +{ + return e ? std::make_optional::grumpkin_point>(to_ct(composer, *e)) : std::nullopt; +}; + +template +std::optional::ecdsa_signature> to_ct(Composer& composer, + std::optional const& e) +{ + return e ? std::make_optional::ecdsa_signature>(to_ct(&composer, e)) : std::nullopt; +}; + +template +std::vector::fr> to_ct(Composer& composer, std::vector const& vec) +{ + auto ref_to_ct = [&](typename NT::fr const& e) { return to_ct(composer, e); }; + + return map(vec, ref_to_ct); +}; + +template +std::optional::fr>> to_ct(Composer& composer, + std::optional> const& vec) +{ + auto ref_to_ct = [&](typename NT::fr const& e) { return to_ct(composer, e); }; + + return vec ? std::make_optional::fr>>(map(*vec, ref_to_ct)) : std::nullopt; +}; + +template +std::array::fr, SIZE> to_ct(Composer& composer, std::array const& arr) +{ + auto ref_to_ct = [&](typename NT::fr const& e) { return to_ct(composer, e); }; + + return map(arr, ref_to_ct); +}; + +template +std::array::fr>, SIZE> to_ct( + Composer& composer, std::array, SIZE> const& arr) +{ + auto ref_to_ct = [&](std::optional const& e) { return to_ct(composer, e); }; + + return map(arr, ref_to_ct); +}; + +// to_nt() below ******************************** + +template typename NT::boolean to_nt(typename CT::boolean const& e) +{ + return e.get_value(); +}; + +template typename NT::fr to_nt(typename CT::fr const& e) +{ + return e.get_value(); +}; + +template typename NT::fq to_nt(typename CT::fq const& e) +{ + return e.get_value(); +}; + +template typename NT::address to_nt(typename CT::address const& e) +{ + return NT::address(e.address_.get_value()); // TODO: add get_value() method to address types. +}; + +template typename NT::uint32 to_nt(typename CT::uint32 const& e) +{ + NT::uint256 e_256 = e.get_value(); + NT::uint64 e_64 = e_256.data[0]; // TODO: check that this endianness is correct! + NT::uint32 e_32 = static_cast(e_64); + return e_32; +}; + +template typename NT::grumpkin_point to_nt(typename CT::grumpkin_point const& e) +{ + return NT::grumpkin_point{ e.x.get_value(), e.y.get_value() }; +}; + +template typename NT::bn254_point to_nt(typename CT::bn254_point const& e) +{ + return e.get_value(); +}; + +template typename NT::ecdsa_signature to_nt(typename CT::ecdsa_signature const& e) +{ + std::vector r_bytes = e.r.get_value(); + std::vector s_bytes = e.s.get_value(); + + std::array r_array; + std::array s_array; + std::copy(r_bytes.begin(), r_bytes.end(), r_array.begin()); + std::copy(s_bytes.begin(), s_bytes.end(), s_array.begin()); + + return NT::ecdsa_signature{ r_array, s_array }; +}; + +template +std::optional to_nt(std::optional::boolean> const& e) +{ + return e ? std::make_optional(to_nt(*e)) : std::nullopt; +}; + +template std::optional to_nt(std::optional::fr> const& e) +{ + return e ? std::make_optional(to_nt(*e)) : std::nullopt; +}; + +template +std::optional to_nt(std::optional::address> const& e) +{ + return e ? std::make_optional(to_nt(*e)) : std::nullopt; +}; + +template +std::optional to_nt(std::optional::grumpkin_point> const& e) +{ + return e ? std::make_optional(to_nt(*e)) : std::nullopt; +}; + +template +std::optional to_nt(std::optional::ecdsa_signature> const& e) +{ + return e ? std::make_optional(to_nt(*e)) : std::nullopt; +}; + +template std::vector to_nt(std::vector::fr> const& vec) +{ + auto ref_to_nt = [&](typename CT::fr const& e) { return to_nt(e); }; + + return map(vec, ref_to_nt); +}; + +template +std::optional> to_nt(std::optional::fr>> const& vec) +{ + auto ref_to_nt = [&](typename CT::fr const& e) { return to_nt(e); }; + + return vec ? std::make_optional>(map(*vec, ref_to_nt)) : std::nullopt; +}; + +template +std::array to_nt(std::array::fr, SIZE> const& arr) +{ + auto ref_to_nt = [&](typename CT::fr const& e) { return to_nt(e); }; + + return map(arr, ref_to_nt); +}; + +// template +// std::optional> to_nt( +// std::optional::fr, SIZE>> const& arr) +// { +// auto ref_to_nt = [&](typename CT::fr const& e) { return to_nt(e); }; + +// return arr ? std::make_optional>(map(arr, ref_to_nt)) : std::nullopt; +// }; + +template +std::array, SIZE> to_nt( + std::array::fr>, SIZE> const& arr) +{ + auto ref_to_nt = [&](std::optional::fr> const& e) { return to_nt(e); }; + + return map(arr, ref_to_nt); +}; + +} // namespace aztec3::utils::types \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/utils/types/native_types.hpp b/circuits/cpp/src/aztec3/utils/types/native_types.hpp new file mode 100644 index 00000000000..10df24f661f --- /dev/null +++ b/circuits/cpp/src/aztec3/utils/types/native_types.hpp @@ -0,0 +1,89 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// #include +// #include +// #include +// #include +// #include +// #include +// #include + +namespace aztec3::utils::types { + +// using plonk::stdlib::address; + +struct NativeTypes { + typedef bool boolean; + + typedef uint8_t uint8; + typedef uint16_t uint16; + typedef uint32_t uint32; + typedef uint64_t uint64; + typedef uint256_t uint256; + + typedef barretenberg::fr fr; + typedef barretenberg::fr safe_fr; + typedef stdlib::address address; + + typedef barretenberg::fq fq; + + // typedef fq grumpkin_fr; + // typedef fr grumpkin_fq; + typedef grumpkin::g1::affine_element grumpkin_point; + // typedef grumpkin::g1::element grumpkin_jac_point; + typedef grumpkin::g1 grumpkin_group; + + typedef barretenberg::g1::affine_element bn254_point; + // typedef barretenberg::g1::element bn254_jac_point; + // typedef barretenberg::g1 bn254_group; + + typedef std::vector bit_array; + typedef std::vector byte_array; + typedef std::string packed_byte_array; + + typedef crypto::schnorr::signature schnorr_signature; + typedef crypto::ecdsa::signature ecdsa_signature; + + typedef stdlib::recursion::native_recursion_output AggregationObject; + typedef bonk::verification_key_data VKData; + typedef bonk::verification_key VK; + typedef plonk::proof Proof; + + /// TODO: lots of these compress / commit functions aren't actually used: remove them. + + // Define the 'native' version of the function `compress`, with the name `compress`: + static fr compress(const std::vector& inputs, const size_t hash_index = 0) + { + return crypto::pedersen_commitment::compress_native(inputs, hash_index); + } + + static fr compress(const std::vector>& input_pairs) + { + return crypto::pedersen_commitment::compress_native(input_pairs); + } + + static grumpkin_point commit(const std::vector& inputs, const size_t hash_index = 0) + { + return crypto::pedersen_commitment::commit_native(inputs, hash_index); + } + + static grumpkin_point commit(const std::vector>& input_pairs) + { + return crypto::pedersen_commitment::commit_native(input_pairs); + } +}; + +} // namespace aztec3::utils::types \ No newline at end of file From 7b24cf3a9ce7c638b6eeb9bc8d09001f01f0f5f8 Mon Sep 17 00:00:00 2001 From: Suyash Bagad Date: Mon, 20 Mar 2023 18:12:23 +0100 Subject: [PATCH 075/166] update bb/aztec3. (#72) --- circuits/cpp/barretenberg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circuits/cpp/barretenberg b/circuits/cpp/barretenberg index 9aae3b4fcbd..617b50e938c 160000 --- a/circuits/cpp/barretenberg +++ b/circuits/cpp/barretenberg @@ -1 +1 @@ -Subproject commit 9aae3b4fcbda51e36782e22108880e48da977af6 +Subproject commit 617b50e938cde7b4883f4be7b15ee43cef3a4ec3 From 596f46a3a5c919ad98e928f778a65d9938b7d340 Mon Sep 17 00:00:00 2001 From: Adam Domurad Date: Tue, 21 Mar 2023 09:28:27 -0400 Subject: [PATCH 076/166] feat(ts): start of merge --- circuits/cpp/src/aztec3/CMakeLists.txt | 42 +++- .../cpp/src/aztec3/circuits/abis/.test.cpp | 16 +- .../abis/append_only_tree_snapshot.hpp | 45 ++++ .../src/aztec3/circuits/abis/barretenberg.hpp | 26 +++ .../abis/barretenberg/aggregation_object.hpp | 29 +++ .../circuits/abis/barretenberg/proof.hpp | 21 ++ .../abis/base_rollup/base_rollup_inputs.hpp | 86 +++++++ .../base_rollup/constant_base_rollup_data.hpp | 79 +++++++ .../base_rollup/nullifier_leaf_preimage.hpp | 49 ++++ .../cpp/src/aztec3/circuits/abis/c_bind.cpp | 86 ++++++- .../cpp/src/aztec3/circuits/abis/c_bind.h | 2 +- .../src/aztec3/circuits/abis/call_context.hpp | 24 +- .../abis/contract_deployment_data.hpp | 37 +-- .../aztec3/circuits/abis/function_data.hpp | 19 +- .../circuits/abis/membership_witness.hpp | 45 ++++ .../abis/optionally_revealed_data.hpp | 45 ++++ .../abis/private_circuit_public_inputs.hpp | 123 +++++----- .../abis/private_kernel/accumulated_data.hpp | 65 ++++++ .../abis/private_kernel/constant_data.hpp | 22 ++ .../abis/private_kernel/new_contract_data.hpp | 82 +++++++ .../abis/private_kernel/old_tree_roots.hpp | 28 +++ .../private_kernel/previous_kernel_data.hpp | 48 +++- .../abis/private_kernel/public_inputs.hpp | 27 +++ .../abis/public_circuit_public_inputs.hpp | 14 +- .../src/aztec3/circuits/abis/tx_context.hpp | 30 +-- .../abis/verifier_reference_string.cpp | 23 ++ .../abis/verifier_reference_string.hpp | 29 +++ .../cpp/src/aztec3/circuits/apps/.test.cpp | 17 +- .../cpp/src/aztec3/circuits/apps/contract.tpp | 2 +- .../apps/function_execution_context.hpp | 5 +- .../aztec3/circuits/apps/opcodes/opcodes.tpp | 4 +- .../circuits/apps/test_apps/escrow/.test.cpp | 3 +- .../apps/test_apps/escrow/transfer.cpp | 2 +- .../apps/test_apps/escrow/withdraw.cpp | 2 +- .../.test.cpp | 3 +- .../src/aztec3/circuits/apps/utxo_datum.hpp | 4 +- .../aztec3/circuits/kernel/private/.test.cpp | 6 +- circuits/cpp/src/aztec3/constants.hpp | 5 + circuits/cpp/src/aztec3/oracle/fake_db.hpp | 6 +- .../rollup-circuits/base-rollup.md | 215 +++++++++--------- 40 files changed, 1138 insertions(+), 278 deletions(-) create mode 100644 circuits/cpp/src/aztec3/circuits/abis/append_only_tree_snapshot.hpp create mode 100644 circuits/cpp/src/aztec3/circuits/abis/barretenberg.hpp create mode 100644 circuits/cpp/src/aztec3/circuits/abis/barretenberg/aggregation_object.hpp create mode 100644 circuits/cpp/src/aztec3/circuits/abis/barretenberg/proof.hpp create mode 100644 circuits/cpp/src/aztec3/circuits/abis/base_rollup/base_rollup_inputs.hpp create mode 100644 circuits/cpp/src/aztec3/circuits/abis/base_rollup/constant_base_rollup_data.hpp create mode 100644 circuits/cpp/src/aztec3/circuits/abis/base_rollup/nullifier_leaf_preimage.hpp create mode 100644 circuits/cpp/src/aztec3/circuits/abis/membership_witness.hpp create mode 100644 circuits/cpp/src/aztec3/circuits/abis/private_kernel/new_contract_data.hpp create mode 100644 circuits/cpp/src/aztec3/circuits/abis/verifier_reference_string.cpp create mode 100644 circuits/cpp/src/aztec3/circuits/abis/verifier_reference_string.hpp diff --git a/circuits/cpp/src/aztec3/CMakeLists.txt b/circuits/cpp/src/aztec3/CMakeLists.txt index 110cca7692c..0a7198e6504 100644 --- a/circuits/cpp/src/aztec3/CMakeLists.txt +++ b/circuits/cpp/src/aztec3/CMakeLists.txt @@ -1,4 +1,44 @@ add_subdirectory(circuits) add_subdirectory(oracle) add_subdirectory(dbs) -add_subdirectory(utils) \ No newline at end of file +add_subdirectory(utils) + +if (WASM) + # We can't build a wasm module by just linking to the libraries as that produces, nothing. + # There are a couple of other ways to avoiding listing all the object files here and leveraging the dependency + # tree, but they come with the problem that they will import the 'env' object files. We explicitly want to avoid + # that as functions in 'env' should be implemented in JS itself. + # It turns out that just explicitly telling the wasm module which object files to include was easiest. + add_executable( + aztec3-circuits.wasm + $ + $ + $ + ) + target_link_libraries(aztec3-circuits.wasm barretenberg) + + # With binaryen installed, it seems its wasm backend optimiser gets invoked automatically. + # Due to either a bug in the optimiser, or non-standards compliant c++ in crypto/aes, tests start failing with + # -O3 level optimisations. We force down to -O2 for current workaround. + # Presumably the -O3 when compiling the object files is fine as it's llvms IR optimiser. + # The backend optimiser is presumably triggered after linking. + target_link_options( + aztec3-circuits.wasm + PRIVATE + # TODO revisit implications of whole-archive + -nostartfiles -O2 -Wl,--whole-archive -Wl,--no-entry -Wl,--export-dynamic -Wl,--import-memory -Wl,--allow-undefined -Wl,--stack-first -Wl,-z,stack-size=1048576 + ) + + find_program(WASM_OPT wasm-opt) + + if(NOT WASM_OPT) + message(FATAL_ERROR "wasm-opt executable not found. Please install binaryen.") + endif() + + add_custom_command( + TARGET aztec3-circuits.wasm + POST_BUILD + COMMAND wasm-opt "$" -O2 --asyncify -o "$" + VERBATIM + ) +endif() diff --git a/circuits/cpp/src/aztec3/circuits/abis/.test.cpp b/circuits/cpp/src/aztec3/circuits/abis/.test.cpp index 17e110655f0..26251a6145f 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/abis/.test.cpp @@ -16,7 +16,7 @@ class abi_tests : public ::testing::Test {}; TEST(abi_tests, test_native_function_data) { FunctionData function_data = { - .function_encoding = 11, + .function_selector = 11, .is_private = false, .is_constructor = false, }; @@ -32,7 +32,7 @@ TEST(abi_tests, test_native_function_data) TEST(abi_tests, test_native_to_circuit_function_data) { FunctionData native_function_data = { - .function_encoding = 11, + .function_selector = 11, .is_private = false, .is_constructor = false, }; @@ -87,7 +87,7 @@ TEST(abi_tests, test_native_to_circuit_call_context) // .public_call_stack = { 26, 27, 28, 29 }, // .contract_deployment_call_stack = { 30, 31 }, // .partial_l1_call_stack = { 32, 33 }, -// .old_private_data_tree_root = 38, +// .historic_private_data_tree_root = 38, // }; // info("public_circuit_public_inputs: ", public_inputs); @@ -104,7 +104,7 @@ TEST(abi_tests, test_native_to_circuit_call_context) // .public_call_stack = { 26, 27, 28, 29 }, // .contract_deployment_call_stack = { 30, 31 }, // .partial_l1_call_stack = { 32, 33 }, -// .old_private_data_tree_root = 38, +// .historic_private_data_tree_root = 38, // }; // info("public_circuit_public_inputs: ", native_public_inputs); @@ -126,13 +126,13 @@ TEST(abi_tests, test_native_to_circuit_call_context) // .public_call_stack = { 26, 27, 28, 29 }, // .contract_deployment_call_stack = { 30, 31 }, // .partial_l1_call_stack = { 32, 33 }, -// .old_private_data_tree_root = 38, +// .historic_private_data_tree_root = 38, // }; // CallStackItem call_stack_item = { // .function_data = { // // .contract_address = 10, -// .function_encoding = 11, +// .function_selector = 11, // .is_private = false, // .is_constructor = false, // }, @@ -159,13 +159,13 @@ TEST(abi_tests, test_native_to_circuit_call_context) // .public_call_stack = { 26, 27, 28, 29 }, // .contract_deployment_call_stack = { 30, 31 }, // .partial_l1_call_stack = { 32, 33 }, -// .old_private_data_tree_root = 38, +// .historic_private_data_tree_root = 38, // }; // CallStackItem native_call_stack_item = { // .function_data = { // // .contract_address = 10, -// .function_encoding = 11, +// .function_selector = 11, // .is_private = false, // .is_constructor = false, // }, diff --git a/circuits/cpp/src/aztec3/circuits/abis/append_only_tree_snapshot.hpp b/circuits/cpp/src/aztec3/circuits/abis/append_only_tree_snapshot.hpp new file mode 100644 index 00000000000..34b66cfc495 --- /dev/null +++ b/circuits/cpp/src/aztec3/circuits/abis/append_only_tree_snapshot.hpp @@ -0,0 +1,45 @@ +#pragma once + +#include "aztec3/utils/types/circuit_types.hpp" +namespace aztec3::circuits::abis { + +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; +using std::is_same; + +template struct AppendOnlyTreeSnapshot { + + typedef typename NCT::fr fr; + typedef typename NCT::uint32 uint32; + + fr root; + uint32 next_available_leaf_index; + + bool operator==(AppendOnlyTreeSnapshot const&) const = default; + + static AppendOnlyTreeSnapshot empty() { return { 0, 0 }; }; +}; + +template void read(uint8_t const*& it, AppendOnlyTreeSnapshot& obj) +{ + using serialize::read; + + read(it, obj.root); + read(it, obj.next_available_leaf_index); +}; + +template void write(std::vector& buf, AppendOnlyTreeSnapshot const& obj) +{ + using serialize::write; + + write(buf, obj.root); + write(buf, obj.next_available_leaf_index); +}; + +template std::ostream& operator<<(std::ostream& os, AppendOnlyTreeSnapshot const& obj) +{ + return os << "root: " << obj.root << "\n" + << "next_available_leaf_index: " << obj.next_available_leaf_index << "\n"; +} + +} // namespace aztec3::circuits::abis \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/abis/barretenberg.hpp b/circuits/cpp/src/aztec3/circuits/abis/barretenberg.hpp new file mode 100644 index 00000000000..c76c3d1b2d2 --- /dev/null +++ b/circuits/cpp/src/aztec3/circuits/abis/barretenberg.hpp @@ -0,0 +1,26 @@ +#pragma once +#include +#include +#include + +namespace serialize { + +inline void read(uint8_t const*& it, plonk::stdlib::types::NativeTypes::Proof& proof) +{ + using serialize::read; + + read(it, proof.proof_data); +}; + +inline void read(uint8_t const*& it, plonk::stdlib::types::NativeTypes::AggregationObject& obj) +{ + using serialize::read; + + read(it, obj.P0); + read(it, obj.P1); + read(it, obj.public_inputs); + read(it, obj.proof_witness_indices); + read(it, obj.has_data); +}; + +} // namespace serialize \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/abis/barretenberg/aggregation_object.hpp b/circuits/cpp/src/aztec3/circuits/abis/barretenberg/aggregation_object.hpp new file mode 100644 index 00000000000..ec9fa038daa --- /dev/null +++ b/circuits/cpp/src/aztec3/circuits/abis/barretenberg/aggregation_object.hpp @@ -0,0 +1,29 @@ +#pragma once +#include +#include + +namespace serialize { +inline void read(uint8_t const*& it, plonk::stdlib::types::NativeTypes::AggregationObject& obj) +{ + using serialize::read; + + read(it, obj.P0); + read(it, obj.P1); + read(it, obj.public_inputs); + read(it, obj.proof_witness_indices); + read(it, obj.has_data); +}; +} // namespace serialize + +namespace std { +inline std::ostream& operator<<(std::ostream& os, stdlib::recursion::native_recursion_output const& obj) +{ + return os << "P0: " << obj.P0 << "\n" + << "P1: " << obj.P1 << "\n" + << "public_inputs:\n" + << obj.public_inputs << "\n" + << "proof_witness_indices:\n" + << obj.proof_witness_indices << "\n" + << "has_data: " << obj.has_data << "\n"; +}; +} // namespace std \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/abis/barretenberg/proof.hpp b/circuits/cpp/src/aztec3/circuits/abis/barretenberg/proof.hpp new file mode 100644 index 00000000000..ab5d7a018af --- /dev/null +++ b/circuits/cpp/src/aztec3/circuits/abis/barretenberg/proof.hpp @@ -0,0 +1,21 @@ +#pragma once +#include +#include + +namespace serialize { +using Proof = plonk::stdlib::types::NativeTypes::Proof; + +inline void read(uint8_t const*& it, Proof& proof) +{ + using serialize::read; + + read(it, proof.proof_data); +}; +} // namespace serialize + +namespace std { +inline std::ostream& operator<<(std::ostream& os, plonk::stdlib::types::NativeTypes::Proof const& data) +{ + return os << data.proof_data; +} +} // namespace std \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/abis/base_rollup/base_rollup_inputs.hpp b/circuits/cpp/src/aztec3/circuits/abis/base_rollup/base_rollup_inputs.hpp new file mode 100644 index 00000000000..84bd08fb50c --- /dev/null +++ b/circuits/cpp/src/aztec3/circuits/abis/base_rollup/base_rollup_inputs.hpp @@ -0,0 +1,86 @@ +#pragma once +#include "../append_only_tree_snapshot.hpp" +#include "../private_kernel/previous_kernel_data.hpp" +#include "../membership_witness.hpp" +#include "./nullifier_leaf_preimage.hpp" +#include "./constant_base_rollup_data.hpp" + +namespace aztec3::circuits::abis { + +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; +using std::is_same; + +template struct BaseRollupInputs { + + typedef typename NCT::fr fr; + + std::array, 2> kernel_data; + + AppendOnlyTreeSnapshot start_nullifier_tree_snapshot; + std::array, 2 * KERNEL_NEW_NULLIFIERS_LENGTH> low_nullifier_leaf_preimages; + std::array, 2 * KERNEL_NEW_NULLIFIERS_LENGTH> + low_nullifier_membership_witness; + + std::array, 2> + historic_private_data_tree_root_membership_witnesses; + std::array, 2> + historic_contract_tree_root_membership_witnesses; + + ConstantBaseRollupData constants; + + fr prover_id; + + bool operator==(BaseRollupInputs const&) const = default; +}; + +template void read(uint8_t const*& it, BaseRollupInputs& obj) +{ + using serialize::read; + + // TODO: serialization of kernel data + // read(it, obj.kernel_data); + read(it, obj.start_nullifier_tree_snapshot); + read(it, obj.low_nullifier_leaf_preimages); + read(it, obj.low_nullifier_membership_witness); + read(it, obj.historic_private_data_tree_root_membership_witnesses); + read(it, obj.historic_contract_tree_root_membership_witnesses); + read(it, obj.constants); + read(it, obj.prover_id); +}; + +template void write(std::vector& buf, BaseRollupInputs const& obj) +{ + using serialize::write; + + // TODO: serialization of kernel data + // write(buf, obj.kernel_data); + write(buf, obj.start_nullifier_tree_snapshot); + write(buf, obj.low_nullifier_leaf_preimages); + write(buf, obj.low_nullifier_membership_witness); + write(buf, obj.historic_private_data_tree_root_membership_witnesses); + write(buf, obj.historic_contract_tree_root_membership_witnesses); + write(buf, obj.constants); + write(buf, obj.prover_id); +}; + +template std::ostream& operator<<(std::ostream& os, BaseRollupInputs const& obj) +{ + return os + //<< "kernel_data: " << obj.kernel_data << "\n" + << "start_nullifier_tree_snapshot:\n" + << obj.start_nullifier_tree_snapshot << "\n" + << "low_nullifier_leaf_preimages:\n" + << obj.low_nullifier_leaf_preimages << "\n" + << "low_nullifier_membership_witness:\n" + << obj.low_nullifier_membership_witness << "\n" + << "historic_private_data_tree_root_membership_witnesses:\n" + << obj.historic_private_data_tree_root_membership_witnesses << "\n" + << "historic_contract_tree_root_membership_witnesses:\n" + << obj.historic_contract_tree_root_membership_witnesses << "\n" + << "constants:\n" + << obj.constants << "\n" + << "prover_id: " << obj.prover_id << "\n"; +} + +} // namespace aztec3::circuits::abis \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/abis/base_rollup/constant_base_rollup_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/base_rollup/constant_base_rollup_data.hpp new file mode 100644 index 00000000000..bc2471f5731 --- /dev/null +++ b/circuits/cpp/src/aztec3/circuits/abis/base_rollup/constant_base_rollup_data.hpp @@ -0,0 +1,79 @@ +#pragma once +#include "../append_only_tree_snapshot.hpp" + +namespace aztec3::circuits::abis { + +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; +using std::is_same; + +template struct ConstantBaseRollupData { + + typedef typename NCT::fr fr; + + // The very latest roots as at the very beginning of the entire rollup: + AppendOnlyTreeSnapshot start_tree_of_historic_private_data_tree_roots_snapshot; + AppendOnlyTreeSnapshot start_tree_of_historic_contract_tree_roots_snapshot; + AppendOnlyTreeSnapshot tree_of_historic_l1_to_l2_msg_tree_roots_snapshot; + + // Some members of this struct tbd: + fr private_kernel_vk_tree_root; + fr public_kernel_vk_tree_root; + fr base_rollup_vk_hash; + fr merge_rollup_vk_hash; + + bool operator==(ConstantBaseRollupData const&) const = default; + + static ConstantBaseRollupData empty() + { + return { AppendOnlyTreeSnapshot::empty(), + AppendOnlyTreeSnapshot::empty(), + AppendOnlyTreeSnapshot::empty(), + 0, + 0, + 0, + 0 }; + }; +}; + +template void read(uint8_t const*& it, ConstantBaseRollupData& obj) +{ + using serialize::read; + + read(it, obj.start_tree_of_historic_private_data_tree_roots_snapshot); + read(it, obj.start_tree_of_historic_contract_tree_roots_snapshot); + read(it, obj.tree_of_historic_l1_to_l2_msg_tree_roots_snapshot); + read(it, obj.private_kernel_vk_tree_root); + read(it, obj.public_kernel_vk_tree_root); + read(it, obj.base_rollup_vk_hash); + read(it, obj.merge_rollup_vk_hash); +}; + +template void write(std::vector& buf, ConstantBaseRollupData const& obj) +{ + using serialize::write; + + write(buf, obj.start_tree_of_historic_private_data_tree_roots_snapshot); + write(buf, obj.start_tree_of_historic_contract_tree_roots_snapshot); + write(buf, obj.tree_of_historic_l1_to_l2_msg_tree_roots_snapshot); + write(buf, obj.private_kernel_vk_tree_root); + write(buf, obj.public_kernel_vk_tree_root); + write(buf, obj.base_rollup_vk_hash); + write(buf, obj.merge_rollup_vk_hash); +}; + +template std::ostream& operator<<(std::ostream& os, ConstantBaseRollupData const& obj) +{ + return os << "start_tree_of_historic_private_data_tree_roots_snapshot:\n " + << obj.start_tree_of_historic_private_data_tree_roots_snapshot << "\n" + << "start_tree_of_historic_contract_tree_roots_snapshot:\n" + << obj.start_tree_of_historic_contract_tree_roots_snapshot << "\n" + << "tree_of_historic_l1_to_l2_msg_tree_roots_snapshot:\n" + << obj.tree_of_historic_l1_to_l2_msg_tree_roots_snapshot << "\n" + << "private_kernel_vk_tree_root: " << obj.private_kernel_vk_tree_root << "\n" + << "public_kernel_vk_tree_root: " << obj.public_kernel_vk_tree_root << "\n" + << "base_rollup_vk_hash: " << obj.base_rollup_vk_hash << "\n" + << "merge_rollup_vk_hash: " << obj.merge_rollup_vk_hash << "\n"; +} + +} // namespace aztec3::circuits::abis \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/abis/base_rollup/nullifier_leaf_preimage.hpp b/circuits/cpp/src/aztec3/circuits/abis/base_rollup/nullifier_leaf_preimage.hpp new file mode 100644 index 00000000000..99d0f5d07d9 --- /dev/null +++ b/circuits/cpp/src/aztec3/circuits/abis/base_rollup/nullifier_leaf_preimage.hpp @@ -0,0 +1,49 @@ +#pragma once + +#include "aztec3/utils/types/circuit_types.hpp" +namespace aztec3::circuits::abis { + +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; +using std::is_same; + +template struct NullifierLeafPreimage { + + typedef typename NCT::fr fr; + typedef typename NCT::uint32 uint32; + + fr leaf_value; + fr next_value; + uint32 next_index; + + bool operator==(NullifierLeafPreimage const&) const = default; + + static NullifierLeafPreimage empty() { return { 0, 0, 0 }; }; +}; + +template void read(uint8_t const*& it, NullifierLeafPreimage& obj) +{ + using serialize::read; + + read(it, obj.leaf_value); + read(it, obj.next_value); + read(it, obj.next_index); +}; + +template void write(std::vector& buf, NullifierLeafPreimage const& obj) +{ + using serialize::write; + + write(buf, obj.leaf_value); + write(buf, obj.next_value); + write(buf, obj.next_index); +}; + +template std::ostream& operator<<(std::ostream& os, NullifierLeafPreimage const& obj) +{ + return os << "leaf_value: " << obj.leaf_value << "\n" + << "next_value: " << obj.next_value << "\n" + << "next_index: " << obj.next_index << "\n"; +} + +} // namespace aztec3::circuits::abis \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp b/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp index b63a2be5527..95dd70647da 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp +++ b/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp @@ -1,6 +1,13 @@ #include "c_bind.h" +#include "barretenberg/srs/reference_string/mem_reference_string.hpp" +#include "aztec3/circuits/abis/function_data.hpp" +#include "aztec3/circuits/abis/verifier_reference_string.hpp" +#include "private_circuit_public_inputs.hpp" #include "tx_request.hpp" +#include "tx_context.hpp" #include "function_leaf_preimage.hpp" +#include "base_rollup/base_rollup_inputs.hpp" +#include "private_kernel/previous_kernel_data.hpp" #include @@ -11,12 +18,42 @@ namespace { using aztec3::GeneratorIndex; using aztec3::circuits::abis::FunctionLeafPreimage; +using aztec3::circuits::abis::TxContext; using aztec3::circuits::abis::TxRequest; using NT = aztec3::utils::types::NativeTypes; } // namespace #define WASM_EXPORT __attribute__((visibility("default"))) +// Note: We don't have a simple way of calling the barretenberg c-bind. +// Mimick bbmalloc behaviour. +static void* bbmalloc(size_t size) +{ + auto ptr = aligned_alloc(64, size); + return ptr; +} + +/** Copy this string to a bbmalloc'd buffer */ +static const char* bbmalloc_copy_string(const char* data, size_t len) +{ + char* output_copy = (char*)bbmalloc(len + 1); + memcpy(output_copy, data, len + 1); + return output_copy; +} + +/** + * For testing only. Take this object, write it to a buffer, then output it. */ +template static const char* as_string_output(uint8_t const* input_buf, uint32_t* size) +{ + T obj; + read(input_buf, obj); + std::ostringstream stream; + stream << obj; + std::string str = stream.str(); + *size = (uint32_t)str.size(); + return bbmalloc_copy_string(str.c_str(), *size); +} + extern "C" { /** @@ -84,4 +121,51 @@ WASM_EXPORT void abis__compute_function_leaf(uint8_t const* function_leaf_preima leaf_preimage.hash(); NT::fr::serialize_to_buffer(leaf_preimage.hash(), output); } -} // extern "C" \ No newline at end of file + +// TODO(AD): After Milestone 1, rewrite this with better injection mechanism. +WASM_EXPORT void abis__set_global_verifier_reference_string(uint8_t* data) +{ + auto vrs = std::make_shared(data); + aztec3::circuits::abis::set_global_verifier_reference_string(vrs); +} + +/*** Serialization test helpers ***/ +WASM_EXPORT const char* abis__test_roundtrip_serialize_tx_context(uint8_t const* tx_context_buf, uint32_t* size) +{ + return as_string_output>(tx_context_buf, size); +} + +WASM_EXPORT const char* abis__test_roundtrip_serialize_tx_request(uint8_t const* tx_request_buf, uint32_t* size) +{ + return as_string_output>(tx_request_buf, size); +} + +WASM_EXPORT const char* abis__test_roundtrip_serialize_call_context(uint8_t const* call_context_buf, uint32_t* size) +{ + return as_string_output>(call_context_buf, size); +} + +WASM_EXPORT const char* abis__test_roundtrip_serialize_private_circuit_public_inputs( + uint8_t const* private_circuits_public_inputs_buf, uint32_t* size) +{ + return as_string_output>(private_circuits_public_inputs_buf, + size); +} + +WASM_EXPORT const char* abis__test_roundtrip_serialize_function_data(uint8_t const* function_data_buf, uint32_t* size) +{ + return as_string_output>(function_data_buf, size); +} + +WASM_EXPORT const char* abis__test_roundtrip_serialize_base_rollup_inputs(uint8_t const* rollup_inputs_buf, + uint32_t* size) +{ + return as_string_output>(rollup_inputs_buf, size); +} + +WASM_EXPORT const char* abis__test_roundtrip_serialize_previous_kernel_data(uint8_t const* kernel_data_buf, + uint32_t* size) +{ + return as_string_output>(kernel_data_buf, size); +} +} // extern "C" diff --git a/circuits/cpp/src/aztec3/circuits/abis/c_bind.h b/circuits/cpp/src/aztec3/circuits/abis/c_bind.h index 77eec984d66..80719bda410 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/c_bind.h +++ b/circuits/cpp/src/aztec3/circuits/abis/c_bind.h @@ -8,4 +8,4 @@ WASM_EXPORT void abis__hash_tx_request(uint8_t const* tx_request_buf, uint8_t* o WASM_EXPORT void abis__compute_function_selector(char const* func_sig_cstr, uint8_t* output); WASM_EXPORT void abis__compute_function_leaf(uint8_t const* function_leaf_preimage_buf, uint8_t* output); -} +} \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/abis/call_context.hpp b/circuits/cpp/src/aztec3/circuits/abis/call_context.hpp index 1f9dfb3e38d..22a87500bd6 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/call_context.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/call_context.hpp @@ -28,17 +28,14 @@ template struct CallContext { boolean is_static_call; boolean is_contract_deployment; - fr reference_block_num; - boolean operator==(CallContext const& other) const { return msg_sender == other.msg_sender && storage_contract_address == other.storage_contract_address && tx_origin == other.tx_origin && is_delegate_call == other.is_delegate_call && - is_static_call == other.is_static_call && is_contract_deployment == other.is_contract_deployment && - reference_block_num == other.reference_block_num; + is_static_call == other.is_static_call && is_contract_deployment == other.is_contract_deployment; }; - static CallContext empty() { return { 0, 0, 0, 0, 0, 0, 0 }; }; + static CallContext empty() { return { 0, 0, 0, 0, 0, 0 }; }; template CallContext> to_circuit_type(Composer& composer) const { @@ -48,8 +45,8 @@ template struct CallContext { auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(composer, e); }; CallContext> call_context = { - to_ct(msg_sender), to_ct(storage_contract_address), to_ct(tx_origin), to_ct(is_delegate_call), - to_ct(is_static_call), to_ct(is_contract_deployment), to_ct(reference_block_num), + to_ct(msg_sender), to_ct(storage_contract_address), to_ct(tx_origin), + to_ct(is_delegate_call), to_ct(is_static_call), to_ct(is_contract_deployment), }; @@ -62,8 +59,8 @@ template struct CallContext { auto to_nt = [&](auto& e) { return aztec3::utils::types::to_nt(e); }; CallContext call_context = { - to_nt(msg_sender), to_nt(storage_contract_address), to_nt(tx_origin), to_nt(is_delegate_call), - to_nt(is_static_call), to_nt(is_contract_deployment), to_nt(reference_block_num), + to_nt(msg_sender), to_nt(storage_contract_address), to_nt(tx_origin), + to_nt(is_delegate_call), to_nt(is_static_call), to_nt(is_contract_deployment), }; return call_context; @@ -73,7 +70,7 @@ template struct CallContext { { std::vector inputs = { msg_sender.to_field(), storage_contract_address.to_field(), tx_origin.to_field(), fr(is_delegate_call), - fr(is_static_call), fr(is_contract_deployment), reference_block_num, + fr(is_static_call), fr(is_contract_deployment), }; return NCT::compress(inputs, GeneratorIndex::CALL_CONTEXT); @@ -89,7 +86,6 @@ template struct CallContext { fr(is_delegate_call).assert_is_zero(); fr(is_static_call).assert_is_zero(); fr(is_contract_deployment).assert_is_zero(); - reference_block_num.assert_is_zero(); } void set_public() @@ -102,7 +98,6 @@ template struct CallContext { fr(is_delegate_call).set_public(); fr(is_static_call).set_public(); fr(is_contract_deployment).set_public(); - reference_block_num.set_public(); } }; @@ -116,7 +111,6 @@ template void read(uint8_t const*& it, CallContext& call_con read(it, call_context.is_delegate_call); read(it, call_context.is_static_call); read(it, call_context.is_contract_deployment); - read(it, call_context.reference_block_num); }; template void write(std::vector& buf, CallContext const& call_context) @@ -129,7 +123,6 @@ template void write(std::vector& buf, CallContext c write(buf, call_context.is_delegate_call); write(buf, call_context.is_static_call); write(buf, call_context.is_contract_deployment); - write(buf, call_context.reference_block_num); }; template std::ostream& operator<<(std::ostream& os, CallContext const& call_context) @@ -139,8 +132,7 @@ template std::ostream& operator<<(std::ostream& os, CallContext struct ContractDeploymentData { typedef typename NCT::boolean boolean; typedef typename NCT::fr fr; - fr contract_data_hash; + fr constructor_vk_hash; fr function_tree_root; - fr constructor_hash; fr contract_address_salt; fr portal_contract_address; // TODO: no uint160 circuit type? bool operator==(ContractDeploymentData const&) const = default; - static ContractDeploymentData empty() { return { 0, 0, 0, 0, 0 }; }; + static ContractDeploymentData empty() { return { 0, 0, 0, 0 }; }; template ContractDeploymentData> to_circuit_type(Composer& composer) const @@ -36,8 +35,10 @@ template struct ContractDeploymentData { auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(composer, e); }; ContractDeploymentData> data = { - to_ct(contract_data_hash), to_ct(function_tree_root), to_ct(constructor_hash), - to_ct(contract_address_salt), to_ct(portal_contract_address), + to_ct(constructor_vk_hash), + to_ct(function_tree_root), + to_ct(contract_address_salt), + to_ct(portal_contract_address), }; return data; @@ -49,8 +50,10 @@ template struct ContractDeploymentData { auto to_nt = [&](auto& e) { return aztec3::utils::types::to_nt(e); }; ContractDeploymentData call_context = { - to_nt(contract_data_hash), to_nt(function_tree_root), to_nt(constructor_hash), - to_nt(contract_address_salt), to_nt(portal_contract_address), + to_nt(constructor_vk_hash), + to_nt(function_tree_root), + to_nt(contract_address_salt), + to_nt(portal_contract_address), }; return call_context; @@ -60,9 +63,8 @@ template struct ContractDeploymentData { { static_assert((std::is_same, NCT>::value)); - contract_data_hash.assert_is_zero(); + constructor_vk_hash.assert_is_zero(); function_tree_root.assert_is_zero(); - constructor_hash.assert_is_zero(); contract_address_salt.assert_is_zero(); portal_contract_address.assert_is_zero(); } @@ -71,9 +73,8 @@ template struct ContractDeploymentData { { static_assert(!(std::is_same::value)); - contract_data_hash.set_public(); + constructor_vk_hash.set_public(); function_tree_root.set_public(); - constructor_hash.set_public(); contract_address_salt.set_public(); portal_contract_address.set_public(); } @@ -81,7 +82,10 @@ template struct ContractDeploymentData { fr hash() const { std::vector inputs = { - contract_data_hash, function_tree_root, constructor_hash, contract_address_salt, portal_contract_address, + constructor_vk_hash, + function_tree_root, + contract_address_salt, + portal_contract_address, }; return NCT::compress(inputs, GeneratorIndex::CONTRACT_DEPLOYMENT_DATA); @@ -92,9 +96,8 @@ template void read(uint8_t const*& it, ContractDeploymentData void write(std::vector& buf, ContractDeployment { using serialize::write; - write(buf, data.contract_data_hash); + write(buf, data.constructor_vk_hash); write(buf, data.function_tree_root); - write(buf, data.constructor_hash); write(buf, data.contract_address_salt); write(buf, data.portal_contract_address); }; template std::ostream& operator<<(std::ostream& os, ContractDeploymentData const& data) { - return os << "contract_data_hash: " << data.contract_data_hash << "\n" + return os << "constructor_vk_hash: " << data.constructor_vk_hash << "\n" << "function_tree_root: " << data.function_tree_root << "\n" - << "constructor_hash: " << data.constructor_hash << "\n" << "contract_address_salt: " << data.contract_address_salt << "\n" << "portal_contract_address: " << data.portal_contract_address << "\n"; } diff --git a/circuits/cpp/src/aztec3/circuits/abis/function_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/function_data.hpp index 487c5bf3849..add90017c41 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/function_data.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/function_data.hpp @@ -1,7 +1,4 @@ #pragma once -// #include -#include -// #include #include #include #include @@ -21,7 +18,7 @@ template struct FunctionData { // typedef typename NCT::grumpkin_point grumpkin_point; typedef typename NCT::fr fr; - uint32 function_encoding; // e.g. 1st 4-bytes of abi-encoding of function. + uint32 function_selector; // e.g. 1st 4-bytes of abi-encoding of function. boolean is_private = false; boolean is_constructor = false; @@ -37,7 +34,7 @@ template struct FunctionData { auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(composer, e); }; FunctionData> function_data = { - to_ct(function_encoding), + to_ct(function_selector), to_ct(is_private), to_ct(is_constructor), }; @@ -51,7 +48,7 @@ template struct FunctionData { auto to_nt = [&](auto& e) { return aztec3::utils::types::to_nt(e); }; FunctionData function_data = { - to_nt(function_encoding), + to_nt(function_selector), to_nt(is_private), to_nt(is_constructor), }; @@ -63,7 +60,7 @@ template struct FunctionData { { static_assert(!(std::is_same::value)); - fr(function_encoding).set_public(); + fr(function_selector).set_public(); fr(is_private).set_public(); fr(is_constructor).set_public(); } @@ -72,7 +69,7 @@ template struct FunctionData { fr hash() const { std::vector inputs = { - fr(function_encoding), + fr(function_selector), fr(is_private), fr(is_constructor), }; @@ -85,7 +82,7 @@ template void read(uint8_t const*& it, FunctionData& functio { using serialize::read; - read(it, function_data.function_encoding); + read(it, function_data.function_selector); read(it, function_data.is_private); read(it, function_data.is_constructor); }; @@ -94,14 +91,14 @@ template void write(std::vector& buf, FunctionData { using serialize::write; - write(buf, function_data.function_encoding); + write(buf, function_data.function_selector); write(buf, function_data.is_private); write(buf, function_data.is_constructor); }; template std::ostream& operator<<(std::ostream& os, FunctionData const& function_data) { - return os << "function_encoding: " << function_data.function_encoding << "\n" + return os << "function_selector: " << function_data.function_selector << "\n" << "is_private: " << function_data.is_private << "\n" << "is_constructor: " << function_data.is_constructor << "\n"; } diff --git a/circuits/cpp/src/aztec3/circuits/abis/membership_witness.hpp b/circuits/cpp/src/aztec3/circuits/abis/membership_witness.hpp new file mode 100644 index 00000000000..db636abe116 --- /dev/null +++ b/circuits/cpp/src/aztec3/circuits/abis/membership_witness.hpp @@ -0,0 +1,45 @@ +#pragma once + +#include "aztec3/utils/types/circuit_types.hpp" +namespace aztec3::circuits::abis { + +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; +using std::is_same; + +template struct MembershipWitness { + + typedef typename NCT::fr fr; + typedef typename NCT::uint32 uint32; + + uint32 leaf_index; + std::array sibling_path; + + bool operator==(MembershipWitness const&) const = default; + + static MembershipWitness empty() { return { 0, std::array(N) }; }; +}; + +template void read(uint8_t const*& it, MembershipWitness& obj) +{ + using serialize::read; + + read(it, obj.leaf_index); + read(it, obj.sibling_path); +}; + +template void write(std::vector& buf, MembershipWitness const& obj) +{ + using serialize::write; + + write(buf, obj.leaf_index); + write(buf, obj.sibling_path); +}; + +template std::ostream& operator<<(std::ostream& os, MembershipWitness const& obj) +{ + return os << "leaf_index: " << obj.leaf_index << "\n" + << "sibling_path: " << obj.sibling_path << "\n"; +} + +} // namespace aztec3::circuits::abis \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/abis/optionally_revealed_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/optionally_revealed_data.hpp index d9a5b613b31..298b28737e2 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/optionally_revealed_data.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/optionally_revealed_data.hpp @@ -84,4 +84,49 @@ template struct OptionallyRevealedData { } }; +template void read(uint8_t const*& it, OptionallyRevealedData& data) +{ + using serialize::read; + + read(it, data.call_stack_item_hash); + read(it, data.function_data); + read(it, data.emitted_events); + read(it, data.vk_hash); + read(it, data.portal_contract_address); + read(it, data.pay_fee_from_l1); + read(it, data.pay_fee_from_public_l2); + read(it, data.called_from_l1); + read(it, data.called_from_public_l2); +}; + +template void write(std::vector& buf, OptionallyRevealedData const& data) +{ + using serialize::write; + + write(buf, data.call_stack_item_hash); + write(buf, data.function_data); + write(buf, data.emitted_events); + write(buf, data.vk_hash); + write(buf, data.portal_contract_address); + write(buf, data.pay_fee_from_l1); + write(buf, data.pay_fee_from_public_l2); + write(buf, data.called_from_l1); + write(buf, data.called_from_public_l2); +}; + +template std::ostream& operator<<(std::ostream& os, OptionallyRevealedData const& data) +{ + return os << "call_stack_item_hash: " << data.call_stack_item_hash << "\n" + << "function_data:\n" + << data.function_data << "\n" + << "emitted_events:\n" + << data.emitted_events << "\n" + << "vk_hash: " << data.vk_hash << "\n" + << "portal_contract_address: " << data.portal_contract_address << "\n" + << "pay_fee_from_l1: " << data.pay_fee_from_l1 << "\n" + << "pay_fee_from_public_l2: " << data.pay_fee_from_public_l2 << "\n" + << "called_from_l1: " << data.called_from_l1 << "\n" + << "called_from_public_l2: " << data.called_from_public_l2 << "\n"; +} + } // namespace aztec3::circuits::abis \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp index 78b27ca771a..7082007e13f 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp @@ -37,9 +37,9 @@ template class PrivateCircuitPublicInputs { std::array public_call_stack; std::array l1_msg_stack; - fr old_private_data_tree_root; - fr old_nullifier_tree_root; - fr old_contract_tree_root; + fr historic_private_data_tree_root; + fr historic_nullifier_tree_root; + fr historic_contract_tree_root; ContractDeploymentData contract_deployment_data; @@ -67,9 +67,9 @@ template class PrivateCircuitPublicInputs { to_ct(public_call_stack), to_ct(l1_msg_stack), - to_ct(old_private_data_tree_root), - to_ct(old_nullifier_tree_root), - to_ct(old_contract_tree_root), + to_ct(historic_private_data_tree_root), + to_ct(historic_nullifier_tree_root), + to_ct(historic_contract_tree_root), to_circuit_type(contract_deployment_data), }; @@ -98,9 +98,9 @@ template class PrivateCircuitPublicInputs { to_nt(public_call_stack), to_nt(l1_msg_stack), - to_nt(old_private_data_tree_root), - to_nt(old_nullifier_tree_root), - to_nt(old_contract_tree_root), + to_nt(historic_private_data_tree_root), + to_nt(historic_nullifier_tree_root), + to_nt(historic_contract_tree_root), to_native_type(contract_deployment_data), }; @@ -128,9 +128,9 @@ template class PrivateCircuitPublicInputs { spread_arr_into_vec(public_call_stack, inputs); spread_arr_into_vec(l1_msg_stack, inputs); - inputs.push_back(old_private_data_tree_root); - inputs.push_back(old_nullifier_tree_root); - inputs.push_back(old_contract_tree_root); + inputs.push_back(historic_private_data_tree_root); + inputs.push_back(historic_nullifier_tree_root); + inputs.push_back(historic_contract_tree_root); inputs.push_back(contract_deployment_data.hash()); @@ -158,10 +158,9 @@ template void read(uint8_t const*& it, PrivateCircuitPublicInputs read(it, pis.private_call_stack); read(it, pis.public_call_stack); read(it, pis.l1_msg_stack); - read(it, pis.old_private_data_tree_root); - read(it, pis.old_nullifier_tree_root); - read(it, pis.old_contract_tree_root); - + read(it, pis.historic_private_data_tree_root); + read(it, pis.historic_nullifier_tree_root); + read(it, pis.historic_contract_tree_root); read(it, pis.contract_deployment_data); }; @@ -181,9 +180,9 @@ void write(std::vector& buf, PrivateCircuitPublicInputs const& pri write(buf, pis.private_call_stack); write(buf, pis.public_call_stack); write(buf, pis.l1_msg_stack); - write(buf, pis.old_private_data_tree_root); - write(buf, pis.old_nullifier_tree_root); - write(buf, pis.old_contract_tree_root); + write(buf, pis.historic_private_data_tree_root); + write(buf, pis.historic_nullifier_tree_root); + write(buf, pis.historic_contract_tree_root); write(buf, pis.contract_deployment_data); }; @@ -202,9 +201,9 @@ std::ostream& operator<<(std::ostream& os, PrivateCircuitPublicInputs const << "private_call_stack: " << pis.private_call_stack << "\n" << "public_call_stack: " << pis.public_call_stack << "\n" << "l1_msg_stack: " << pis.l1_msg_stack << "\n" - << "old_private_data_tree_root: " << pis.old_private_data_tree_root << "\n" - << "old_nullifier_tree_root: " << pis.old_nullifier_tree_root << "\n" - << "old_nullifier_tree_root: " << pis.old_nullifier_tree_root << "\n" + << "historic_private_data_tree_root: " << pis.historic_private_data_tree_root << "\n" + << "historic_nullifier_tree_root: " << pis.historic_nullifier_tree_root << "\n" + << "contract_deployment_data: " << pis.contract_deployment_data << "\n" << "contract_deployment_data: " << pis.contract_deployment_data << "\n"; } @@ -233,9 +232,9 @@ template class OptionalPrivateCircuitPublicInputs { std::array public_call_stack; std::array l1_msg_stack; - opt_fr old_private_data_tree_root; - opt_fr old_nullifier_tree_root; - opt_fr old_contract_tree_root; + opt_fr historic_private_data_tree_root; + opt_fr historic_nullifier_tree_root; + opt_fr historic_contract_tree_root; std::optional> contract_deployment_data; @@ -255,9 +254,9 @@ template class OptionalPrivateCircuitPublicInputs { std::array const& public_call_stack, std::array const& l1_msg_stack, - opt_fr const& old_private_data_tree_root, - opt_fr const& old_nullifier_tree_root, - opt_fr const& old_contract_tree_root, + opt_fr const& historic_private_data_tree_root, + opt_fr const& historic_nullifier_tree_root, + opt_fr const& historic_contract_tree_root, std::optional> const& contract_deployment_data) : call_context(call_context) @@ -269,9 +268,9 @@ template class OptionalPrivateCircuitPublicInputs { , private_call_stack(private_call_stack) , public_call_stack(public_call_stack) , l1_msg_stack(l1_msg_stack) - , old_private_data_tree_root(old_private_data_tree_root) - , old_nullifier_tree_root(old_nullifier_tree_root) - , old_contract_tree_root(old_contract_tree_root) + , historic_private_data_tree_root(historic_private_data_tree_root) + , historic_nullifier_tree_root(historic_nullifier_tree_root) + , historic_contract_tree_root(historic_contract_tree_root) , contract_deployment_data(contract_deployment_data){}; bool operator==(OptionalPrivateCircuitPublicInputs const&) const = default; @@ -295,9 +294,9 @@ template class OptionalPrivateCircuitPublicInputs { new_inputs.public_call_stack.fill(std::nullopt); new_inputs.l1_msg_stack.fill(std::nullopt); - new_inputs.old_private_data_tree_root = std::nullopt; - new_inputs.old_nullifier_tree_root = std::nullopt; - new_inputs.old_contract_tree_root = std::nullopt; + new_inputs.historic_private_data_tree_root = std::nullopt; + new_inputs.historic_nullifier_tree_root = std::nullopt; + new_inputs.historic_contract_tree_root = std::nullopt; new_inputs.contract_deployment_data = std::nullopt; @@ -342,9 +341,9 @@ template class OptionalPrivateCircuitPublicInputs { make_unused_array_elements_zero(composer, public_call_stack); make_unused_array_elements_zero(composer, l1_msg_stack); - make_unused_element_zero(composer, old_private_data_tree_root); - make_unused_element_zero(composer, old_nullifier_tree_root); - make_unused_element_zero(composer, old_contract_tree_root); + make_unused_element_zero(composer, historic_private_data_tree_root); + make_unused_element_zero(composer, historic_nullifier_tree_root); + make_unused_element_zero(composer, historic_contract_tree_root); make_unused_element_zero(composer, contract_deployment_data); @@ -373,9 +372,9 @@ template class OptionalPrivateCircuitPublicInputs { set_array_public(public_call_stack); set_array_public(l1_msg_stack); - (*old_private_data_tree_root).set_public(); - (*old_nullifier_tree_root).set_public(); - (*old_contract_tree_root).set_public(); + (*historic_private_data_tree_root).set_public(); + (*historic_nullifier_tree_root).set_public(); + (*historic_contract_tree_root).set_public(); (*contract_deployment_data).set_public(); } @@ -406,9 +405,9 @@ template class OptionalPrivateCircuitPublicInputs { to_ct(public_call_stack), to_ct(l1_msg_stack), - to_ct(old_private_data_tree_root), - to_ct(old_nullifier_tree_root), - to_ct(old_contract_tree_root), + to_ct(historic_private_data_tree_root), + to_ct(historic_nullifier_tree_root), + to_ct(historic_contract_tree_root), to_circuit_type(contract_deployment_data), }; @@ -440,9 +439,9 @@ template class OptionalPrivateCircuitPublicInputs { to_nt(public_call_stack), to_nt(l1_msg_stack), - to_nt(old_private_data_tree_root), - to_nt(old_nullifier_tree_root), - to_nt(old_contract_tree_root), + to_nt(historic_private_data_tree_root), + to_nt(historic_nullifier_tree_root), + to_nt(historic_contract_tree_root), to_native_type(contract_deployment_data), }; @@ -475,9 +474,9 @@ template class OptionalPrivateCircuitPublicInputs { spread_arr_opt_into_vec(public_call_stack, inputs); spread_arr_opt_into_vec(l1_msg_stack, inputs); - inputs.push_back(*old_private_data_tree_root); - inputs.push_back(*old_nullifier_tree_root); - inputs.push_back(*old_contract_tree_root); + inputs.push_back(*historic_private_data_tree_root); + inputs.push_back(*historic_nullifier_tree_root); + inputs.push_back(*historic_contract_tree_root); inputs.push_back((*contract_deployment_data).hash()); @@ -504,9 +503,9 @@ template class OptionalPrivateCircuitPublicInputs { .public_call_stack = map(public_call_stack, get_value), .l1_msg_stack = map(l1_msg_stack, get_value), - .old_private_data_tree_root = old_private_data_tree_root.value(), - .old_nullifier_tree_root = old_nullifier_tree_root.value(), - .old_contract_tree_root = old_contract_tree_root.value(), + .historic_private_data_tree_root = historic_private_data_tree_root.value(), + .historic_nullifier_tree_root = historic_nullifier_tree_root.value(), + .historic_contract_tree_root = historic_contract_tree_root.value(), .contract_deployment_data = contract_deployment_data.value(), }; @@ -595,10 +594,9 @@ void read(uint8_t const*& it, OptionalPrivateCircuitPublicInputs& private_c read(it, pis.private_call_stack); read(it, pis.public_call_stack); read(it, pis.l1_msg_stack); - read(it, pis.old_private_data_tree_root); - read(it, pis.old_nullifier_tree_root); - read(it, pis.old_contract_tree_root); - + read(it, pis.historic_private_data_tree_root); + read(it, pis.historic_nullifier_tree_root); + read(it, pis.historic_contract_tree_root); read(it, pis.contract_deployment_data); }; @@ -618,10 +616,9 @@ void write(std::vector& buf, OptionalPrivateCircuitPublicInputs co write(buf, pis.private_call_stack); write(buf, pis.public_call_stack); write(buf, pis.l1_msg_stack); - write(buf, pis.old_private_data_tree_root); - write(buf, pis.old_nullifier_tree_root); - write(buf, pis.old_contract_tree_root); - + write(buf, pis.historic_private_data_tree_root); + write(buf, pis.historic_nullifier_tree_root); + write(buf, pis.historic_contract_tree_root); write(buf, pis.contract_deployment_data); }; @@ -639,9 +636,9 @@ std::ostream& operator<<(std::ostream& os, OptionalPrivateCircuitPublicInputs #include #include @@ -28,6 +29,8 @@ template struct AccumulatedData { std::array public_call_stack; std::array l1_msg_stack; + std::array, KERNEL_NEW_CONTRACTS_LENGTH> new_contracts; + std::array, KERNEL_OPTIONALLY_REVEALED_DATA_LENGTH> optionally_revealed_data; template AccumulatedData> to_circuit_type(Composer& composer) const @@ -57,6 +60,7 @@ template struct AccumulatedData { to_ct(public_call_stack), to_ct(l1_msg_stack), + map(new_contracts, to_circuit_type), map(optionally_revealed_data, to_circuit_type), }; @@ -87,6 +91,7 @@ template struct AccumulatedData { to_nt(public_call_stack), to_nt(l1_msg_stack), + map(new_contracts, to_native_type), map(optionally_revealed_data, to_native_type), }; @@ -108,6 +113,7 @@ template struct AccumulatedData { set_array_public(public_call_stack); set_array_public(l1_msg_stack); + set_array_public(new_contracts); set_array_public(optionally_revealed_data); } @@ -126,6 +132,65 @@ template struct AccumulatedData { e.set_public(); } } + + template void set_array_public(std::array, SIZE>& arr) + { + static_assert(!(std::is_same::value)); + for (auto& e : arr) { + e.set_public(); + } + } +}; + +template void read(uint8_t const*& it, AccumulatedData& accum_data) +{ + using serialize::read; + + read(it, accum_data.aggregation_object); + read(it, accum_data.private_call_count); + read(it, accum_data.new_commitments); + read(it, accum_data.new_nullifiers); + read(it, accum_data.private_call_stack); + read(it, accum_data.public_call_stack); + read(it, accum_data.l1_msg_stack); + read(it, accum_data.new_contracts); + read(it, accum_data.optionally_revealed_data); }; +template void write(std::vector& buf, AccumulatedData const& accum_data) +{ + using serialize::write; + + write(buf, accum_data.aggregation_object); + write(buf, accum_data.private_call_count); + write(buf, accum_data.new_commitments); + write(buf, accum_data.new_nullifiers); + write(buf, accum_data.private_call_stack); + write(buf, accum_data.public_call_stack); + write(buf, accum_data.l1_msg_stack); + write(buf, accum_data.new_contracts); + write(buf, accum_data.optionally_revealed_data); +}; + +template std::ostream& operator<<(std::ostream& os, AccumulatedData const& accum_data) +{ + return os << "aggregation_object:\n" + << accum_data.aggregation_object << "\n" + << "private_call_count: " << accum_data.private_call_count << "\n" + << "new_commitments:\n" + << accum_data.new_commitments << "\n" + << "new_nullifiers:\n" + << accum_data.new_nullifiers << "\n" + << "private_call_stack:\n" + << accum_data.private_call_stack << "\n" + << "public_call_stack:\n" + << accum_data.public_call_stack << "\n" + << "l1_msg_stack:\n" + << accum_data.l1_msg_stack << "\n" + << "new_contracts:\n" + << accum_data.new_contracts << "\n" + << "optionally_revealed_data:\n" + << accum_data.optionally_revealed_data << "\n"; +} + } // namespace aztec3::circuits::abis::private_kernel \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/constant_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/constant_data.hpp index 3d5e9e4b757..d5dd3a77315 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/constant_data.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/constant_data.hpp @@ -57,4 +57,26 @@ template struct ConstantData { } }; +template void read(uint8_t const*& it, ConstantData& constant_data) +{ + using serialize::read; + + read(it, constant_data.old_tree_roots); + read(it, constant_data.tx_context); +}; + +template void write(std::vector& buf, ConstantData const& constant_data) +{ + using serialize::write; + + write(buf, constant_data.old_tree_roots); + write(buf, constant_data.tx_context); +}; + +template std::ostream& operator<<(std::ostream& os, ConstantData const& constant_data) +{ + return os << "old_tree_roots: " << constant_data.old_tree_roots << "\n" + << "tx_context: " << constant_data.tx_context << "\n"; +} + } // namespace aztec3::circuits::abis::private_kernel \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/new_contract_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/new_contract_data.hpp new file mode 100644 index 00000000000..9ac222126e2 --- /dev/null +++ b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/new_contract_data.hpp @@ -0,0 +1,82 @@ +#pragma once + +#include "aztec3/utils/types/circuit_types.hpp" +#include "aztec3/utils/types/convert.hpp" +#include "barretenberg/stdlib/primitives/witness/witness.hpp" +namespace aztec3::circuits::abis::private_kernel { + +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; +using plonk::stdlib::witness_t; +using std::is_same; + +template struct NewContractData { + typedef typename NCT::fr fr; + typedef typename NCT::boolean boolean; + + fr contract_address; // TODO: Change to aztec address type + fr portal_contract_address; // TODO: Change to eth address type + fr function_tree_root; + + template NewContractData> to_circuit_type(Composer& composer) const + { + static_assert((std::is_same::value)); + + auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(composer, e); }; + + NewContractData> new_contract_data = { to_ct(contract_address), + to_ct(portal_contract_address), + to_ct(function_tree_root) }; + + return new_contract_data; + }; + + template NewContractData to_native_type() const + { + static_assert(std::is_same, NCT>::value); + + auto to_native_type = [](T& e) { return e.template to_native_type(); }; + + NewContractData new_contract_data = { to_native_type(contract_address), + to_native_type(portal_contract_address), + to_native_type(function_tree_root) }; + + return new_contract_data; + }; + + void set_public() + { + static_assert(!(std::is_same::value)); + + contract_address.set_public(); + portal_contract_address.set_public(); + function_tree_root.set_public(); + } +}; + +template void read(uint8_t const*& it, NewContractData& new_contract_data) +{ + using serialize::read; + + read(it, new_contract_data.contract_address); + read(it, new_contract_data.portal_contract_address); + read(it, new_contract_data.function_tree_root); +}; + +template void write(std::vector& buf, NewContractData const& new_contract_data) +{ + using serialize::write; + + write(buf, new_contract_data.contract_address); + write(buf, new_contract_data.portal_contract_address); + write(buf, new_contract_data.function_tree_root); +}; + +template std::ostream& operator<<(std::ostream& os, NewContractData const& new_contract_data) +{ + return os << "contract_address: " << new_contract_data.contract_address << "\n" + << "portal_contract_address: " << new_contract_data.portal_contract_address << "\n" + << "function_tree_root: " << new_contract_data.function_tree_root << "\n"; +} + +} // namespace aztec3::circuits::abis::private_kernel \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/old_tree_roots.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/old_tree_roots.hpp index 8e686da4521..d74c8288e4f 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/old_tree_roots.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/old_tree_roots.hpp @@ -62,4 +62,32 @@ template struct OldTreeRoots { } }; +template void read(uint8_t const*& it, OldTreeRoots& old_tree_roots) +{ + using serialize::read; + + read(it, old_tree_roots.private_data_tree_root); + read(it, old_tree_roots.nullifier_tree_root); + read(it, old_tree_roots.contract_tree_root); + read(it, old_tree_roots.private_kernel_vk_tree_root); +}; + +template void write(std::vector& buf, OldTreeRoots const& old_tree_roots) +{ + using serialize::write; + + write(buf, old_tree_roots.private_data_tree_root); + write(buf, old_tree_roots.nullifier_tree_root); + write(buf, old_tree_roots.contract_tree_root); + write(buf, old_tree_roots.private_kernel_vk_tree_root); +}; + +template std::ostream& operator<<(std::ostream& os, OldTreeRoots const& old_tree_roots) +{ + return os << "private_data_tree_root: " << old_tree_roots.private_data_tree_root << "\n" + << "nullifier_tree_root: " << old_tree_roots.nullifier_tree_root << "\n" + << "contract_tree_root: " << old_tree_roots.contract_tree_root << "\n" + << "private_kernel_vk_tree_root: " << old_tree_roots.private_kernel_vk_tree_root << "\n"; +} + } // namespace aztec3::circuits::abis::private_kernel \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp index 803084b4f84..ea4aeb6190d 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp @@ -1,5 +1,6 @@ #pragma once -#include "public_inputs.hpp" +#include "aztec3/circuits/abis/private_kernel/public_inputs.hpp" +#include "aztec3/circuits/abis/verifier_reference_string.hpp" #include #include #include @@ -15,6 +16,7 @@ using std::is_same; template struct PreviousKernelData { typedef typename NCT::fr fr; typedef typename NCT::VK VK; + typedef typename NCT::uint32 uint32; PublicInputs public_inputs; // TODO: not needed as already contained in proof? NativeTypes::Proof proof; // TODO: how to express proof as native/circuit type when it gets used as a buffer? @@ -22,7 +24,7 @@ template struct PreviousKernelData { // TODO: this index and path are meant to be those of a leaf within the tree of _kernel circuit_ vks; not the tree // of functions within the contract tree. - fr vk_index; + uint32 vk_index; std::array vk_path; // WARNING: the `proof` does NOT get converted! @@ -46,4 +48,46 @@ template struct PreviousKernelData { }; }; // namespace aztec3::circuits::abis::private_kernel +template inline void read(B& buf, verification_key& key) +{ + using serialize::read; + // Note this matches write() below + verification_key_data data; + read(buf, data); + key = verification_key{ std::move(data), get_global_verifier_reference_string() }; +} + +template void read(uint8_t const*& it, PreviousKernelData& kernel_data) +{ + using aztec3::circuits::abis::read; + using serialize::read; + + read(it, kernel_data.public_inputs); + // read(it, kernel_data.proof); TODO + read(it, kernel_data.vk); + read(it, kernel_data.vk_index); + read(it, kernel_data.vk_path); +}; + +template void write(std::vector& buf, PreviousKernelData const& kernel_data) +{ + using aztec3::circuits::abis::write; + using serialize::write; + + write(buf, kernel_data.public_inputs); + // write(buf, kernel_data.proof); TODO + write(buf, kernel_data.vk); + write(buf, kernel_data.vk_index); + write(buf, kernel_data.vk_path); +}; + +template std::ostream& operator<<(std::ostream& os, PreviousKernelData const& kernel_data) +{ + return os << "public_inputs: " << kernel_data.public_inputs << "\n" + << "proof: " << kernel_data.proof << "\n" + << "vk: " << kernel_data.vk << "\n" + << "vk_index: " << kernel_data.vk_index << "\n" + << "vk_path: " << kernel_data.vk_path << "\n"; +} + } // namespace aztec3::circuits::abis::private_kernel \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/public_inputs.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/public_inputs.hpp index b36541e02e6..762afedae85 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/public_inputs.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/public_inputs.hpp @@ -66,4 +66,31 @@ template struct PublicInputs { } }; +template void read(uint8_t const*& it, PublicInputs& public_inputs) +{ + using serialize::read; + + read(it, public_inputs.end); + read(it, public_inputs.constants); + read(it, public_inputs.is_private); +}; + +template void write(std::vector& buf, PublicInputs const& public_inputs) +{ + using serialize::write; + + write(buf, public_inputs.end); + write(buf, public_inputs.constants); + write(buf, public_inputs.is_private); +}; + +template std::ostream& operator<<(std::ostream& os, PublicInputs const& public_inputs) +{ + return os << "end:\n" + << public_inputs.end << "\n" + << "constants:\n" + << public_inputs.constants << "\n" + << "is_private: " << public_inputs.is_private << "\n"; +} + } // namespace aztec3::circuits::abis::private_kernel \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp b/circuits/cpp/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp index 4db22b90109..81b56e93818 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp @@ -34,7 +34,7 @@ template struct PublicCircuitPublicInputs { std::array public_call_stack; std::array l1_msg_stack; - fr old_private_data_tree_root; + fr historic_private_data_tree_root; address prover_address; @@ -56,7 +56,7 @@ template struct PublicCircuitPublicInputs { // std::array::fill(0), // std::array::fill(0), - // .old_private_data_tree_root = 0, + // .historic_private_data_tree_root = 0, // .prover_address = 0, // }; @@ -87,7 +87,7 @@ template struct PublicCircuitPublicInputs { .public_call_stack = to_ct(public_call_stack), .l1_msg_stack = to_ct(l1_msg_stack), - .old_private_data_tree_root = to_ct(old_private_data_tree_root), + .historic_private_data_tree_root = to_ct(historic_private_data_tree_root), .prover_address = to_ct(prover_address), }; @@ -116,7 +116,7 @@ template struct PublicCircuitPublicInputs { spread_arr_into_vec(public_call_stack, inputs); spread_arr_into_vec(l1_msg_stack, inputs); - inputs.push_back(old_private_data_tree_root); + inputs.push_back(historic_private_data_tree_root); return NCT::compress(inputs, GeneratorIndex::PRIVATE_CIRCUIT_PUBLIC_INPUTS); } @@ -144,7 +144,7 @@ template void read(uint8_t const*& it, PublicCircuitPublicInputs< read(it, pis.public_call_stack); read(it, pis.l1_msg_stack); - read(it, pis.old_private_data_tree_root); + read(it, pis.historic_private_data_tree_root); read(it, pis.prover_address); }; @@ -167,7 +167,7 @@ void write(std::vector& buf, PublicCircuitPublicInputs const& priv write(buf, pis.public_call_stack); write(buf, pis.l1_msg_stack); - write(buf, pis.old_private_data_tree_root); + write(buf, pis.historic_private_data_tree_root); write(buf, pis.prover_address); }; @@ -187,7 +187,7 @@ std::ostream& operator<<(std::ostream& os, PublicCircuitPublicInputs const& << "public_call_stack: " << pis.public_call_stack << "\n" << "l1_msg_stack: " << pis.l1_msg_stack << "\n" - << "old_private_data_tree_root: " << pis.old_private_data_tree_root << "\n" + << "historic_private_data_tree_root: " << pis.historic_private_data_tree_root << "\n" << "prover_address: " << pis.prover_address << "\n"; } diff --git a/circuits/cpp/src/aztec3/circuits/abis/tx_context.hpp b/circuits/cpp/src/aztec3/circuits/abis/tx_context.hpp index 98f0573e34f..a8680c0485e 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/tx_context.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/tx_context.hpp @@ -26,8 +26,6 @@ template struct TxContext { ContractDeploymentData contract_deployment_data; - fr reference_block_num; - template TxContext> to_circuit_type(Composer& composer) const { static_assert((std::is_same::value)); @@ -37,9 +35,10 @@ template struct TxContext { // auto to_circuit_type = [&](auto& e) { return e.to_circuit_type(composer); }; TxContext> tx_context = { - to_ct(is_fee_payment_tx), to_ct(is_rebate_payment_tx), - to_ct(is_contract_deployment_tx), contract_deployment_data.to_circuit_type(composer), - to_ct(reference_block_num), + to_ct(is_fee_payment_tx), + to_ct(is_rebate_payment_tx), + to_ct(is_contract_deployment_tx), + contract_deployment_data.to_circuit_type(composer), }; return tx_context; @@ -52,9 +51,10 @@ template struct TxContext { auto to_native_type = [](T& e) { return e.template to_native_type(); }; TxContext tx_context = { - to_nt(is_fee_payment_tx), to_nt(is_rebate_payment_tx), - to_nt(is_contract_deployment_tx), to_native_type(contract_deployment_data), - to_nt(reference_block_num), + to_nt(is_fee_payment_tx), + to_nt(is_rebate_payment_tx), + to_nt(is_contract_deployment_tx), + to_native_type(contract_deployment_data), }; return tx_context; @@ -68,14 +68,15 @@ template struct TxContext { fr(is_rebate_payment_tx).set_public(); fr(is_contract_deployment_tx).set_public(); contract_deployment_data.set_public(); - reference_block_num.set_public(); } fr hash() const { std::vector inputs = { - fr(is_fee_payment_tx), fr(is_rebate_payment_tx), fr(is_contract_deployment_tx), - contract_deployment_data.hash(), reference_block_num, + fr(is_fee_payment_tx), + fr(is_rebate_payment_tx), + fr(is_contract_deployment_tx), + contract_deployment_data.hash(), }; return NCT::compress(inputs, GeneratorIndex::TX_CONTEXT); @@ -90,7 +91,6 @@ template void read(uint8_t const*& it, TxContext& tx_context read(it, tx_context.is_rebate_payment_tx); read(it, tx_context.is_contract_deployment_tx); read(it, tx_context.contract_deployment_data); - read(it, tx_context.reference_block_num); }; template void write(std::vector& buf, TxContext const& tx_context) @@ -101,7 +101,6 @@ template void write(std::vector& buf, TxContext con write(buf, tx_context.is_rebate_payment_tx); write(buf, tx_context.is_contract_deployment_tx); write(buf, tx_context.contract_deployment_data); - write(buf, tx_context.reference_block_num); }; template std::ostream& operator<<(std::ostream& os, TxContext const& tx_context) @@ -109,8 +108,9 @@ template std::ostream& operator<<(std::ostream& os, TxContext* global_verifier_reference_string; + +// TODO(AD): After Milestone 1, rewrite this with better injection mechanism. +std::shared_ptr get_global_verifier_reference_string() +{ + return *global_verifier_reference_string; +} +// TODO(AD): After Milestone 1, rewrite this with better injection mechanism. +void set_global_verifier_reference_string(std::shared_ptr const& vrs) +{ + if (global_verifier_reference_string == nullptr) { + global_verifier_reference_string = new std::shared_ptr(); + } + *global_verifier_reference_string = vrs; +} + +} // namespace aztec3::circuits::abis diff --git a/circuits/cpp/src/aztec3/circuits/abis/verifier_reference_string.hpp b/circuits/cpp/src/aztec3/circuits/abis/verifier_reference_string.hpp new file mode 100644 index 00000000000..a8c93a18021 --- /dev/null +++ b/circuits/cpp/src/aztec3/circuits/abis/verifier_reference_string.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include +#include "barretenberg/srs/reference_string/reference_string.hpp" +#include "barretenberg/proof_system/verification_key/verification_key.hpp" + +namespace aztec3::circuits::abis { + +// TODO(AD): After Milestone 1, rewrite this with better injection mechanism. +std::shared_ptr get_global_verifier_reference_string(); +// TODO(AD): After Milestone 1, rewrite this with better injection mechanism. +void set_global_verifier_reference_string(std::shared_ptr const& vrs); + +inline void read(uint8_t const*& it, std::shared_ptr& key) +{ + // Note: matches the structure of write verification_key + bonk::verification_key_data vk_data; + read(it, vk_data); + // TODO(AD): After Milestone 1, rewrite this with better injection mechanism. + key = std::make_shared(std::move(vk_data), get_global_verifier_reference_string()); +} + +inline void write(std::vector& buf, std::shared_ptr const& key) +{ + // Note: matches the structure of write verification_key + write(buf, *key.get()); +} + +} // namespace aztec3::circuits::abis \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/apps/.test.cpp b/circuits/cpp/src/aztec3/circuits/apps/.test.cpp index 2a9bdb917a2..ea9e5b60dc2 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/apps/.test.cpp @@ -96,20 +96,17 @@ class state_var_tests : public ::testing::Test { uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); FunctionData function_data{ - .function_encoding = 1, // TODO: deduce this from the contract, somehow. + .function_selector = 1, // TODO: deduce this from the contract, somehow. .is_private = true, .is_constructor = false, }; - CallContext call_context{ - .msg_sender = msg_sender, - .storage_contract_address = contract_address, - .tx_origin = msg_sender, - .is_delegate_call = false, - .is_static_call = false, - .is_contract_deployment = false, - .reference_block_num = 0, - }; + CallContext call_context{ .msg_sender = msg_sender, + .storage_contract_address = contract_address, + .tx_origin = msg_sender, + .is_delegate_call = false, + .is_static_call = false, + .is_contract_deployment = false }; return NativeOracle(db, contract_address, function_data, call_context, msg_sender_private_key); }; diff --git a/circuits/cpp/src/aztec3/circuits/apps/contract.tpp b/circuits/cpp/src/aztec3/circuits/apps/contract.tpp index 495ea4187c4..ca980073ba4 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/contract.tpp +++ b/circuits/cpp/src/aztec3/circuits/apps/contract.tpp @@ -27,7 +27,7 @@ template void Contract::set_functions(std::vector{ - .function_encoding = uint32(i), + .function_selector = uint32(i), .is_private = function.is_private, .is_constructor = function.is_constructor, }; diff --git a/circuits/cpp/src/aztec3/circuits/apps/function_execution_context.hpp b/circuits/cpp/src/aztec3/circuits/apps/function_execution_context.hpp index 1b5169d5155..35300d060fd 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/function_execution_context.hpp +++ b/circuits/cpp/src/aztec3/circuits/apps/function_execution_context.hpp @@ -170,7 +170,7 @@ template class FunctionExecutionContext { memcpy(&f_encoding, f_encoding_bytes.data(), sizeof(f_encoding)); fr f_encoding_ct = fr(f_encoding); - // Important Note: we MUST constrain this function_encoding value against a fixed selector value. Without the + // Important Note: we MUST constrain this function_selector value against a fixed selector value. Without the // below line, an attacker could pass any f_encoding as a witness. f_encoding_ct.convert_constant_to_fixed_witness(&composer); @@ -180,7 +180,7 @@ template class FunctionExecutionContext { const FunctionData f_function_data_ct{ // Note: we MUST - .function_encoding = f_encoding_ct, + .function_selector = f_encoding_ct, .is_private = true, .is_constructor = false, }; @@ -192,7 +192,6 @@ template class FunctionExecutionContext { .is_delegate_call = false, .is_static_call = false, .is_contract_deployment = false, - .reference_block_num = 0, }; NativeOracle f_oracle(oracle.native_oracle.db, diff --git a/circuits/cpp/src/aztec3/circuits/apps/opcodes/opcodes.tpp b/circuits/cpp/src/aztec3/circuits/apps/opcodes/opcodes.tpp index 5b0fba4055d..4e73e0ff174 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/opcodes/opcodes.tpp +++ b/circuits/cpp/src/aztec3/circuits/apps/opcodes/opcodes.tpp @@ -55,7 +55,7 @@ Note Opcodes::UTXO_SLOAD(UTXOStateVar* utxo_state_var, // TODO within this function: // - Merkle Membership Check using the contract_address, utxo_datum.{sibling_path, leaf_index, - // old_private_data_tree_root} + // historic_private_data_tree_root} return new_note; }; @@ -97,7 +97,7 @@ std::vector Opcodes::UTXO_SLOAD(UTXOSetStateVar* // TODO within this function: // - Merkle Membership Check using the contract_address, utxo_datum.{sibling_path, leaf_index, - // old_private_data_tree_root} + // historic_private_data_tree_root} new_notes.push_back(new_note); } diff --git a/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp b/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp index fac8f03d6c4..23c62f9630b 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp @@ -24,7 +24,7 @@ class escrow_tests : public ::testing::Test { uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); FunctionData function_data{ - .function_encoding = 1, // TODO: deduce this from the contract, somehow. + .function_selector = 1, // TODO: deduce this from the contract, somehow. .is_private = true, .is_constructor = false, }; @@ -36,7 +36,6 @@ class escrow_tests : public ::testing::Test { .is_delegate_call = false, .is_static_call = false, .is_contract_deployment = false, - .reference_block_num = 0, }; return NativeOracle(db, contract_address, function_data, call_context, msg_sender_private_key); diff --git a/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp b/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp index 559e98b9741..d81b65967ed 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp +++ b/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/transfer.cpp @@ -101,7 +101,7 @@ OptionalPrivateCircuitPublicInputs transfer(FunctionExecutionContext& exec_c public_inputs.emitted_events[1] = CT::fr::copy_as_new_witness(composer, asset_id); /// TODO: merkle membership check - // public_inputs.old_private_data_tree_root + // public_inputs.historic_private_data_tree_root exec_ctx.finalise(); diff --git a/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp b/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp index 7aa48c54d9b..d6d9b401a3e 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp +++ b/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/withdraw.cpp @@ -95,7 +95,7 @@ OptionalPrivateCircuitPublicInputs withdraw(FunctionExecutionContext& exec_c exec_ctx.finalise(); /// TODO: merkle membership check - // public_inputs.old_private_data_tree_root + // public_inputs.historic_private_data_tree_root info("public inputs: ", public_inputs); diff --git a/circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp b/circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp index 990d2e93de1..82502033d74 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp @@ -24,7 +24,7 @@ TEST(private_to_private_function_call_tests, test_private_to_private_function_ca uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL); const FunctionData function_data{ - .function_encoding = 1, // TODO: deduce this from the contract, somehow. + .function_selector = 1, // TODO: deduce this from the contract, somehow. .is_private = true, .is_constructor = false, }; @@ -36,7 +36,6 @@ TEST(private_to_private_function_call_tests, test_private_to_private_function_ca .is_delegate_call = false, .is_static_call = false, .is_contract_deployment = false, - .reference_block_num = 0, }; NativeOracle fn1_oracle = NativeOracle(db, contract_address, function_data, call_context, msg_sender_private_key); diff --git a/circuits/cpp/src/aztec3/circuits/apps/utxo_datum.hpp b/circuits/cpp/src/aztec3/circuits/apps/utxo_datum.hpp index fb9018c3191..dd2ce3526b7 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/utxo_datum.hpp +++ b/circuits/cpp/src/aztec3/circuits/apps/utxo_datum.hpp @@ -25,7 +25,7 @@ template struct UTXOSLoadDatum { std::vector sibling_path; uint32 leaf_index; - fr old_private_data_tree_root; + fr historic_private_data_tree_root; template auto to_circuit_type(Composer& composer) const { @@ -38,7 +38,7 @@ template struct UTXOSLoadDatum { UTXOSLoadDatum, decltype(preimage_ct)> datum = { to_ct(commitment), to_ct(contract_address), preimage_ct, - to_ct(sibling_path), to_ct(leaf_index), to_ct(old_private_data_tree_root), + to_ct(sibling_path), to_ct(leaf_index), to_ct(historic_private_data_tree_root), }; return datum; diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/.test.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/.test.cpp index 20abb061eb8..b8dcb1a70f3 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/.test.cpp @@ -90,7 +90,7 @@ TEST(private_kernel_tests, test_deposit) DB db; FunctionData function_data{ - .function_encoding = 1, // TODO: deduce this from the contract, somehow. + .function_selector = 1, // TODO: deduce this from the contract, somehow. .is_private = true, .is_constructor = false, }; @@ -102,7 +102,6 @@ TEST(private_kernel_tests, test_deposit) .is_delegate_call = false, .is_static_call = false, .is_contract_deployment = false, - .reference_block_num = 0, }; NativeOracle deposit_oracle = @@ -141,7 +140,6 @@ TEST(private_kernel_tests, test_deposit) .is_rebate_payment_tx = false, .is_contract_deployment_tx = false, .contract_deployment_data = ContractDeploymentData(), - .reference_block_num = 0, }, .chain_id = 1, }; @@ -188,7 +186,7 @@ TEST(private_kernel_tests, test_deposit) ConstantData{ .old_tree_roots = OldTreeRoots{ - .private_data_tree_root = deposit_public_inputs.old_private_data_tree_root, + .private_data_tree_root = deposit_public_inputs.historic_private_data_tree_root, // .nullifier_tree_root = // .contract_tree_root = // .private_kernel_vk_tree_root = diff --git a/circuits/cpp/src/aztec3/constants.hpp b/circuits/cpp/src/aztec3/constants.hpp index 84c8aa9d028..f15aa05832e 100644 --- a/circuits/cpp/src/aztec3/constants.hpp +++ b/circuits/cpp/src/aztec3/constants.hpp @@ -3,6 +3,7 @@ namespace aztec3 { +// Note: must be kept in sync with ts/structs/constants.ts constexpr size_t ARGS_LENGTH = 8; constexpr size_t RETURN_VALUES_LENGTH = 4; constexpr size_t EMITTED_EVENTS_LENGTH = 4; @@ -19,6 +20,7 @@ constexpr size_t L1_MSG_STACK_LENGTH = 2; constexpr size_t KERNEL_NEW_COMMITMENTS_LENGTH = 16; constexpr size_t KERNEL_NEW_NULLIFIERS_LENGTH = 16; +constexpr size_t KERNEL_NEW_CONTRACTS_LENGTH = 8; constexpr size_t KERNEL_PRIVATE_CALL_STACK_LENGTH = 8; constexpr size_t KERNEL_PUBLIC_CALL_STACK_LENGTH = 8; constexpr size_t KERNEL_L1_MSG_STACK_LENGTH = 4; @@ -29,6 +31,9 @@ constexpr size_t CONTRACT_TREE_HEIGHT = 4; constexpr size_t PRIVATE_DATA_TREE_HEIGHT = 8; constexpr size_t NULLIFIER_TREE_HEIGHT = 8; +constexpr size_t PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT = 8; +constexpr size_t CONTRACT_TREE_ROOTS_TREE_HEIGHT = 8; + constexpr size_t FUNCTION_SELECTOR_NUM_BYTES = 31; // must be <= 31 // Enumerate the hash_indices which are used for pedersen hashing diff --git a/circuits/cpp/src/aztec3/oracle/fake_db.hpp b/circuits/cpp/src/aztec3/oracle/fake_db.hpp index 4d791f7e5f4..c748d050ca6 100644 --- a/circuits/cpp/src/aztec3/oracle/fake_db.hpp +++ b/circuits/cpp/src/aztec3/oracle/fake_db.hpp @@ -67,7 +67,7 @@ class FakeDB { .sibling_path = sibling_path, .leaf_index = 2, - .old_private_data_tree_root = required_utxo_tree_root, + .historic_private_data_tree_root = required_utxo_tree_root, }; }; @@ -115,7 +115,7 @@ class FakeDB { .sibling_path = sibling_path, .leaf_index = 2, - .old_private_data_tree_root = required_utxo_tree_root, + .historic_private_data_tree_root = required_utxo_tree_root, }); } @@ -159,7 +159,7 @@ class FakeDB { .sibling_path = sibling_path, .leaf_index = 2, - .old_private_data_tree_root = required_utxo_tree_root, + .historic_private_data_tree_root = required_utxo_tree_root, }; }; }; diff --git a/circuits/specs/src/architecture/rollup-circuits/base-rollup.md b/circuits/specs/src/architecture/rollup-circuits/base-rollup.md index 5d4111c419f..40bb2b34a75 100644 --- a/circuits/specs/src/architecture/rollup-circuits/base-rollup.md +++ b/circuits/specs/src/architecture/rollup-circuits/base-rollup.md @@ -248,25 +248,26 @@ optionallyRevealedData: [{ },...], // combined from both input kernel snarks' public inputs proverRecords: [{ proverAddress, - totalNumberOfGates, + totalNumberOfGates, },...], // combined from both input kernel snarks' public inputs proverAddress, minMinTimestamp, // the min of the minTimestamps passed to this circuit maxMinTimestamp, // the max of the minTimestamps passed to this circuit ``` - ## Execution Logic We'll do a few things in the circuit: + - Verify the two kernel snarks - Merge some arrays from both inputs - Check some tree stuff - Check the public inputs of both kernel snarks based on the ordering: - - `kernelSnarks[0]` happened first - - `kernelSnarks[1]` happened second + - `kernelSnarks[0]` happened first + - `kernelSnarks[1]` happened second So: + - the base rollup circuit's `start` tree data must line up with the `initial...` tree data of `kernelSnarks[0]`. - the `end` tree data of `kernelSnarks[0]` must line up with the `initial...` tree data of `kernelSnarks[1]`. - the `end` tree data of `kernelSnarks[1]` must line up with the base rollup circuit's `end` tree data. @@ -274,153 +275,159 @@ So: Here we go... - For `i in [0, 1]`: - - If `kernelSnarks[i].publicInputs.constants.isConstructorRecursion == true`: - - Revert. A constructor kernel can only be verified by the contractDeployment kernel snark. - - Verify `(kernelSnarks[i].proof, kernelSnarks[i].publicInputs)` against the vk `kernelSnarks[i].vk`. - - Validate that the `kernelSnarks[i].vk` is a valid kernel snark of the correct `kernelSnarks[i].kernelType` with a membership check of the relevent kernel snark vk tree: - - Calculate `kernelVKHash := hash(kernelSnarks[i].vk)`; - - Compute `root` using the `kernelVKHash`, `kernelSnarks[i].vkPath` and `kernelSnarks[i].vkIndex`. - - Validate that `root == constants.KernelVKTreeRoot`. + - If `kernelSnarks[i].publicInputs.constants.isConstructorRecursion == true`: + - Revert. A constructor kernel can only be verified by the contractDeployment kernel snark. + - Verify `(kernelSnarks[i].proof, kernelSnarks[i].publicInputs)` against the vk `kernelSnarks[i].vk`. + - Validate that the `kernelSnarks[i].vk` is a valid kernel snark of the correct `kernelSnarks[i].kernelType` with a membership check of the relevent kernel snark vk tree: + - Calculate `kernelVKHash := hash(kernelSnarks[i].vk)`; + - Compute `root` using the `kernelVKHash`, `kernelSnarks[i].vkPath` and `kernelSnarks[i].vkIndex`. + - Validate that `root == constants.KernelVKTreeRoot`. Validate that the callStacks of both kernel snarks were all completed (are all empty): + - For `i in [0, 1]`: - - `require(callCount == 0);` - - Require all values of `privateCallStack`, `publicCallStack`, `contractDeploymentCallStack` to be `0`. + - `require(callCount == 0);` + - Require all values of `privateCallStack`, `publicCallStack`, `contractDeploymentCallStack` to be `0`. Check the old tree roots (that were referred-to by the users' circuits) have actually existed (at some point in history) as the root of their tree: + - For `i in [0, 1]`: - - Check the old private data tree root once existed: - - Calculate `root` using: `leafValue: kernelSnarks[i].publicInputs.constants.oldTreeRoots.privateDataTree, leafIndex: membershipWitnesses.oldPrivateDataTreeRoots[i].leafIndex, siblingPath: membershipWitnesses.oldPrivateDataTreeRoots[i].siblingPath`. - - `assert(root == start.privateDataTreeRootsTree.root` - - Check the old contract tree root once existed: - - Calculate `root` using: `leafValue: kernelSnarks[i].publicInputs.constants.oldTreeRoots.contractTree, leafIndex: membershipWitnesses.oldContractTreeRoots[i].leafIndex, siblingPath: membershipWitnesses.oldContractTreeRoots[i].siblingPath`. - - `assert(root == start.contractTreeRootsTree.root` - - Check the old L1 results tree root once existed: - - Calculate `root` using: `leafValue: kernelSnarks[i].publicInputs.constants.oldTreeRoots.l1ResultsTree, leafIndex: membershipWitnesses.oldL1ResultsTreeRoots[i].leafIndex, siblingPath: membershipWitnesses.oldL1ResultsTreeRoots[i].siblingPath`. - - `assert(root == start.contractTreeRootsTree.root` + - Check the old private data tree root once existed: + - Calculate `root` using: `leafValue: kernelSnarks[i].publicInputs.constants.oldTreeRoots.privateDataTree, leafIndex: membershipWitnesses.oldPrivateDataTreeRoots[i].leafIndex, siblingPath: membershipWitnesses.oldPrivateDataTreeRoots[i].siblingPath`. + - `assert(root == start.privateDataTreeRootsTree.root` + - Check the old contract tree root once existed: + - Calculate `root` using: `leafValue: kernelSnarks[i].publicInputs.constants.oldTreeRoots.contractTree, leafIndex: membershipWitnesses.oldContractTreeRoots[i].leafIndex, siblingPath: membershipWitnesses.oldContractTreeRoots[i].siblingPath`. + - `assert(root == start.contractTreeRootsTree.root` + - Check the old L1 results tree root once existed: + - Calculate `root` using: `leafValue: kernelSnarks[i].publicInputs.constants.oldTreeRoots.l1ResultsTree, leafIndex: membershipWitnesses.oldL1ResultsTreeRoots[i].leafIndex, siblingPath: membershipWitnesses.oldL1ResultsTreeRoots[i].siblingPath`. + - `assert(root == start.contractTreeRootsTree.root` Check the alignment of the start and end states of the two trees which were updated _within the kernel snarks_ (the publicDataTree and the contractTree). This ensures the kernel snarks didn't make any unexpected changes to those trees: - `start -> kernelSnarks[0]`: - - `require(start.publicDataTree.root == kernelSnarks[0].publicInputs.constants.initialPublicDataTreeRoot);` - - `require(start.contractTree.root == kernelSnarks[0].publicInputs.constants.initialContractTreeRoot);` - - `require(start.contractTree.nextAvailableLeafIndex == kernelSnarks[0].publicInputs.constants.initialNextAvailableContractTreeLeafIndex);` + - `require(start.publicDataTree.root == kernelSnarks[0].publicInputs.constants.initialPublicDataTreeRoot);` + - `require(start.contractTree.root == kernelSnarks[0].publicInputs.constants.initialContractTreeRoot);` + - `require(start.contractTree.nextAvailableLeafIndex == kernelSnarks[0].publicInputs.constants.initialNextAvailableContractTreeLeafIndex);` - `kernelSnarks[0] -> kernelSnarks[1]`: - - `require(kernelSnarks[0].publicInputs.end.publicDataTreeRoot == kernelSnarks[1].publicInputs.constants.initialPublicDataTreeRoot);` - - `require(kernelSnarks[0].publicInputs.end.contractTreeRoot == kernelSnarks[1].publicInputs.constants.initialContractTreeRoot);` - - `require(kernelSnarks[0].publicInputs.end.nextAvailableContractTreeLeafIndex == kernelSnarks[1].publicInputs.constants.initialNextAvailableContractTreeLeafIndex);` + - `require(kernelSnarks[0].publicInputs.end.publicDataTreeRoot == kernelSnarks[1].publicInputs.constants.initialPublicDataTreeRoot);` + - `require(kernelSnarks[0].publicInputs.end.contractTreeRoot == kernelSnarks[1].publicInputs.constants.initialContractTreeRoot);` + - `require(kernelSnarks[0].publicInputs.end.nextAvailableContractTreeLeafIndex == kernelSnarks[1].publicInputs.constants.initialNextAvailableContractTreeLeafIndex);` - `kernelSnarks[1] -> end`: - - `require(kernelSnarks[1].publicInputs.end.publicDataTreeRoot == end.publicDataTree.root);` - - `require(kernelSnarks[1].publicInputs.end.contractTreeRoot == end.contractTree.root);` - - `require(kernelSnarks[1].publicInputs.end.nextAvailableContractTreeLeafIndex == end.contractTree.nextAvailableLeafIndex);` + - `require(kernelSnarks[1].publicInputs.end.publicDataTreeRoot == end.publicDataTree.root);` + - `require(kernelSnarks[1].publicInputs.end.contractTreeRoot == end.contractTree.root);` + - `require(kernelSnarks[1].publicInputs.end.nextAvailableContractTreeLeafIndex == end.contractTree.nextAvailableLeafIndex);` Merge input stacks/arrays to create single output stacks/arrays: + - `assert(l1CallStack == [...kernelSnarks[0].publicInputs.end.l1CallStack, ...kernelSnarks[1].publicInputs..end.l1CallStack]);` - `assert(optionallyRevealedData == [...kernelSnarks[0].publicInputs..end.optionallyRevealedData, ...kernelSnarks[1].publicInputs.end.optionallyRevealedData]);` - `assert(deployedContractData == [...kernelSnarks[0].publicInputs..end.deployedContractData, ...kernelSnarks[1].publicInputs.end.deployedContractData]);` - If either of the kernel snarks was a callback execution, check that their purported L1 Result is correct (i.e. that it exists in the L1 results tree). We do this here, in the base rollup circuit rather than the public kernel circuit, because this only needs to be done at most once per tx, so it'd be wasteful to repeat this calc in every kernel recursion. Having said that, the _private_ kernel circuit does also offer this functionality, so that a user may hide which callback they're calling (and even the fact they're executing a callback at all). This logic MUST come before the 'nullifier insertion' logic, because we add a new nullifier to the set here. + - Let `callbackNullifiers = []` - For `i in [0, 1]`: - - If `kernelSnarks[i].publicInputs.constants.isCallbackRecursion` - - `require(l1ResultHash != 0)` to prevent a user executing a callback which refers to a _pending_ result. - - Extract `{ l1ResultHash, l1ResultsTreeLeafIndex } = kernelSnarks[i].publicInputs.constants.executedCallback;` - - Extract `{ callbackStackItem: { callbackPublicKey, successCallback, failureCallbac } } = membershipWitnesses.executedCallbacks[i];` - - Extract the function data of the callback which was called (this will always be at the 0th position of the optionallyRevealedData): - - Let `executedCallbackFunctionData = kernelSnarks[i].publicInputs.end.optionallyRevealedData[0].functionSelector`. - - `require(executedCallbackFunctionData != 0)` - - Let `executedCallbackEmittedPublicInputs = kernelSnarks[i].publicInputs.end.optionallyRevealedData[0].emittedPublicInputs`. - - If `l1ResultHash != 0` (success): - - Check the successCallback's `functionData` matches the kernel snark's: - - `require(successCallbackHash.functionData == executedCallbackFunctionData)` - - In fact, check the entire successCallbackCallHash - - Else: - - Check the failureCallbackHash's `functionData` matches the kernel snark's: - - `require(failureCallbackHash.functionData == executedCallbackFunctionData)` - - In fact, check the entire successCallbackCallHash - - `require(callbackPublicKey == 0)`, otherwise this callback should have been processed in the private kernel snark. - - Let `callbackStackItemHash := hash(callbackPublicKey, callbackStackItem.successCallbackHash, callbackStackItem.failureCallbackHash)` - - Let `leafValue = hash(l1ResultHash, callbackStackItemHash);` - - Check membership of the `leafValue` in the `l1ResultsTree` using: - - `l1ResultsTreeLeafIndex` - - `membershipWitnesses.executedCallbacks[i].siblingPath` - - `kernelSnarks[i].publicInputs.constants.oldTreeRoots.l1ResultsTree` - - Set `callbackNullifiers[i] := hash(callbackStackItemHash, callbackPrivateKey = 0)` to prevent this callback from being executed again. - - We don't include the whole `leafValue` in the preimage of the nullifier, to prevent a user maliciously calling the callback twice: once for 'success' and once for 'fail' (although that shouldn't be possible if the 'L1 results copier' circuit works correctly). - - The `callbackPrivateKey` only gets used if the callback is executed privately (in which case all of the checks of this section are done in the private kernel circuit. The private kernel circuit would then toggle the `isCallbackRecursion` to `false`, to hide the fact that it's a callback, and so that this section is skipped within this circuit). + - If `kernelSnarks[i].publicInputs.constants.isCallbackRecursion` + - `require(l1ResultHash != 0)` to prevent a user executing a callback which refers to a _pending_ result. + - Extract `{ l1ResultHash, l1ResultsTreeLeafIndex } = kernelSnarks[i].publicInputs.constants.executedCallback;` + - Extract `{ callbackStackItem: { callbackPublicKey, successCallback, failureCallbac } } = membershipWitnesses.executedCallbacks[i];` + - Extract the function data of the callback which was called (this will always be at the 0th position of the optionallyRevealedData): + - Let `executedCallbackFunctionData = kernelSnarks[i].publicInputs.end.optionallyRevealedData[0].functionSelector`. + - `require(executedCallbackFunctionData != 0)` + - Let `executedCallbackEmittedPublicInputs = kernelSnarks[i].publicInputs.end.optionallyRevealedData[0].emittedPublicInputs`. + - If `l1ResultHash != 0` (success): + - Check the successCallback's `functionData` matches the kernel snark's: + - `require(successCallbackHash.functionData == executedCallbackFunctionData)` + - In fact, check the entire successCallbackCallHash + - Else: + - Check the failureCallbackHash's `functionData` matches the kernel snark's: + - `require(failureCallbackHash.functionData == executedCallbackFunctionData)` + - In fact, check the entire successCallbackCallHash + - `require(callbackPublicKey == 0)`, otherwise this callback should have been processed in the private kernel snark. + - Let `callbackStackItemHash := hash(callbackPublicKey, callbackStackItem.successCallbackHash, callbackStackItem.failureCallbackHash)` + - Let `leafValue = hash(l1ResultHash, callbackStackItemHash);` + - Check membership of the `leafValue` in the `l1ResultsTree` using: + - `l1ResultsTreeLeafIndex` + - `membershipWitnesses.executedCallbacks[i].siblingPath` + - `kernelSnarks[i].publicInputs.constants.oldTreeRoots.l1ResultsTree` + - Set `callbackNullifiers[i] := hash(callbackStackItemHash, callbackPrivateKey = 0)` to prevent this callback from being executed again. + - We don't include the whole `leafValue` in the preimage of the nullifier, to prevent a user maliciously calling the callback twice: once for 'success' and once for 'fail' (although that shouldn't be possible if the 'L1 results copier' circuit works correctly). + - The `callbackPrivateKey` only gets used if the callback is executed privately (in which case all of the checks of this section are done in the private kernel circuit. The private kernel circuit would then toggle the `isCallbackRecursion` to `false`, to hide the fact that it's a callback, and so that this section is skipped within this circuit). Add new pending callbacks to the l1ResultsTree: + - Let `pendingResultLeafValues = [];` - For `i in [0, 1]` - For each `callbackStackItem in kernelSnarks[i].publicInputs.end.callbackStack`. - Set `pendingResultLeafValues.push( callbackStackItemHash )` ("pendingResult", because "finalisation" of the leaf happens once the L1 results are added in the next rollup). - Batch-insert the `pendingResultLeafValues`, using: - - `start.l1ResultsTree.nextAvailableLeafIndex` - - `start.l1ResultsTree.root` (to reconcile the starting root before adding more leaves) - - `end.l1ResultsTree.nextAvailableLeafIndex` - - `end.l1ResultsTree.root` - - `membershipWitnesses.callbackStackBatch` - - + - `start.l1ResultsTree.nextAvailableLeafIndex` + - `start.l1ResultsTree.root` (to reconcile the starting root before adding more leaves) + - `end.l1ResultsTree.nextAvailableLeafIndex` + - `end.l1ResultsTree.root` + - `membershipWitnesses.callbackStackBatch` Add the inputNullifiers and outputCommitments to their trees: + - Merge the arrays from the two input kernel snarks: - - Let `inputNullifiers := [...kernelSnarks[0].publicInputs.end.inputNullifiers, ...kernelSnarks[1].publicInputs.end.inputNullifiers]`; - - Let `outputCommitments := [...kernelSnarks[0].publicInputs.end.outputCommitments, ...kernelSnarks[1].publicInputs.end.outputCommitments]`; + - Let `inputNullifiers := [...kernelSnarks[0].publicInputs.end.inputNullifiers, ...kernelSnarks[1].publicInputs.end.inputNullifiers]`; + - Let `outputCommitments := [...kernelSnarks[0].publicInputs.end.outputCommitments, ...kernelSnarks[1].publicInputs.end.outputCommitments]`; Nullifiers: + - Let `inputNullifierLeafIndex := start.nullifierTree.nextAvailableLeafIndex` - Let `rootBeforeInsertion := start.nullifierTree.root` -- For each `inputNullifier` in `inputNullifiers` (index `i`): - - Do a non-membership check, using: - - `membershipWitnesses.lowNullifiers[i]` (to validate `rootBeforeInsertion`) - - `inputNullifiers[i]` to validate non-membership. - - See the hackmd for the new nullifier tree info. - - Update all of the `lowNullifiers[i].leafValue.nextValue` and `lowNullifiers[i].leafValue.nextIndex` values, using: - - `membershipWitnesses.lowNullifiers[i]` - - `inputNullifiers[i]` to update the 'next' values. - - Batch-insert the new `inputNullifiers`, using: - - `start.nullifierTree.nextAvailableLeafIndex` - - `start.nullifierTree.root` (to reconcile the starting root before adding more leaves) - - `end.nullifierTree.nextAvailableLeafIndex` - - `end.nullifierTree.root` - - `membershipWitnesses.inputNullifiersBatch` +- For each `inputNullifier` in `inputNullifiers` (index `i`): + - Do a non-membership check, using: + - `membershipWitnesses.lowNullifiers[i]` (to validate `rootBeforeInsertion`) + - `inputNullifiers[i]` to validate non-membership. + - See the hackmd for the new nullifier tree info. + - Update all of the `lowNullifiers[i].leafValue.nextValue` and `lowNullifiers[i].leafValue.nextIndex` values, using: + - `membershipWitnesses.lowNullifiers[i]` + - `inputNullifiers[i]` to update the 'next' values. + - Batch-insert the new `inputNullifiers`, using: + - `start.nullifierTree.nextAvailableLeafIndex` + - `start.nullifierTree.root` (to reconcile the starting root before adding more leaves) + - `end.nullifierTree.nextAvailableLeafIndex` + - `end.nullifierTree.root` + - `membershipWitnesses.inputNullifiersBatch` Commitments: -- Batch-insert `outputCommitments` (and validate start and end tree states) using: - - `start.privateDataTree.nextAvailableLeafIndex` - - `start.privateDataTree.root` (to reconcile the starting root before adding more leaves) - - `end.privateDataTree.nextAvailableLeafIndex` - - `end.privateDataTree.root` - - `membershipWitnesses.outputCommitmentsBatch` +- Batch-insert `outputCommitments` (and validate start and end tree states) using: + - `start.privateDataTree.nextAvailableLeafIndex` + - `start.privateDataTree.root` (to reconcile the starting root before adding more leaves) + - `end.privateDataTree.nextAvailableLeafIndex` + - `end.privateDataTree.root` + - `membershipWitnesses.outputCommitmentsBatch` Update the (difficultly-named) trees whose leaves are the roots of historic trees. I.e. add the newly-calculated roots as the 'latest' roots of the historic trees (`privateDataTreeRootsTree`, `contractTreeRootsTree`, `l1ResultsTreeRootsTree`). - Insert the newly-calculated `end.privateDataTree.root` as a new leaf in the `privateDataTreeRootsTree` using: - - `membershipWitnesses.endPrivateDataTreeRoot.siblingPath` - - `start.privateDataTreeRootsTree.nextAvailableLeafIndex` - - `start.privateDataTreeRootsTree.root` - - `end.privateDataTreeRootsTree.nextAvailableLeafIndex` - - `end.privateDataTreeRootsTree.root` + + - `membershipWitnesses.endPrivateDataTreeRoot.siblingPath` + - `start.privateDataTreeRootsTree.nextAvailableLeafIndex` + - `start.privateDataTreeRootsTree.root` + - `end.privateDataTreeRootsTree.nextAvailableLeafIndex` + - `end.privateDataTreeRootsTree.root` - Insert the newly-calculated `end.contractTree.root` as a new leaf in the `contractTreeRootsTree` using: - - `membershipWitnesses.endContractTreeRoot.siblingPath` - - `start.contractTreeRootsTree.nextAvailableLeafIndex` - - `start.contractTreeRootsTree.root` - - `end.contractTreeRootsTree.nextAvailableLeafIndex` - - `end.contractTreeRootsTree.root` + + - `membershipWitnesses.endContractTreeRoot.siblingPath` + - `start.contractTreeRootsTree.nextAvailableLeafIndex` + - `start.contractTreeRootsTree.root` + - `end.contractTreeRootsTree.nextAvailableLeafIndex` + - `end.contractTreeRootsTree.root` - Insert the newly-calculated `end.l1ResultsTree.root` as a new leaf in the `l1ResultsTreeRootsTree` using: - - `membershipWitnesses.endl1ResultsTreeRoot.siblingPath` - - `start.l1ResultsTreeRootsTree.nextAvailableLeafIndex` - - `start.l1ResultsTreeRootsTree.root` - - `end.l1ResultsTreeRootsTree.nextAvailableLeafIndex` - - `end.l1ResultsTreeRootsTree.root` + - `membershipWitnesses.endl1ResultsTreeRoot.siblingPath` + - `start.l1ResultsTreeRootsTree.nextAvailableLeafIndex` + - `start.l1ResultsTreeRootsTree.root` + - `end.l1ResultsTreeRootsTree.nextAvailableLeafIndex` + - `end.l1ResultsTreeRootsTree.root` * Calculate new data to push to `proverRecords`: - - Calculate new prover record data from both input kernelSnarks, using the `proverAddress` and `vk` of the kernel snarks' `publicInputs` (see detailed logic in the kernel snarks' 'execution logic' sections). - - Push that data onto the `proverRecords` array. \ No newline at end of file + - Calculate new prover record data from both input kernelSnarks, using the `proverAddress` and `vk` of the kernel snarks' `publicInputs` (see detailed logic in the kernel snarks' 'execution logic' sections). + - Push that data onto the `proverRecords` array. From c8f694f2ba415eaa73e926a52b23b0757e903094 Mon Sep 17 00:00:00 2001 From: Adam Domurad Date: Tue, 21 Mar 2023 10:16:49 -0400 Subject: [PATCH 077/166] feat(ts): building after merge --- .../cpp/src/aztec3/circuits/abis/.test.cpp | 1 - .../src/aztec3/circuits/abis/barretenberg.hpp | 26 ------------------- .../abis/barretenberg/aggregation_object.hpp | 10 ++++--- .../circuits/abis/barretenberg/proof.hpp | 9 +++---- .../verifier_reference_string.cpp | 4 +-- .../verifier_reference_string.hpp | 4 +-- .../cpp/src/aztec3/circuits/abis/c_bind.cpp | 4 +-- .../abis/private_kernel/accumulated_data.hpp | 1 + .../private_kernel/previous_kernel_data.hpp | 5 ++-- .../src/aztec3/utils/types/native_types.hpp | 8 ------ 10 files changed, 21 insertions(+), 51 deletions(-) delete mode 100644 circuits/cpp/src/aztec3/circuits/abis/barretenberg.hpp rename circuits/cpp/src/aztec3/circuits/abis/{ => barretenberg}/verifier_reference_string.cpp (92%) rename circuits/cpp/src/aztec3/circuits/abis/{ => barretenberg}/verifier_reference_string.hpp (93%) diff --git a/circuits/cpp/src/aztec3/circuits/abis/.test.cpp b/circuits/cpp/src/aztec3/circuits/abis/.test.cpp index 26251a6145f..652a7d2ee71 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/abis/.test.cpp @@ -1,7 +1,6 @@ #include #include #include -// #include #include "index.hpp" #include diff --git a/circuits/cpp/src/aztec3/circuits/abis/barretenberg.hpp b/circuits/cpp/src/aztec3/circuits/abis/barretenberg.hpp deleted file mode 100644 index c76c3d1b2d2..00000000000 --- a/circuits/cpp/src/aztec3/circuits/abis/barretenberg.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once -#include -#include -#include - -namespace serialize { - -inline void read(uint8_t const*& it, plonk::stdlib::types::NativeTypes::Proof& proof) -{ - using serialize::read; - - read(it, proof.proof_data); -}; - -inline void read(uint8_t const*& it, plonk::stdlib::types::NativeTypes::AggregationObject& obj) -{ - using serialize::read; - - read(it, obj.P0); - read(it, obj.P1); - read(it, obj.public_inputs); - read(it, obj.proof_witness_indices); - read(it, obj.has_data); -}; - -} // namespace serialize \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/abis/barretenberg/aggregation_object.hpp b/circuits/cpp/src/aztec3/circuits/abis/barretenberg/aggregation_object.hpp index ec9fa038daa..a591834980b 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/barretenberg/aggregation_object.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/barretenberg/aggregation_object.hpp @@ -1,9 +1,10 @@ #pragma once -#include -#include +#include "barretenberg/common/serialize.hpp" +#include "aztec3/utils/types/native_types.hpp" namespace serialize { -inline void read(uint8_t const*& it, plonk::stdlib::types::NativeTypes::AggregationObject& obj) + +inline void read(uint8_t const*& it, aztec3::utils::types::NativeTypes::AggregationObject& obj) { using serialize::read; @@ -13,9 +14,11 @@ inline void read(uint8_t const*& it, plonk::stdlib::types::NativeTypes::Aggregat read(it, obj.proof_witness_indices); read(it, obj.has_data); }; + } // namespace serialize namespace std { + inline std::ostream& operator<<(std::ostream& os, stdlib::recursion::native_recursion_output const& obj) { return os << "P0: " << obj.P0 << "\n" @@ -26,4 +29,5 @@ inline std::ostream& operator<<(std::ostream& os, stdlib::recursion::native_recu << obj.proof_witness_indices << "\n" << "has_data: " << obj.has_data << "\n"; }; + } // namespace std \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/abis/barretenberg/proof.hpp b/circuits/cpp/src/aztec3/circuits/abis/barretenberg/proof.hpp index ab5d7a018af..323a8f6c983 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/barretenberg/proof.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/barretenberg/proof.hpp @@ -1,11 +1,10 @@ #pragma once -#include -#include + +#include "aztec3/utils/types/native_types.hpp" namespace serialize { -using Proof = plonk::stdlib::types::NativeTypes::Proof; -inline void read(uint8_t const*& it, Proof& proof) +inline void read(uint8_t const*& it, aztec3::utils::types::NativeTypes::Proof& proof) { using serialize::read; @@ -14,7 +13,7 @@ inline void read(uint8_t const*& it, Proof& proof) } // namespace serialize namespace std { -inline std::ostream& operator<<(std::ostream& os, plonk::stdlib::types::NativeTypes::Proof const& data) +inline std::ostream& operator<<(std::ostream& os, aztec3::utils::types::NativeTypes::Proof const& data) { return os << data.proof_data; } diff --git a/circuits/cpp/src/aztec3/circuits/abis/verifier_reference_string.cpp b/circuits/cpp/src/aztec3/circuits/abis/barretenberg/verifier_reference_string.cpp similarity index 92% rename from circuits/cpp/src/aztec3/circuits/abis/verifier_reference_string.cpp rename to circuits/cpp/src/aztec3/circuits/abis/barretenberg/verifier_reference_string.cpp index 1c9a5e9a000..151a52153f6 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/verifier_reference_string.cpp +++ b/circuits/cpp/src/aztec3/circuits/abis/barretenberg/verifier_reference_string.cpp @@ -1,6 +1,6 @@ #include "verifier_reference_string.hpp" -namespace aztec3::circuits::abis { +namespace serialize { // TODO(AD): After Milestone 1, rewrite this with better injection mechanism. // Use a pointer to play nicely in case initialization does not occur (i.e. WASM) @@ -20,4 +20,4 @@ void set_global_verifier_reference_string(std::shared_ptr get_global_verifier_reference_string(); @@ -26,4 +26,4 @@ inline void write(std::vector& buf, std::shared_ptr(data); - aztec3::circuits::abis::set_global_verifier_reference_string(vrs); + serialize::set_global_verifier_reference_string(vrs); } /*** Serialization test helpers ***/ diff --git a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/accumulated_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/accumulated_data.hpp index 731968ae0f2..d295ead7ef7 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/accumulated_data.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/accumulated_data.hpp @@ -1,6 +1,7 @@ #pragma once #include "../optionally_revealed_data.hpp" #include "aztec3/circuits/abis/private_kernel/new_contract_data.hpp" +#include "aztec3/circuits/abis/barretenberg/aggregation_object.hpp" #include #include #include diff --git a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp index ea4aeb6190d..aa342438f07 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp @@ -1,6 +1,7 @@ #pragma once #include "aztec3/circuits/abis/private_kernel/public_inputs.hpp" -#include "aztec3/circuits/abis/verifier_reference_string.hpp" +#include "aztec3/circuits/abis/barretenberg/verifier_reference_string.hpp" +#include "aztec3/circuits/abis/barretenberg/proof.hpp" #include #include #include @@ -54,7 +55,7 @@ template inline void read(B& buf, verification_key& key) // Note this matches write() below verification_key_data data; read(buf, data); - key = verification_key{ std::move(data), get_global_verifier_reference_string() }; + key = verification_key{ std::move(data), serialize::get_global_verifier_reference_string() }; } template void read(uint8_t const*& it, PreviousKernelData& kernel_data) diff --git a/circuits/cpp/src/aztec3/utils/types/native_types.hpp b/circuits/cpp/src/aztec3/utils/types/native_types.hpp index 10df24f661f..f3cbcee6fda 100644 --- a/circuits/cpp/src/aztec3/utils/types/native_types.hpp +++ b/circuits/cpp/src/aztec3/utils/types/native_types.hpp @@ -13,14 +13,6 @@ #include #include -// #include -// #include -// #include -// #include -// #include -// #include -// #include - namespace aztec3::utils::types { // using plonk::stdlib::address; From 2369fc342286a6583fff955a500bd1be81a84eb0 Mon Sep 17 00:00:00 2001 From: ludamad Date: Mon, 17 Apr 2023 14:26:42 -0400 Subject: [PATCH 078/166] Cbind for `compute_function_tree_root` (#65) * cbind for compute_function_tree_root * fix func tree root test for wasm * compute_tree_root_native fix in bberg * use NT random_element for random fields instead of engine get_random_256() * template with compute_root_of_partial_left_tree logic which will be used by multiple tree root cbinds * unused include in constants, bad import in cbind * update bb/aztec3 --------- Co-authored-by: Suyash Bagad --- circuits/cpp/barretenberg | 2 +- .../cpp/src/aztec3/circuits/abis/c_bind.cpp | 46 +++++++++++++++- .../cpp/src/aztec3/circuits/abis/c_bind.h | 1 + .../src/aztec3/circuits/abis/c_bind.test.cpp | 54 +++++++++++++++---- circuits/cpp/src/aztec3/constants.hpp | 2 + 5 files changed, 93 insertions(+), 12 deletions(-) diff --git a/circuits/cpp/barretenberg b/circuits/cpp/barretenberg index 617b50e938c..85e07cace6d 160000 --- a/circuits/cpp/barretenberg +++ b/circuits/cpp/barretenberg @@ -1 +1 @@ -Subproject commit 617b50e938cde7b4883f4be7b15ee43cef3a4ec3 +Subproject commit 85e07cace6d98ab8e6e018646e1eaea39721148b diff --git a/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp b/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp index caa003497ab..01e80933a9b 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp +++ b/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp @@ -12,15 +12,59 @@ #include #include +#include #include #include namespace { -using aztec3::GeneratorIndex; + using aztec3::circuits::abis::FunctionLeafPreimage; using aztec3::circuits::abis::TxContext; using aztec3::circuits::abis::TxRequest; using NT = aztec3::utils::types::NativeTypes; + +// Cbind helper functions +/** + * @brief Compute an imperfect merkle tree's root from leaves. + * + * @details given a `uint8_t const*` buffer representing a merkle tree's leaves, + * compute the corresponding tree's root and return the serialized results + * in the `output` buffer. "Partial left tree" here means that the tree's leaves + * are filled strictly from left to right, but there may be empty leaves on the right + * end of the tree. + * + * @tparam TREE_HEIGHT height of the tree used to determine max leaves and used when computing root + * @tparam LeafPreimage the preimage type with a `.hash()` function to generate empty/zero-leaves + * @param leaves_buf a buffer of bytes representing the leaves of the tree, where each leaf is + * assumed to be a field and is interpreted using `NT::fr::serialize_from_buffer(leaf_ptr)` + * @param num_leaves the number of leaves in leaves_buf + * @returns a field (`NT::fr`) containing the computed merkle tree root + */ +template +NT::fr compute_root_of_partial_left_tree(uint8_t const* leaves_buf, uint8_t num_leaves) +{ + const size_t max_leaves = 2 << (TREE_HEIGHT - 1); + // cant exceed max leaves + ASSERT(num_leaves <= max_leaves); + + // initialize the vector of leaves to a complete-tree-sized vector of zero-leaves + NT::fr zero_leaf = LeafPreimage().hash(); // hash of empty/0 preimage + std::vector leaves(max_leaves, zero_leaf); + + // Iterate over the input buffer, extracting each leaf and serializing it from buffer to field + // Insert each leaf field into the vector + // If num_leaves < perfect tree, remaining leaves will be `zero_leaf` + for (size_t l = 0; l < num_leaves; l++) { + // each iteration skips to over some number of `fr`s to get to the // next leaf + uint8_t const* cur_leaf_ptr = leaves_buf + sizeof(NT::fr) * l; + NT::fr leaf = NT::fr::serialize_from_buffer(cur_leaf_ptr); + leaves[l] = leaf; + } + + // compute the root of this complete tree, return + return plonk::stdlib::merkle_tree::compute_tree_root_native(leaves); +} + } // namespace #define WASM_EXPORT __attribute__((visibility("default"))) diff --git a/circuits/cpp/src/aztec3/circuits/abis/c_bind.h b/circuits/cpp/src/aztec3/circuits/abis/c_bind.h index 80719bda410..0cfac00caae 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/c_bind.h +++ b/circuits/cpp/src/aztec3/circuits/abis/c_bind.h @@ -7,5 +7,6 @@ extern "C" { WASM_EXPORT void abis__hash_tx_request(uint8_t const* tx_request_buf, uint8_t* output); WASM_EXPORT void abis__compute_function_selector(char const* func_sig_cstr, uint8_t* output); WASM_EXPORT void abis__compute_function_leaf(uint8_t const* function_leaf_preimage_buf, uint8_t* output); +WASM_EXPORT void abis__compute_function_tree_root(uint8_t const* function_leaves_buf, uint8_t num_leaves, uint8_t* output); } \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp b/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp index 3904d3279ba..47967efd38e 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp @@ -3,6 +3,7 @@ #include "tx_request.hpp" #include "function_leaf_preimage.hpp" +#include #include #include @@ -38,18 +39,18 @@ TEST(abi_tests, hash_tx_request) // randomize function args for tx request std::array args; for (size_t i = 0; i < ARGS_LENGTH; i++) { - args[i] = fr(engine.get_random_uint256()); + args[i] = NT::fr::random_element(); } // Construct TxRequest with some randomized fields TxRequest tx_request = TxRequest{ - .from = engine.get_random_uint256(), - .to = engine.get_random_uint256(), + .from = NT::fr::random_element(), + .to = NT::fr::random_element(), .function_data = FunctionData(), .args = args, - .nonce = engine.get_random_uint256(), + .nonce = NT::fr::random_element(), .tx_context = TxContext(), - .chain_id = engine.get_random_uint256(), + .chain_id = NT::fr::random_element(), }; // Write the tx request to a buffer and @@ -57,7 +58,7 @@ TEST(abi_tests, hash_tx_request) write(buf, tx_request); // create an output buffer for cbind hash results - std::array output = { 0 }; + std::array output = { 0 }; // Make the c_bind call to hash the tx request abis__hash_tx_request(buf.data(), output.data()); @@ -103,21 +104,54 @@ TEST(abi_tests, compute_function_leaf) { // Construct FunctionLeafPreimage with some randomized fields FunctionLeafPreimage preimage = FunctionLeafPreimage{ - .function_selector = engine.get_random_uint256(), + .function_selector = NT::fr::random_element(), .is_private = static_cast(engine.get_random_uint8() & 1), - .vk_hash = engine.get_random_uint256(), - .acir_hash = engine.get_random_uint256(), + .vk_hash = NT::fr::random_element(), + .acir_hash = NT::fr::random_element(), }; // Write the leaf preimage to a buffer std::vector preimage_buf; write(preimage_buf, preimage); - std::array output = { 0 }; + std::array output = { 0 }; abis__compute_function_leaf(preimage_buf.data(), output.data()); NT::fr got_leaf = NT::fr::serialize_from_buffer(output.data()); EXPECT_EQ(got_leaf, preimage.hash()); } +TEST(abi_tests, compute_function_tree_root) +{ + NT::fr zero_leaf = FunctionLeafPreimage().hash(); // hash of empty/0 preimage + // these frs will be used to compute the root directly (without cbind) + // all empty slots will have the zero-leaf to ensure full tree + std::vector leaves_frs(FUNCTION_TREE_NUM_LEAVES, zero_leaf); + + // randomize number of non-zero leaves such that `0 < num_nonzero_leaves <= FUNCTION_TREE_NUM_LEAVES` + uint8_t num_nonzero_leaves = engine.get_random_uint8() % (FUNCTION_TREE_NUM_LEAVES + 1); + // create a vector whose vec.data() can be cast to a single mega-buffer containing all non-zero leaves + // initialize the vector with its size so that a leaf's data can be copied in (via `seralize_to_buffer`) + // (uint256_t here means nothing; it is just used because it is the right size (32 uint8_ts)) + std::vector leaves(num_nonzero_leaves); + + // generate some random leaves + // insert them into the vector of leaf fields (for direct tree root computation) + // insert their serialized form into the vector of 32-bytes chunks/uint256_ts + // (to be cast to a single mega uint8_t* buffer and passed to cbind) + for (size_t l = 0; l < num_nonzero_leaves; l++) { + NT::fr leaf = NT::fr::random_element(); + leaves_frs[l] = leaf; + NT::fr::serialize_to_buffer(leaf, reinterpret_cast(&leaves[l])); + } + + // call cbind and get output (root) + std::array output = { 0 }; + abis__compute_function_tree_root(reinterpret_cast(leaves.data()), num_nonzero_leaves, output.data()); + + // compare cbind results with direct computation + NT::fr got_root = NT::fr::serialize_from_buffer(output.data()); + EXPECT_EQ(got_root, plonk::stdlib::merkle_tree::compute_tree_root_native(leaves_frs)); +} + } // namespace aztec3::circuits::abis diff --git a/circuits/cpp/src/aztec3/constants.hpp b/circuits/cpp/src/aztec3/constants.hpp index f15aa05832e..956b4b98a26 100644 --- a/circuits/cpp/src/aztec3/constants.hpp +++ b/circuits/cpp/src/aztec3/constants.hpp @@ -35,6 +35,8 @@ constexpr size_t PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT = 8; constexpr size_t CONTRACT_TREE_ROOTS_TREE_HEIGHT = 8; constexpr size_t FUNCTION_SELECTOR_NUM_BYTES = 31; // must be <= 31 +constexpr size_t FUNCTION_TREE_HEIGHT = 8; +constexpr size_t FUNCTION_TREE_NUM_LEAVES = 2 << (FUNCTION_TREE_HEIGHT - 1); // leaves = 2 ^ height // Enumerate the hash_indices which are used for pedersen hashing // Start from 1 to avoid the default generators. From f5cbd436f4469e7faa45b77f831e8b3e2a85feef Mon Sep 17 00:00:00 2001 From: ludamad Date: Mon, 17 Apr 2023 14:27:16 -0400 Subject: [PATCH 079/166] feat(ts): build wasm. bundle dependencies --- .../ts/.yalc/@aztec/eslint-config/index.js | 92 ++++++++ .../.yalc/@aztec/eslint-config/package.json | 22 ++ .../ts/.yalc/@aztec/eslint-config/yalc.sig | 1 + circuits/ts/.yalc/@aztec/log/.eslintrc.cjs | 6 + circuits/ts/.yalc/@aztec/log/.tsbuildinfo | 1 + circuits/ts/.yalc/@aztec/log/Dockerfile | 16 ++ circuits/ts/.yalc/@aztec/log/README.md | 1 + circuits/ts/.yalc/@aztec/log/dest/index.d.ts | 11 + .../ts/.yalc/@aztec/log/dest/index.d.ts.map | 1 + circuits/ts/.yalc/@aztec/log/dest/index.js | 9 + circuits/ts/.yalc/@aztec/log/package.json | 18 ++ circuits/ts/.yalc/@aztec/log/src/index.ts | 12 + .../ts/.yalc/@aztec/log/tsconfig.dest.json | 4 + circuits/ts/.yalc/@aztec/log/tsconfig.json | 9 + circuits/ts/.yalc/@aztec/log/yalc.sig | 1 + .../ts/.yalc/@aztec/wasm-worker/.eslintrc.cjs | 6 + .../ts/.yalc/@aztec/wasm-worker/.tsbuildinfo | 1 + .../ts/.yalc/@aztec/wasm-worker/Dockerfile | 14 ++ .../ts/.yalc/@aztec/wasm-worker/README.md | 10 + .../.yalc/@aztec/wasm-worker/dest/index.d.ts | 5 + .../@aztec/wasm-worker/dest/index.d.ts.map | 1 + .../ts/.yalc/@aztec/wasm-worker/dest/index.js | 5 + .../@aztec/wasm-worker/dest/memory_fifo.d.ts | 46 ++++ .../wasm-worker/dest/memory_fifo.d.ts.map | 1 + .../@aztec/wasm-worker/dest/memory_fifo.js | 101 ++++++++ .../dest/transport/browser/index.d.ts | 5 + .../dest/transport/browser/index.d.ts.map | 1 + .../dest/transport/browser/index.js | 5 + .../browser/message_port_socket.d.ts | 28 +++ .../browser/message_port_socket.d.ts.map | 1 + .../transport/browser/message_port_socket.js | 37 +++ .../browser/shared_worker_connector.d.ts | 19 ++ .../browser/shared_worker_connector.d.ts.map | 1 + .../browser/shared_worker_connector.js | 21 ++ .../browser/shared_worker_listener.d.ts | 38 +++ .../browser/shared_worker_listener.d.ts.map | 1 + .../browser/shared_worker_listener.js | 39 +++ .../transport/browser/worker_connector.d.ts | 18 ++ .../browser/worker_connector.d.ts.map | 1 + .../transport/browser/worker_connector.js | 22 ++ .../transport/browser/worker_listener.d.ts | 38 +++ .../browser/worker_listener.d.ts.map | 1 + .../dest/transport/browser/worker_listener.js | 39 +++ .../dispatch/create_dispatch_fn.d.ts | 21 ++ .../dispatch/create_dispatch_fn.d.ts.map | 1 + .../transport/dispatch/create_dispatch_fn.js | 11 + .../dispatch/create_dispatch_proxy.d.ts | 50 ++++ .../dispatch/create_dispatch_proxy.d.ts.map | 1 + .../dispatch/create_dispatch_proxy.js | 38 +++ .../dest/transport/dispatch/messages.d.ts | 45 ++++ .../dest/transport/dispatch/messages.d.ts.map | 1 + .../dest/transport/dispatch/messages.js | 8 + .../wasm-worker/dest/transport/index.d.ts | 12 + .../wasm-worker/dest/transport/index.d.ts.map | 1 + .../wasm-worker/dest/transport/index.js | 12 + .../dest/transport/interface/connector.d.ts | 8 + .../transport/interface/connector.d.ts.map | 1 + .../dest/transport/interface/connector.js | 2 + .../dest/transport/interface/listener.d.ts | 13 + .../transport/interface/listener.d.ts.map | 1 + .../dest/transport/interface/listener.js | 2 + .../dest/transport/interface/socket.d.ts | 13 + .../dest/transport/interface/socket.d.ts.map | 1 + .../dest/transport/interface/socket.js | 2 + .../transport/interface/transferable.d.ts | 60 +++++ .../transport/interface/transferable.d.ts.map | 1 + .../dest/transport/interface/transferable.js | 35 +++ .../dest/transport/node/index.d.ts | 3 + .../dest/transport/node/index.d.ts.map | 1 + .../wasm-worker/dest/transport/node/index.js | 3 + .../dest/transport/node/node_connector.d.ts | 17 ++ .../transport/node/node_connector.d.ts.map | 1 + .../dest/transport/node/node_connector.js | 17 ++ .../transport/node/node_connector_socket.d.ts | 27 +++ .../node/node_connector_socket.d.ts.map | 1 + .../transport/node/node_connector_socket.js | 33 +++ .../dest/transport/node/node_listener.d.ts | 18 ++ .../transport/node/node_listener.d.ts.map | 1 + .../dest/transport/node/node_listener.js | 22 ++ .../transport/node/node_listener_socket.d.ts | 27 +++ .../node/node_listener_socket.d.ts.map | 1 + .../transport/node/node_listener_socket.js | 34 +++ .../dest/transport/transport_client.d.ts | 44 ++++ .../dest/transport/transport_client.d.ts.map | 1 + .../dest/transport/transport_client.js | 79 +++++++ .../dest/transport/transport_server.d.ts | 44 ++++ .../dest/transport/transport_server.d.ts.map | 1 + .../dest/transport/transport_server.js | 89 +++++++ .../dest/wasm/async_call_state.d.ts | 72 ++++++ .../dest/wasm/async_call_state.d.ts.map | 1 + .../wasm-worker/dest/wasm/async_call_state.js | 111 +++++++++ .../wasm-worker/dest/wasm/empty_wasi_sdk.d.ts | 24 ++ .../dest/wasm/empty_wasi_sdk.d.ts.map | 1 + .../wasm-worker/dest/wasm/empty_wasi_sdk.js | 61 +++++ .../@aztec/wasm-worker/dest/wasm/index.d.ts | 3 + .../wasm-worker/dest/wasm/index.d.ts.map | 1 + .../@aztec/wasm-worker/dest/wasm/index.js | 3 + .../wasm-worker/dest/wasm/wasm_module.d.ts | 96 ++++++++ .../dest/wasm/wasm_module.d.ts.map | 1 + .../wasm-worker/dest/wasm/wasm_module.js | 181 ++++++++++++++ .../dest/worker/browser/index.d.ts | 3 + .../dest/worker/browser/index.d.ts.map | 1 + .../wasm-worker/dest/worker/browser/index.js | 3 + .../dest/worker/browser/start_web_module.d.ts | 7 + .../worker/browser/start_web_module.d.ts.map | 1 + .../dest/worker/browser/start_web_module.js | 22 ++ .../dest/worker/browser/web_data_store.d.ts | 23 ++ .../worker/browser/web_data_store.d.ts.map | 1 + .../dest/worker/browser/web_data_store.js | 32 +++ .../dest/worker/browser/web_worker.d.ts | 6 + .../dest/worker/browser/web_worker.d.ts.map | 1 + .../dest/worker/browser/web_worker.js | 19 ++ .../wasm-worker/dest/worker/data_store.d.ts | 9 + .../dest/worker/data_store.d.ts.map | 1 + .../wasm-worker/dest/worker/data_store.js | 2 + .../@aztec/wasm-worker/dest/worker/index.d.ts | 2 + .../wasm-worker/dest/worker/index.d.ts.map | 1 + .../@aztec/wasm-worker/dest/worker/index.js | 2 + .../wasm-worker/dest/worker/node/index.d.ts | 3 + .../dest/worker/node/index.d.ts.map | 1 + .../wasm-worker/dest/worker/node/index.js | 3 + .../dest/worker/node/node_data_store.d.ts | 22 ++ .../dest/worker/node/node_data_store.d.ts.map | 1 + .../dest/worker/node/node_data_store.js | 31 +++ .../dest/worker/node/node_worker.d.ts | 6 + .../dest/worker/node/node_worker.d.ts.map | 1 + .../dest/worker/node/node_worker.js | 21 ++ .../dest/worker/node/start_node_module.d.ts | 7 + .../worker/node/start_node_module.d.ts.map | 1 + .../dest/worker/node/start_node_module.js | 26 ++ .../wasm-worker/dest/worker/wasm_worker.d.ts | 9 + .../dest/worker/wasm_worker.d.ts.map | 1 + .../wasm-worker/dest/worker/wasm_worker.js | 2 + .../wasm-worker/dest/worker/worker_pool.d.ts | 40 ++++ .../dest/worker/worker_pool.d.ts.map | 1 + .../wasm-worker/dest/worker/worker_pool.js | 62 +++++ .../ts/.yalc/@aztec/wasm-worker/package.json | 42 ++++ .../ts/.yalc/@aztec/wasm-worker/src/index.ts | 5 + .../@aztec/wasm-worker/src/memory_fifo.ts | 104 ++++++++ .../@aztec/wasm-worker/src/test/gcd.wasm | Bin 0 -> 76 bytes .../.yalc/@aztec/wasm-worker/src/test/gcd.wat | 27 +++ .../src/transport/browser/index.ts | 4 + .../transport/browser/message_port_socket.ts | 39 +++ .../browser/shared_worker_connector.ts | 21 ++ .../browser/shared_worker_listener.ts | 52 ++++ .../src/transport/browser/worker_connector.ts | 22 ++ .../src/transport/browser/worker_listener.ts | 52 ++++ .../transport/dispatch/create_dispatch_fn.ts | 24 ++ .../dispatch/create_dispatch_proxy.ts | 88 +++++++ .../src/transport/dispatch/messages.ts | 51 ++++ .../@aztec/wasm-worker/src/transport/index.ts | 11 + .../src/transport/interface/connector.ts | 8 + .../src/transport/interface/listener.ts | 14 ++ .../src/transport/interface/socket.ts | 12 + .../src/transport/interface/transferable.ts | 92 ++++++++ .../wasm-worker/src/transport/node/index.ts | 2 + .../src/transport/node/node_connector.ts | 18 ++ .../transport/node/node_connector_socket.ts | 36 +++ .../src/transport/node/node_listener.ts | 25 ++ .../transport/node/node_listener_socket.ts | 37 +++ .../src/transport/transport_client.ts | 106 +++++++++ .../src/transport/transport_server.ts | 96 ++++++++ .../wasm-worker/src/wasm/async_call_state.ts | 136 +++++++++++ .../wasm-worker/src/wasm/empty_wasi_sdk.ts | 61 +++++ .../@aztec/wasm-worker/src/wasm/index.ts | 2 + .../wasm-worker/src/wasm/wasm_module.test.ts | 27 +++ .../wasm-worker/src/wasm/wasm_module.ts | 203 ++++++++++++++++ .../wasm-worker/src/worker/browser/index.ts | 2 + .../src/worker/browser/start_web_module.ts | 23 ++ .../src/worker/browser/web_data_store.ts | 37 +++ .../src/worker/browser/web_worker.ts | 20 ++ .../wasm-worker/src/worker/data_store.ts | 7 + .../@aztec/wasm-worker/src/worker/index.ts | 1 + .../wasm-worker/src/worker/node/index.ts | 2 + .../src/worker/node/node_data_store.ts | 36 +++ .../src/worker/node/node_worker.ts | 22 ++ .../src/worker/node/start_node_module.ts | 28 +++ .../wasm-worker/src/worker/wasm_worker.ts | 7 + .../wasm-worker/src/worker/worker_pool.ts | 73 ++++++ .../@aztec/wasm-worker/tsconfig.dest.json | 4 + .../ts/.yalc/@aztec/wasm-worker/tsconfig.json | 9 + circuits/ts/.yalc/@aztec/wasm-worker/yalc.sig | 1 + circuits/ts/.yalc/@aztec/wasm/.eslintrc.cjs | 6 + circuits/ts/.yalc/@aztec/wasm/.tsbuildinfo | 1 + circuits/ts/.yalc/@aztec/wasm/Dockerfile | 14 ++ circuits/ts/.yalc/@aztec/wasm/README.md | 6 + circuits/ts/.yalc/@aztec/wasm/dest/index.d.ts | 8 + .../ts/.yalc/@aztec/wasm/dest/index.d.ts.map | 1 + circuits/ts/.yalc/@aztec/wasm/dest/index.js | 8 + .../.yalc/@aztec/wasm/dest/memory_fifo.d.ts | 46 ++++ .../@aztec/wasm/dest/memory_fifo.d.ts.map | 1 + .../ts/.yalc/@aztec/wasm/dest/memory_fifo.js | 101 ++++++++ .../wasm/dest/transport/browser/index.d.ts | 5 + .../dest/transport/browser/index.d.ts.map | 1 + .../wasm/dest/transport/browser/index.js | 5 + .../browser/message_port_socket.d.ts | 28 +++ .../browser/message_port_socket.d.ts.map | 1 + .../transport/browser/message_port_socket.js | 37 +++ .../browser/shared_worker_connector.d.ts | 19 ++ .../browser/shared_worker_connector.d.ts.map | 1 + .../browser/shared_worker_connector.js | 21 ++ .../browser/shared_worker_listener.d.ts | 38 +++ .../browser/shared_worker_listener.d.ts.map | 1 + .../browser/shared_worker_listener.js | 39 +++ .../transport/browser/worker_connector.d.ts | 18 ++ .../browser/worker_connector.d.ts.map | 1 + .../transport/browser/worker_connector.js | 22 ++ .../transport/browser/worker_listener.d.ts | 38 +++ .../browser/worker_listener.d.ts.map | 1 + .../dest/transport/browser/worker_listener.js | 39 +++ .../dispatch/create_dispatch_fn.d.ts | 21 ++ .../dispatch/create_dispatch_fn.d.ts.map | 1 + .../transport/dispatch/create_dispatch_fn.js | 11 + .../dispatch/create_dispatch_proxy.d.ts | 50 ++++ .../dispatch/create_dispatch_proxy.d.ts.map | 1 + .../dispatch/create_dispatch_proxy.js | 38 +++ .../dest/transport/dispatch/messages.d.ts | 45 ++++ .../dest/transport/dispatch/messages.d.ts.map | 1 + .../wasm/dest/transport/dispatch/messages.js | 8 + .../@aztec/wasm/dest/transport/index.d.ts | 12 + .../@aztec/wasm/dest/transport/index.d.ts.map | 1 + .../.yalc/@aztec/wasm/dest/transport/index.js | 12 + .../dest/transport/interface/connector.d.ts | 8 + .../transport/interface/connector.d.ts.map | 1 + .../dest/transport/interface/connector.js | 2 + .../dest/transport/interface/listener.d.ts | 13 + .../transport/interface/listener.d.ts.map | 1 + .../wasm/dest/transport/interface/listener.js | 2 + .../wasm/dest/transport/interface/socket.d.ts | 13 + .../dest/transport/interface/socket.d.ts.map | 1 + .../wasm/dest/transport/interface/socket.js | 2 + .../transport/interface/transferable.d.ts | 60 +++++ .../transport/interface/transferable.d.ts.map | 1 + .../dest/transport/interface/transferable.js | 35 +++ .../wasm/dest/transport/node/index.d.ts | 3 + .../wasm/dest/transport/node/index.d.ts.map | 1 + .../@aztec/wasm/dest/transport/node/index.js | 3 + .../dest/transport/node/node_connector.d.ts | 17 ++ .../transport/node/node_connector.d.ts.map | 1 + .../dest/transport/node/node_connector.js | 17 ++ .../transport/node/node_connector_socket.d.ts | 27 +++ .../node/node_connector_socket.d.ts.map | 1 + .../transport/node/node_connector_socket.js | 33 +++ .../dest/transport/node/node_listener.d.ts | 18 ++ .../transport/node/node_listener.d.ts.map | 1 + .../wasm/dest/transport/node/node_listener.js | 22 ++ .../transport/node/node_listener_socket.d.ts | 27 +++ .../node/node_listener_socket.d.ts.map | 1 + .../transport/node/node_listener_socket.js | 34 +++ .../wasm/dest/transport/transport_client.d.ts | 44 ++++ .../dest/transport/transport_client.d.ts.map | 1 + .../wasm/dest/transport/transport_client.js | 79 +++++++ .../wasm/dest/transport/transport_server.d.ts | 44 ++++ .../dest/transport/transport_server.d.ts.map | 1 + .../wasm/dest/transport/transport_server.js | 89 +++++++ .../wasm/dest/wasm/async_call_state.d.ts | 72 ++++++ .../wasm/dest/wasm/async_call_state.d.ts.map | 1 + .../@aztec/wasm/dest/wasm/async_call_state.js | 111 +++++++++ .../@aztec/wasm/dest/wasm/empty_wasi_sdk.d.ts | 24 ++ .../wasm/dest/wasm/empty_wasi_sdk.d.ts.map | 1 + .../@aztec/wasm/dest/wasm/empty_wasi_sdk.js | 61 +++++ .../ts/.yalc/@aztec/wasm/dest/wasm/index.d.ts | 3 + .../@aztec/wasm/dest/wasm/index.d.ts.map | 1 + .../ts/.yalc/@aztec/wasm/dest/wasm/index.js | 3 + .../@aztec/wasm/dest/wasm/wasm_module.d.ts | 107 +++++++++ .../wasm/dest/wasm/wasm_module.d.ts.map | 1 + .../@aztec/wasm/dest/wasm/wasm_module.js | 202 ++++++++++++++++ .../wasm/dest/worker/browser/index.d.ts | 3 + .../wasm/dest/worker/browser/index.d.ts.map | 1 + .../@aztec/wasm/dest/worker/browser/index.js | 3 + .../dest/worker/browser/start_web_module.d.ts | 7 + .../worker/browser/start_web_module.d.ts.map | 1 + .../dest/worker/browser/start_web_module.js | 22 ++ .../dest/worker/browser/web_data_store.d.ts | 23 ++ .../worker/browser/web_data_store.d.ts.map | 1 + .../dest/worker/browser/web_data_store.js | 32 +++ .../wasm/dest/worker/browser/web_worker.d.ts | 10 + .../dest/worker/browser/web_worker.d.ts.map | 1 + .../wasm/dest/worker/browser/web_worker.js | 23 ++ .../@aztec/wasm/dest/worker/data_store.d.ts | 9 + .../wasm/dest/worker/data_store.d.ts.map | 1 + .../@aztec/wasm/dest/worker/data_store.js | 2 + .../.yalc/@aztec/wasm/dest/worker/index.d.ts | 3 + .../@aztec/wasm/dest/worker/index.d.ts.map | 1 + .../ts/.yalc/@aztec/wasm/dest/worker/index.js | 2 + .../@aztec/wasm/dest/worker/node/index.d.ts | 3 + .../wasm/dest/worker/node/index.d.ts.map | 1 + .../@aztec/wasm/dest/worker/node/index.js | 3 + .../dest/worker/node/node_data_store.d.ts | 22 ++ .../dest/worker/node/node_data_store.d.ts.map | 1 + .../wasm/dest/worker/node/node_data_store.js | 31 +++ .../wasm/dest/worker/node/node_worker.d.ts | 6 + .../dest/worker/node/node_worker.d.ts.map | 1 + .../wasm/dest/worker/node/node_worker.js | 21 ++ .../dest/worker/node/start_node_module.d.ts | 7 + .../worker/node/start_node_module.d.ts.map | 1 + .../dest/worker/node/start_node_module.js | 26 ++ .../@aztec/wasm/dest/worker/wasm_worker.d.ts | 9 + .../wasm/dest/worker/wasm_worker.d.ts.map | 1 + .../@aztec/wasm/dest/worker/wasm_worker.js | 2 + .../@aztec/wasm/dest/worker/worker_pool.d.ts | 40 ++++ .../wasm/dest/worker/worker_pool.d.ts.map | 1 + .../@aztec/wasm/dest/worker/worker_pool.js | 62 +++++ circuits/ts/.yalc/@aztec/wasm/package.json | 42 ++++ circuits/ts/.yalc/@aztec/wasm/src/index.ts | 7 + .../ts/.yalc/@aztec/wasm/src/memory_fifo.ts | 104 ++++++++ .../ts/.yalc/@aztec/wasm/src/test/gcd.wasm | Bin 0 -> 76 bytes .../ts/.yalc/@aztec/wasm/src/test/gcd.wat | 27 +++ .../wasm/src/transport/browser/index.ts | 4 + .../transport/browser/message_port_socket.ts | 39 +++ .../browser/shared_worker_connector.ts | 21 ++ .../browser/shared_worker_listener.ts | 52 ++++ .../src/transport/browser/worker_connector.ts | 22 ++ .../src/transport/browser/worker_listener.ts | 52 ++++ .../transport/dispatch/create_dispatch_fn.ts | 24 ++ .../dispatch/create_dispatch_proxy.ts | 88 +++++++ .../wasm/src/transport/dispatch/messages.ts | 51 ++++ .../.yalc/@aztec/wasm/src/transport/index.ts | 11 + .../wasm/src/transport/interface/connector.ts | 8 + .../wasm/src/transport/interface/listener.ts | 14 ++ .../wasm/src/transport/interface/socket.ts | 12 + .../src/transport/interface/transferable.ts | 92 ++++++++ .../@aztec/wasm/src/transport/node/index.ts | 2 + .../wasm/src/transport/node/node_connector.ts | 18 ++ .../transport/node/node_connector_socket.ts | 36 +++ .../wasm/src/transport/node/node_listener.ts | 25 ++ .../transport/node/node_listener_socket.ts | 37 +++ .../wasm/src/transport/transport_client.ts | 106 +++++++++ .../wasm/src/transport/transport_server.ts | 96 ++++++++ .../@aztec/wasm/src/wasm/async_call_state.ts | 136 +++++++++++ .../@aztec/wasm/src/wasm/empty_wasi_sdk.ts | 61 +++++ .../ts/.yalc/@aztec/wasm/src/wasm/index.ts | 2 + .../@aztec/wasm/src/wasm/wasm_module.test.ts | 27 +++ .../.yalc/@aztec/wasm/src/wasm/wasm_module.ts | 223 ++++++++++++++++++ .../@aztec/wasm/src/worker/browser/index.ts | 2 + .../src/worker/browser/start_web_module.ts | 23 ++ .../wasm/src/worker/browser/web_data_store.ts | 37 +++ .../wasm/src/worker/browser/web_worker.ts | 24 ++ .../@aztec/wasm/src/worker/data_store.ts | 7 + .../ts/.yalc/@aztec/wasm/src/worker/index.ts | 2 + .../@aztec/wasm/src/worker/node/index.ts | 2 + .../wasm/src/worker/node/node_data_store.ts | 36 +++ .../wasm/src/worker/node/node_worker.ts | 22 ++ .../wasm/src/worker/node/start_node_module.ts | 28 +++ .../@aztec/wasm/src/worker/wasm_worker.ts | 7 + .../@aztec/wasm/src/worker/worker_pool.ts | 73 ++++++ .../ts/.yalc/@aztec/wasm/tsconfig.dest.json | 4 + circuits/ts/.yalc/@aztec/wasm/tsconfig.json | 9 + circuits/ts/.yalc/@aztec/wasm/yalc.sig | 1 + 349 files changed, 8128 insertions(+) create mode 100644 circuits/ts/.yalc/@aztec/eslint-config/index.js create mode 100644 circuits/ts/.yalc/@aztec/eslint-config/package.json create mode 100644 circuits/ts/.yalc/@aztec/eslint-config/yalc.sig create mode 100644 circuits/ts/.yalc/@aztec/log/.eslintrc.cjs create mode 100644 circuits/ts/.yalc/@aztec/log/.tsbuildinfo create mode 100644 circuits/ts/.yalc/@aztec/log/Dockerfile create mode 100644 circuits/ts/.yalc/@aztec/log/README.md create mode 100644 circuits/ts/.yalc/@aztec/log/dest/index.d.ts create mode 100644 circuits/ts/.yalc/@aztec/log/dest/index.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/log/dest/index.js create mode 100644 circuits/ts/.yalc/@aztec/log/package.json create mode 100644 circuits/ts/.yalc/@aztec/log/src/index.ts create mode 100644 circuits/ts/.yalc/@aztec/log/tsconfig.dest.json create mode 100644 circuits/ts/.yalc/@aztec/log/tsconfig.json create mode 100644 circuits/ts/.yalc/@aztec/log/yalc.sig create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/.eslintrc.cjs create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/.tsbuildinfo create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/Dockerfile create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/README.md create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/index.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/index.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/index.js create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/memory_fifo.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/memory_fifo.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/memory_fifo.js create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/index.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/index.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/index.js create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/message_port_socket.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/message_port_socket.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/message_port_socket.js create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/shared_worker_connector.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/shared_worker_connector.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/shared_worker_connector.js create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/shared_worker_listener.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/shared_worker_listener.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/shared_worker_listener.js create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/worker_connector.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/worker_connector.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/worker_connector.js create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/worker_listener.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/worker_listener.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/worker_listener.js create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/create_dispatch_fn.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/create_dispatch_fn.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/create_dispatch_fn.js create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/create_dispatch_proxy.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/create_dispatch_proxy.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/create_dispatch_proxy.js create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/messages.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/messages.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/messages.js create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/index.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/index.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/index.js create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/connector.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/connector.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/connector.js create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/listener.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/listener.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/listener.js create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/socket.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/socket.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/socket.js create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/transferable.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/transferable.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/transferable.js create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/index.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/index.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/index.js create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_connector.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_connector.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_connector.js create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_connector_socket.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_connector_socket.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_connector_socket.js create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_listener.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_listener.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_listener.js create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_listener_socket.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_listener_socket.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_listener_socket.js create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/transport_client.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/transport_client.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/transport_client.js create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/transport_server.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/transport_server.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/transport_server.js create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/async_call_state.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/async_call_state.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/async_call_state.js create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/empty_wasi_sdk.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/empty_wasi_sdk.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/empty_wasi_sdk.js create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/index.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/index.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/index.js create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/wasm_module.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/wasm_module.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/wasm_module.js create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/index.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/index.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/index.js create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/start_web_module.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/start_web_module.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/start_web_module.js create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/web_data_store.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/web_data_store.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/web_data_store.js create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/web_worker.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/web_worker.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/web_worker.js create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/data_store.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/data_store.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/data_store.js create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/index.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/index.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/index.js create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/index.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/index.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/index.js create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/node_data_store.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/node_data_store.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/node_data_store.js create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/node_worker.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/node_worker.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/node_worker.js create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/start_node_module.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/start_node_module.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/start_node_module.js create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/wasm_worker.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/wasm_worker.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/wasm_worker.js create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/worker_pool.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/worker_pool.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/worker_pool.js create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/package.json create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/index.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/memory_fifo.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/test/gcd.wasm create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/test/gcd.wat create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/transport/browser/index.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/transport/browser/message_port_socket.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/transport/browser/shared_worker_connector.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/transport/browser/shared_worker_listener.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/transport/browser/worker_connector.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/transport/browser/worker_listener.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/transport/dispatch/create_dispatch_fn.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/transport/dispatch/create_dispatch_proxy.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/transport/dispatch/messages.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/transport/index.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/transport/interface/connector.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/transport/interface/listener.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/transport/interface/socket.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/transport/interface/transferable.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/transport/node/index.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/transport/node/node_connector.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/transport/node/node_connector_socket.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/transport/node/node_listener.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/transport/node/node_listener_socket.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/transport/transport_client.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/transport/transport_server.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/wasm/async_call_state.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/wasm/empty_wasi_sdk.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/wasm/index.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/wasm/wasm_module.test.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/wasm/wasm_module.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/worker/browser/index.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/worker/browser/start_web_module.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/worker/browser/web_data_store.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/worker/browser/web_worker.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/worker/data_store.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/worker/index.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/worker/node/index.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/worker/node/node_data_store.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/worker/node/node_worker.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/worker/node/start_node_module.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/worker/wasm_worker.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/worker/worker_pool.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/tsconfig.dest.json create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/tsconfig.json create mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/yalc.sig create mode 100644 circuits/ts/.yalc/@aztec/wasm/.eslintrc.cjs create mode 100644 circuits/ts/.yalc/@aztec/wasm/.tsbuildinfo create mode 100644 circuits/ts/.yalc/@aztec/wasm/Dockerfile create mode 100644 circuits/ts/.yalc/@aztec/wasm/README.md create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/index.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/index.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/index.js create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/memory_fifo.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/memory_fifo.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/memory_fifo.js create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/index.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/index.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/index.js create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/message_port_socket.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/message_port_socket.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/message_port_socket.js create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_connector.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_connector.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_connector.js create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_listener.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_listener.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_listener.js create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/worker_connector.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/worker_connector.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/worker_connector.js create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/worker_listener.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/worker_listener.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/worker_listener.js create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_fn.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_fn.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_fn.js create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_proxy.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_proxy.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_proxy.js create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/messages.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/messages.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/messages.js create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/index.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/index.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/index.js create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/connector.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/connector.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/connector.js create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/listener.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/listener.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/listener.js create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/socket.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/socket.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/socket.js create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/transferable.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/transferable.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/transferable.js create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/node/index.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/node/index.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/node/index.js create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_connector.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_connector.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_connector.js create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_connector_socket.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_connector_socket.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_connector_socket.js create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_listener.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_listener.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_listener.js create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_listener_socket.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_listener_socket.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_listener_socket.js create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/transport_client.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/transport_client.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/transport_client.js create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/transport_server.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/transport_server.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/transport_server.js create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/wasm/async_call_state.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/wasm/async_call_state.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/wasm/async_call_state.js create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/wasm/empty_wasi_sdk.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/wasm/empty_wasi_sdk.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/wasm/empty_wasi_sdk.js create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/wasm/index.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/wasm/index.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/wasm/index.js create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/wasm/wasm_module.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/wasm/wasm_module.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/wasm/wasm_module.js create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/index.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/index.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/index.js create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/start_web_module.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/start_web_module.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/start_web_module.js create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/web_data_store.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/web_data_store.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/web_data_store.js create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/web_worker.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/web_worker.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/web_worker.js create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/data_store.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/data_store.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/data_store.js create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/index.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/index.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/index.js create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/node/index.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/node/index.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/node/index.js create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/node/node_data_store.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/node/node_data_store.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/node/node_data_store.js create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/node/node_worker.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/node/node_worker.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/node/node_worker.js create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/node/start_node_module.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/node/start_node_module.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/node/start_node_module.js create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/wasm_worker.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/wasm_worker.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/wasm_worker.js create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/worker_pool.d.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/worker_pool.d.ts.map create mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/worker_pool.js create mode 100644 circuits/ts/.yalc/@aztec/wasm/package.json create mode 100644 circuits/ts/.yalc/@aztec/wasm/src/index.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/src/memory_fifo.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/src/test/gcd.wasm create mode 100644 circuits/ts/.yalc/@aztec/wasm/src/test/gcd.wat create mode 100644 circuits/ts/.yalc/@aztec/wasm/src/transport/browser/index.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/src/transport/browser/message_port_socket.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/src/transport/browser/shared_worker_connector.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/src/transport/browser/shared_worker_listener.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/src/transport/browser/worker_connector.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/src/transport/browser/worker_listener.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/src/transport/dispatch/create_dispatch_fn.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/src/transport/dispatch/create_dispatch_proxy.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/src/transport/dispatch/messages.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/src/transport/index.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/src/transport/interface/connector.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/src/transport/interface/listener.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/src/transport/interface/socket.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/src/transport/interface/transferable.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/src/transport/node/index.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/src/transport/node/node_connector.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/src/transport/node/node_connector_socket.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/src/transport/node/node_listener.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/src/transport/node/node_listener_socket.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/src/transport/transport_client.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/src/transport/transport_server.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/src/wasm/async_call_state.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/src/wasm/empty_wasi_sdk.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/src/wasm/index.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/src/wasm/wasm_module.test.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/src/wasm/wasm_module.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/src/worker/browser/index.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/src/worker/browser/start_web_module.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/src/worker/browser/web_data_store.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/src/worker/browser/web_worker.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/src/worker/data_store.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/src/worker/index.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/src/worker/node/index.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/src/worker/node/node_data_store.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/src/worker/node/node_worker.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/src/worker/node/start_node_module.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/src/worker/wasm_worker.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/src/worker/worker_pool.ts create mode 100644 circuits/ts/.yalc/@aztec/wasm/tsconfig.dest.json create mode 100644 circuits/ts/.yalc/@aztec/wasm/tsconfig.json create mode 100644 circuits/ts/.yalc/@aztec/wasm/yalc.sig diff --git a/circuits/ts/.yalc/@aztec/eslint-config/index.js b/circuits/ts/.yalc/@aztec/eslint-config/index.js new file mode 100644 index 00000000000..3e30099520f --- /dev/null +++ b/circuits/ts/.yalc/@aztec/eslint-config/index.js @@ -0,0 +1,92 @@ +const contexts = [ + 'TSMethodDefinition', + 'MethodDefinition', + // 'TSPropertyDefinition', + // 'PropertyDefinition', + 'TSPropertySignature', + 'PropertySignature', + 'TSInterfaceDeclaration', + 'InterfaceDeclaration', + 'TSTypeAliasDeclaration', + 'TypeAliasDeclaration', + 'TSTypeDeclaration', + 'TypeDeclaration', + 'TSEnumDeclaration', + 'EnumDeclaration', + 'TSClassDeclaration', + 'ClassDeclaration', + 'TSClassExpression', + 'ClassExpression', + 'TSFunctionExpression', + 'FunctionExpression', + 'TSInterfaceExpression', + 'InterfaceExpression', + 'TSEnumExpression', + 'EnumExpression', +]; + +module.exports = { + extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'], + root: true, + parser: '@typescript-eslint/parser', + plugins: ['@typescript-eslint', 'eslint-plugin-tsdoc', 'jsdoc'], + overrides: [ + { + files: ['*.ts', '*.tsx'], + parserOptions: { + project: ['./tsconfig.json'], + }, + }, + ], + env: { + node: true, + }, + rules: { + '@typescript-eslint/explicit-module-boundary-types': 'off', + '@typescript-eslint/no-non-null-assertion': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-empty-function': 'off', + '@typescript-eslint/await-thenable': 'error', + '@typescript-eslint/no-floating-promises': 2, + 'require-await': 2, + 'no-constant-condition': 'off', + camelcase: 2, + 'no-restricted-imports': [ + 'warn', + { + patterns: [ + { + group: ['client-dest'], + message: "Fix this absolute garbage import. It's your duty to solve it before it spreads.", + }, + { + group: ['dest'], + message: 'You should not be importing from a build directory. Did you accidentally do a relative import?', + }, + ], + }, + ], + 'tsdoc/syntax': 'warn', + 'jsdoc/require-jsdoc': [ + 'warn', + { + contexts, + checkConstructors: false, + checkGetters: true, + checkSetters: true, + }, + ], + 'jsdoc/require-description': ['warn', { contexts }], + 'jsdoc/require-description-complete-sentence': ['warn'], + 'jsdoc/require-hyphen-before-param-description': ['warn'], + 'jsdoc/require-param': ['warn', { contexts, checkDestructured: false }], + 'jsdoc/require-param-description': ['warn', { contexts }], + 'jsdoc/require-param-name': ['warn', { contexts }], + 'jsdoc/require-property': ['warn', { contexts }], + 'jsdoc/require-property-description': ['warn', { contexts }], + 'jsdoc/require-property-name': ['warn', { contexts }], + 'jsdoc/require-returns': ['warn', { contexts }], + 'jsdoc/require-returns-description': ['warn', { contexts }], + }, + ignorePatterns: ['node_modules', 'dest*', 'dist', '*.js', '.eslintrc.cjs'], +}; diff --git a/circuits/ts/.yalc/@aztec/eslint-config/package.json b/circuits/ts/.yalc/@aztec/eslint-config/package.json new file mode 100644 index 00000000000..336361c7ea4 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/eslint-config/package.json @@ -0,0 +1,22 @@ +{ + "name": "@aztec/eslint-config", + "version": "0.0.0", + "packageManager": "yarn@3.2.2", + "files": [ + "index.js" + ], + "scripts": { + "build": "echo \"Did nothing.\"" + }, + "dependencies": { + "@aztec/eslint-config": "link:../../../yarn-project/eslint-config", + "@aztec/wasm-worker": "link:../../../yarn-project/wasm-worker", + "@typescript-eslint/eslint-plugin": "^5.38.0", + "@typescript-eslint/parser": "^5.38.0", + "eslint": "^8.21.0", + "eslint-config-prettier": "^8.5.0", + "eslint-plugin-jsdoc": "^40.0.0", + "eslint-plugin-tsdoc": "^0.2.17" + }, + "yalcSig": "afe1f6648a5208f857a53f99fbc458af" +} diff --git a/circuits/ts/.yalc/@aztec/eslint-config/yalc.sig b/circuits/ts/.yalc/@aztec/eslint-config/yalc.sig new file mode 100644 index 00000000000..40838000ca5 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/eslint-config/yalc.sig @@ -0,0 +1 @@ +afe1f6648a5208f857a53f99fbc458af \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/log/.eslintrc.cjs b/circuits/ts/.yalc/@aztec/log/.eslintrc.cjs new file mode 100644 index 00000000000..9cf806b1500 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/log/.eslintrc.cjs @@ -0,0 +1,6 @@ +require('@rushstack/eslint-patch/modern-module-resolution'); + +module.exports = { + extends: ['@aztec/eslint-config'], + parserOptions: { tsconfigRootDir: __dirname }, +}; diff --git a/circuits/ts/.yalc/@aztec/log/.tsbuildinfo b/circuits/ts/.yalc/@aztec/log/.tsbuildinfo new file mode 100644 index 00000000000..adf6de4136f --- /dev/null +++ b/circuits/ts/.yalc/@aztec/log/.tsbuildinfo @@ -0,0 +1 @@ +{"program":{"fileNames":["../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es5.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2015.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2016.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2017.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2018.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2019.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2020.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2021.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2022.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.esnext.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.dom.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2015.core.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2015.collection.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2015.generator.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2015.promise.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2017.object.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2017.string.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2017.intl.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2018.intl.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2018.promise.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2019.array.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2019.object.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2019.string.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2019.intl.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2020.date.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2020.promise.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2020.string.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2020.intl.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2020.number.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2021.promise.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2021.string.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2021.weakref.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2021.intl.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2022.array.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2022.error.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2022.intl.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2022.object.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2022.sharedmemory.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2022.string.d.ts","../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.esnext.intl.d.ts","./src/index.ts"],"fileInfos":[{"version":"8730f4bf322026ff5229336391a18bcaa1f94d4f82416c8b2f3954e2ccaae2ba","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc47c4fa66b9b9890cf076304de2a9c5201e94b740cffdf09f87296d877d71f6","impliedFormat":1},{"version":"7a387c58583dfca701b6c85e0adaf43fb17d590fb16d5b2dc0a2fbd89f35c467","impliedFormat":1},{"version":"8a12173c586e95f4433e0c6dc446bc88346be73ffe9ca6eec7aa63c8f3dca7f9","impliedFormat":1},{"version":"5f4e733ced4e129482ae2186aae29fde948ab7182844c3a5a51dd346182c7b06","impliedFormat":1},{"version":"4b421cbfb3a38a27c279dec1e9112c3d1da296f77a1a85ddadf7e7a425d45d18","impliedFormat":1},{"version":"1fc5ab7a764205c68fa10d381b08417795fc73111d6dd16b5b1ed36badb743d9","impliedFormat":1},{"version":"746d62152361558ea6d6115cf0da4dd10ede041d14882ede3568bce5dc4b4f1f","impliedFormat":1},{"version":"d11a03592451da2d1065e09e61f4e2a9bf68f780f4f6623c18b57816a9679d17","impliedFormat":1},{"version":"aea179452def8a6152f98f63b191b84e7cbd69b0e248c91e61fb2e52328abe8c","impliedFormat":1},{"version":"3aafcb693fe5b5c3bd277bd4c3a617b53db474fe498fc5df067c5603b1eebde7","affectsGlobalScope":true,"impliedFormat":1},{"version":"adb996790133eb33b33aadb9c09f15c2c575e71fb57a62de8bf74dbf59ec7dfb","affectsGlobalScope":true,"impliedFormat":1},{"version":"8cc8c5a3bac513368b0157f3d8b31cfdcfe78b56d3724f30f80ed9715e404af8","affectsGlobalScope":true,"impliedFormat":1},{"version":"cdccba9a388c2ee3fd6ad4018c640a471a6c060e96f1232062223063b0a5ac6a","affectsGlobalScope":true,"impliedFormat":1},{"version":"c5c05907c02476e4bde6b7e76a79ffcd948aedd14b6a8f56e4674221b0417398","affectsGlobalScope":true,"impliedFormat":1},{"version":"5f406584aef28a331c36523df688ca3650288d14f39c5d2e555c95f0d2ff8f6f","affectsGlobalScope":true,"impliedFormat":1},{"version":"22f230e544b35349cfb3bd9110b6ef37b41c6d6c43c3314a31bd0d9652fcec72","affectsGlobalScope":true,"impliedFormat":1},{"version":"7ea0b55f6b315cf9ac2ad622b0a7813315bb6e97bf4bb3fbf8f8affbca7dc695","affectsGlobalScope":true,"impliedFormat":1},{"version":"3013574108c36fd3aaca79764002b3717da09725a36a6fc02eac386593110f93","affectsGlobalScope":true,"impliedFormat":1},{"version":"eb26de841c52236d8222f87e9e6a235332e0788af8c87a71e9e210314300410a","affectsGlobalScope":true,"impliedFormat":1},{"version":"3be5a1453daa63e031d266bf342f3943603873d890ab8b9ada95e22389389006","affectsGlobalScope":true,"impliedFormat":1},{"version":"17bb1fc99591b00515502d264fa55dc8370c45c5298f4a5c2083557dccba5a2a","affectsGlobalScope":true,"impliedFormat":1},{"version":"7ce9f0bde3307ca1f944119f6365f2d776d281a393b576a18a2f2893a2d75c98","affectsGlobalScope":true,"impliedFormat":1},{"version":"6a6b173e739a6a99629a8594bfb294cc7329bfb7b227f12e1f7c11bc163b8577","affectsGlobalScope":true,"impliedFormat":1},{"version":"81cac4cbc92c0c839c70f8ffb94eb61e2d32dc1c3cf6d95844ca099463cf37ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"b0124885ef82641903d232172577f2ceb5d3e60aed4da1153bab4221e1f6dd4e","affectsGlobalScope":true,"impliedFormat":1},{"version":"0eb85d6c590b0d577919a79e0084fa1744c1beba6fd0d4e951432fa1ede5510a","affectsGlobalScope":true,"impliedFormat":1},{"version":"da233fc1c8a377ba9e0bed690a73c290d843c2c3d23a7bd7ec5cd3d7d73ba1e0","affectsGlobalScope":true,"impliedFormat":1},{"version":"d154ea5bb7f7f9001ed9153e876b2d5b8f5c2bb9ec02b3ae0d239ec769f1f2ae","affectsGlobalScope":true,"impliedFormat":1},{"version":"bb2d3fb05a1d2ffbca947cc7cbc95d23e1d053d6595391bd325deb265a18d36c","affectsGlobalScope":true,"impliedFormat":1},{"version":"c80df75850fea5caa2afe43b9949338ce4e2de086f91713e9af1a06f973872b8","affectsGlobalScope":true,"impliedFormat":1},{"version":"9d57b2b5d15838ed094aa9ff1299eecef40b190722eb619bac4616657a05f951","affectsGlobalScope":true,"impliedFormat":1},{"version":"6c51b5dd26a2c31dbf37f00cfc32b2aa6a92e19c995aefb5b97a3a64f1ac99de","affectsGlobalScope":true,"impliedFormat":1},{"version":"6e7997ef61de3132e4d4b2250e75343f487903ddf5370e7ce33cf1b9db9a63ed","affectsGlobalScope":true,"impliedFormat":1},{"version":"2ad234885a4240522efccd77de6c7d99eecf9b4de0914adb9a35c0c22433f993","affectsGlobalScope":true,"impliedFormat":1},{"version":"5e5e095c4470c8bab227dbbc61374878ecead104c74ab9960d3adcccfee23205","affectsGlobalScope":true,"impliedFormat":1},{"version":"09aa50414b80c023553090e2f53827f007a301bc34b0495bfb2c3c08ab9ad1eb","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7f680a43f8cd12a6b6122c07c54ba40952b0c8aa140dcfcf32eb9e6cb028596","affectsGlobalScope":true,"impliedFormat":1},{"version":"3787b83e297de7c315d55d4a7c546ae28e5f6c0a361b7a1dcec1f1f50a54ef11","affectsGlobalScope":true,"impliedFormat":1},{"version":"e7e8e1d368290e9295ef18ca23f405cf40d5456fa9f20db6373a61ca45f75f40","affectsGlobalScope":true,"impliedFormat":1},{"version":"faf0221ae0465363c842ce6aa8a0cbda5d9296940a8e26c86e04cc4081eea21e","affectsGlobalScope":true,"impliedFormat":1},{"version":"06393d13ea207a1bfe08ec8d7be562549c5e2da8983f2ee074e00002629d1871","affectsGlobalScope":true,"impliedFormat":1},{"version":"2768ef564cfc0689a1b76106c421a2909bdff0acbe87da010785adab80efdd5c","affectsGlobalScope":true,"impliedFormat":1},{"version":"b248e32ca52e8f5571390a4142558ae4f203ae2f94d5bac38a3084d529ef4e58","affectsGlobalScope":true,"impliedFormat":1},{"version":"6c55633c733c8378db65ac3da7a767c3cf2cf3057f0565a9124a16a3a2019e87","affectsGlobalScope":true,"impliedFormat":1},{"version":"fb4416144c1bf0323ccbc9afb0ab289c07312214e8820ad17d709498c865a3fe","affectsGlobalScope":true,"impliedFormat":1},{"version":"5b0ca94ec819d68d33da516306c15297acec88efeb0ae9e2b39f71dbd9685ef7","affectsGlobalScope":true,"impliedFormat":1},{"version":"34c839eaaa6d78c8674ae2c37af2236dee6831b13db7b4ef4df3ec889a04d4f2","affectsGlobalScope":true,"impliedFormat":1},{"version":"34478567f8a80171f88f2f30808beb7da15eac0538ae91282dd33dce928d98ed","affectsGlobalScope":true,"impliedFormat":1},{"version":"ab7d58e6161a550ff92e5aff755dc37fe896245348332cd5f1e1203479fe0ed1","affectsGlobalScope":true,"impliedFormat":1},{"version":"6bda95ea27a59a276e46043b7065b55bd4b316c25e70e29b572958fa77565d43","affectsGlobalScope":true,"impliedFormat":1},{"version":"aedb8de1abb2ff1095c153854a6df7deae4a5709c37297f9d6e9948b6806fa66","affectsGlobalScope":true,"impliedFormat":1},{"version":"a4da0551fd39b90ca7ce5f68fb55d4dc0c1396d589b612e1902f68ee090aaada","affectsGlobalScope":true,"impliedFormat":1},{"version":"11ffe3c281f375fff9ffdde8bbec7669b4dd671905509079f866f2354a788064","affectsGlobalScope":true,"impliedFormat":1},{"version":"52d1bb7ab7a3306fd0375c8bff560feed26ed676a5b0457fa8027b563aecb9a4","affectsGlobalScope":true,"impliedFormat":1},{"version":"6db2dd7173ffce430408ed9f23786e40ed210d8de99931b77b52ab39e4c49fc1","signature":"c1b0d202c9f1b9a9271a7304a47a406d338df8f432a6ccd46169007cfd3f9fff","impliedFormat":99}],"options":{"allowSyntheticDefaultImports":true,"composite":true,"declaration":true,"declarationMap":true,"downlevelIteration":true,"esModuleInterop":true,"importHelpers":true,"inlineSourceMap":true,"module":199,"noUnusedLocals":true,"outDir":"./dest","rootDir":"./src","strict":true,"target":7,"tsBuildInfoFile":"./.tsbuildinfo"},"referencedMap":[],"exportedModulesMap":[],"semanticDiagnosticsPerFile":[11,13,12,2,14,15,16,17,18,19,20,21,3,4,25,22,23,24,26,27,28,5,29,30,31,32,6,36,33,34,35,37,7,38,43,44,39,40,41,42,8,48,45,46,47,49,9,50,51,52,53,54,1,10,55,56],"latestChangedDtsFile":"./dest/index.d.ts"},"version":"4.9.5"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/log/Dockerfile b/circuits/ts/.yalc/@aztec/log/Dockerfile new file mode 100644 index 00000000000..c4cb6732b03 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/log/Dockerfile @@ -0,0 +1,16 @@ +FROM 278380418400.dkr.ecr.eu-west-2.amazonaws.com/yarn-project-base AS builder +COPY aztec.js aztec.js +RUN cd aztec.js && yarn build + +COPY end-to-end end-to-end +WORKDIR /usr/src/yarn-project/end-to-end +RUN yarn build && yarn formatting + +# Prune dev dependencies. See comment in base image. +RUN yarn cache clean +RUN yarn workspaces focus --production > /dev/null + +FROM alpine:latest +COPY --from=builder /usr/src/yarn-project /usr/src/yarn-project +WORKDIR /usr/src/yarn-project/end-to-end +ENTRYPOINT ["yarn", "test"] \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/log/README.md b/circuits/ts/.yalc/@aztec/log/README.md new file mode 100644 index 00000000000..29465cb23be --- /dev/null +++ b/circuits/ts/.yalc/@aztec/log/README.md @@ -0,0 +1 @@ +# End to End diff --git a/circuits/ts/.yalc/@aztec/log/dest/index.d.ts b/circuits/ts/.yalc/@aztec/log/dest/index.d.ts new file mode 100644 index 00000000000..ec158175aa6 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/log/dest/index.d.ts @@ -0,0 +1,11 @@ +/** + * Type for a logger. + */ +export type DebugLogger = (...args: any[]) => void; +/** + * Creates a logger. + * TODO port aztec2 logger over. + * @param moduleName - Name of module for logging or filtering purposes. + */ +export declare function createDebugLogger(moduleName: string): DebugLogger; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/log/dest/index.d.ts.map b/circuits/ts/.yalc/@aztec/log/dest/index.d.ts.map new file mode 100644 index 00000000000..95d18c16e9d --- /dev/null +++ b/circuits/ts/.yalc/@aztec/log/dest/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;AACnD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,WAAW,CAEjE"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/log/dest/index.js b/circuits/ts/.yalc/@aztec/log/dest/index.js new file mode 100644 index 00000000000..7986ed755b4 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/log/dest/index.js @@ -0,0 +1,9 @@ +/** + * Creates a logger. + * TODO port aztec2 logger over. + * @param moduleName - Name of module for logging or filtering purposes. + */ +export function createDebugLogger(moduleName) { + return (...args) => console.log(moduleName, ...args); +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBSUE7Ozs7R0FJRztBQUNILE1BQU0sVUFBVSxpQkFBaUIsQ0FBQyxVQUFrQjtJQUNsRCxPQUFPLENBQUMsR0FBRyxJQUFXLEVBQUUsRUFBRSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsVUFBVSxFQUFFLEdBQUcsSUFBSSxDQUFDLENBQUM7QUFDOUQsQ0FBQyJ9 \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/log/package.json b/circuits/ts/.yalc/@aztec/log/package.json new file mode 100644 index 00000000000..e379fa270ac --- /dev/null +++ b/circuits/ts/.yalc/@aztec/log/package.json @@ -0,0 +1,18 @@ +{ + "name": "@aztec/log", + "version": "0.0.0", + "type": "module", + "exports": "./dest/index.js", + "typedoc": { + "entryPoint": "./src/index.ts", + "displayName": "log", + "tsconfig": "./tsconfig.dest.json" + }, + "scripts": { + "build": "yarn clean && yarn formatting && tsc -b tsconfig.dest.json", + "clean": "rm -rf ./dest .tsbuildinfo", + "formatting": "run -T prettier --check ./src && run -T eslint --max-warnings 0 ./src", + "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --no-cache --passWithNoTests" + }, + "yalcSig": "66820adbe0b16465eb2826f2bc079a5c" +} diff --git a/circuits/ts/.yalc/@aztec/log/src/index.ts b/circuits/ts/.yalc/@aztec/log/src/index.ts new file mode 100644 index 00000000000..47b59cb1178 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/log/src/index.ts @@ -0,0 +1,12 @@ +/** + * Type for a logger. + */ +export type DebugLogger = (...args: any[]) => void; +/** + * Creates a logger. + * TODO port aztec2 logger over. + * @param moduleName - Name of module for logging or filtering purposes. + */ +export function createDebugLogger(moduleName: string): DebugLogger { + return (...args: any[]) => console.log(moduleName, ...args); +} diff --git a/circuits/ts/.yalc/@aztec/log/tsconfig.dest.json b/circuits/ts/.yalc/@aztec/log/tsconfig.dest.json new file mode 100644 index 00000000000..965aaa1c433 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/log/tsconfig.dest.json @@ -0,0 +1,4 @@ +{ + "extends": ".", + "exclude": ["**/*.test.*", "**/fixtures/*"] +} diff --git a/circuits/ts/.yalc/@aztec/log/tsconfig.json b/circuits/ts/.yalc/@aztec/log/tsconfig.json new file mode 100644 index 00000000000..f67ddec9fd6 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/log/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "..", + "compilerOptions": { + "outDir": "dest", + "rootDir": "src", + "tsBuildInfoFile": ".tsbuildinfo" + }, + "include": ["src"] +} diff --git a/circuits/ts/.yalc/@aztec/log/yalc.sig b/circuits/ts/.yalc/@aztec/log/yalc.sig new file mode 100644 index 00000000000..e77ce2f031d --- /dev/null +++ b/circuits/ts/.yalc/@aztec/log/yalc.sig @@ -0,0 +1 @@ +66820adbe0b16465eb2826f2bc079a5c \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/.eslintrc.cjs b/circuits/ts/.yalc/@aztec/wasm-worker/.eslintrc.cjs new file mode 100644 index 00000000000..9cf806b1500 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/.eslintrc.cjs @@ -0,0 +1,6 @@ +require('@rushstack/eslint-patch/modern-module-resolution'); + +module.exports = { + extends: ['@aztec/eslint-config'], + parserOptions: { tsconfigRootDir: __dirname }, +}; diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/.tsbuildinfo b/circuits/ts/.yalc/@aztec/wasm-worker/.tsbuildinfo new file mode 100644 index 00000000000..f34f7afab13 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/.tsbuildinfo @@ -0,0 +1 @@ +{"program":{"fileNames":["../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es5.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2015.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2016.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2017.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2018.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2019.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2020.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2021.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2022.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.esnext.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.dom.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2015.core.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2015.collection.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2015.generator.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2015.iterable.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2015.promise.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2015.proxy.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2015.reflect.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2015.symbol.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2016.array.include.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2017.object.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2017.string.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2017.intl.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2018.intl.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2018.promise.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2018.regexp.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2019.array.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2019.object.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2019.string.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2019.symbol.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2019.intl.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2020.bigint.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2020.date.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2020.promise.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2020.string.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2020.intl.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2020.number.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2021.promise.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2021.string.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2021.weakref.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2021.intl.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2022.array.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2022.error.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2022.intl.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2022.object.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2022.sharedmemory.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.es2022.string.d.ts","../.yarn/cache/typescript-patch-72dc6f164f-ab417a2f39.zip/node_modules/typescript/lib/lib.esnext.intl.d.ts","../.yarn/cache/tslib-npm-2.5.0-bb364efebd-ae3ed5f9ce.zip/node_modules/tslib/tslib.d.ts","../log/dest/index.d.ts","./src/memory_fifo.ts","./src/wasm/empty_wasi_sdk.ts","./src/wasm/wasm_module.ts","./src/transport/dispatch/create_dispatch_fn.ts","./src/transport/dispatch/messages.ts","./src/transport/interface/socket.ts","./src/transport/interface/connector.ts","./src/transport/transport_client.ts","./src/transport/interface/transferable.ts","./src/transport/dispatch/create_dispatch_proxy.ts","./src/transport/interface/listener.ts","./src/transport/transport_server.ts","./src/transport/browser/message_port_socket.ts","./src/transport/browser/worker_connector.ts","./src/transport/browser/worker_listener.ts","./src/transport/browser/shared_worker_connector.ts","./src/transport/browser/shared_worker_listener.ts","./src/transport/browser/index.ts","./src/transport/node/node_connector_socket.ts","./src/transport/node/node_connector.ts","./src/transport/node/node_listener_socket.ts","./src/transport/node/node_listener.ts","./src/transport/node/index.ts","./src/transport/index.ts","./src/worker/wasm_worker.ts","./src/worker/browser/web_worker.ts","./src/worker/data_store.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/assert.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/assert/strict.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/globals.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/async_hooks.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/buffer.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/child_process.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/cluster.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/console.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/constants.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/crypto.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/dgram.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/diagnostics_channel.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/dns.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/dns/promises.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/domain.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/dom-events.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/events.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/fs.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/fs/promises.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/http.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/http2.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/https.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/inspector.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/module.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/net.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/os.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/path.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/perf_hooks.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/process.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/punycode.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/querystring.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/readline.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/readline/promises.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/repl.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/stream.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/stream/promises.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/stream/consumers.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/stream/web.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/string_decoder.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/test.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/timers.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/timers/promises.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/tls.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/trace_events.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/tty.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/url.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/util.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/v8.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/vm.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/wasi.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/worker_threads.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/zlib.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/globals.global.d.ts","../.yarn/cache/@types-node-npm-18.14.6-7d0665d471-2f88f482ca.zip/node_modules/@types/node/index.d.ts","../.yarn/cache/@types-abstract-leveldown-npm-7.2.1-d0cda6811c-20689e7d14.zip/node_modules/@types/abstract-leveldown/index.d.ts","../.yarn/cache/@types-level-errors-npm-3.0.0-58ecd77a87-ad93926634.zip/node_modules/@types/level-errors/index.d.ts","../.yarn/cache/@types-levelup-npm-5.1.2-d41edd2f8f-6740284488.zip/node_modules/@types/levelup/index.d.ts","../.yarn/cache/@types-memdown-npm-3.0.1-57d57d174a-08085fff44.zip/node_modules/@types/memdown/index.d.ts","./src/worker/browser/web_data_store.ts","./src/worker/browser/index.ts","./src/worker/node/node_worker.ts","../.yarn/cache/@types-leveldown-npm-4.0.3-d7b4f50594-0a476bd8d3.zip/node_modules/@types/leveldown/index.d.ts","./src/worker/node/node_data_store.ts","./src/worker/node/index.ts","./src/wasm/async_call_state.ts","./src/wasm/index.ts","./src/index.ts","./src/worker/worker_pool.ts","./src/worker/index.ts","./src/worker/browser/start_web_module.ts","./src/worker/node/start_node_module.ts","../.yarn/cache/@types-detect-node-npm-2.0.0-035f21ce7d-f0f5c8ec94.zip/node_modules/@types/detect-node/index.d.ts","../.yarn/cache/@jest-expect-utils-npm-29.5.0-69b6ba2629-c46fb677c8.zip/node_modules/@jest/expect-utils/build/index.d.ts","../.yarn/cache/chalk-npm-4.1.2-ba8b67ab80-fe75c9d5c7.zip/node_modules/chalk/index.d.ts","../.yarn/cache/@sinclair-typebox-npm-0.25.24-d04d0f45ef-10219c58f4.zip/node_modules/@sinclair/typebox/typebox.d.ts","../.yarn/cache/@jest-schemas-npm-29.4.3-7d963e8d97-ac754e245c.zip/node_modules/@jest/schemas/build/index.d.ts","../.yarn/cache/pretty-format-npm-29.5.0-4f1086147d-4065356b55.zip/node_modules/pretty-format/build/index.d.ts","../.yarn/cache/jest-diff-npm-29.5.0-5c9573ed73-dfd0f4a299.zip/node_modules/jest-diff/build/index.d.ts","../.yarn/cache/jest-matcher-utils-npm-29.5.0-f255c78df4-1d3e8c746e.zip/node_modules/jest-matcher-utils/build/index.d.ts","../.yarn/cache/expect-npm-29.5.0-395e2d6fda-58f70b3869.zip/node_modules/expect/build/index.d.ts","../.yarn/cache/@types-jest-npm-29.4.0-e28b79cadc-2376028236.zip/node_modules/@types/jest/index.d.ts"],"fileInfos":[{"version":"8730f4bf322026ff5229336391a18bcaa1f94d4f82416c8b2f3954e2ccaae2ba","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc47c4fa66b9b9890cf076304de2a9c5201e94b740cffdf09f87296d877d71f6","impliedFormat":1},{"version":"7a387c58583dfca701b6c85e0adaf43fb17d590fb16d5b2dc0a2fbd89f35c467","impliedFormat":1},{"version":"8a12173c586e95f4433e0c6dc446bc88346be73ffe9ca6eec7aa63c8f3dca7f9","impliedFormat":1},{"version":"5f4e733ced4e129482ae2186aae29fde948ab7182844c3a5a51dd346182c7b06","impliedFormat":1},{"version":"4b421cbfb3a38a27c279dec1e9112c3d1da296f77a1a85ddadf7e7a425d45d18","impliedFormat":1},{"version":"1fc5ab7a764205c68fa10d381b08417795fc73111d6dd16b5b1ed36badb743d9","impliedFormat":1},{"version":"746d62152361558ea6d6115cf0da4dd10ede041d14882ede3568bce5dc4b4f1f","impliedFormat":1},{"version":"d11a03592451da2d1065e09e61f4e2a9bf68f780f4f6623c18b57816a9679d17","impliedFormat":1},{"version":"aea179452def8a6152f98f63b191b84e7cbd69b0e248c91e61fb2e52328abe8c","impliedFormat":1},{"version":"3aafcb693fe5b5c3bd277bd4c3a617b53db474fe498fc5df067c5603b1eebde7","affectsGlobalScope":true,"impliedFormat":1},{"version":"adb996790133eb33b33aadb9c09f15c2c575e71fb57a62de8bf74dbf59ec7dfb","affectsGlobalScope":true,"impliedFormat":1},{"version":"8cc8c5a3bac513368b0157f3d8b31cfdcfe78b56d3724f30f80ed9715e404af8","affectsGlobalScope":true,"impliedFormat":1},{"version":"cdccba9a388c2ee3fd6ad4018c640a471a6c060e96f1232062223063b0a5ac6a","affectsGlobalScope":true,"impliedFormat":1},{"version":"c5c05907c02476e4bde6b7e76a79ffcd948aedd14b6a8f56e4674221b0417398","affectsGlobalScope":true,"impliedFormat":1},{"version":"5f406584aef28a331c36523df688ca3650288d14f39c5d2e555c95f0d2ff8f6f","affectsGlobalScope":true,"impliedFormat":1},{"version":"22f230e544b35349cfb3bd9110b6ef37b41c6d6c43c3314a31bd0d9652fcec72","affectsGlobalScope":true,"impliedFormat":1},{"version":"7ea0b55f6b315cf9ac2ad622b0a7813315bb6e97bf4bb3fbf8f8affbca7dc695","affectsGlobalScope":true,"impliedFormat":1},{"version":"3013574108c36fd3aaca79764002b3717da09725a36a6fc02eac386593110f93","affectsGlobalScope":true,"impliedFormat":1},{"version":"eb26de841c52236d8222f87e9e6a235332e0788af8c87a71e9e210314300410a","affectsGlobalScope":true,"impliedFormat":1},{"version":"3be5a1453daa63e031d266bf342f3943603873d890ab8b9ada95e22389389006","affectsGlobalScope":true,"impliedFormat":1},{"version":"17bb1fc99591b00515502d264fa55dc8370c45c5298f4a5c2083557dccba5a2a","affectsGlobalScope":true,"impliedFormat":1},{"version":"7ce9f0bde3307ca1f944119f6365f2d776d281a393b576a18a2f2893a2d75c98","affectsGlobalScope":true,"impliedFormat":1},{"version":"6a6b173e739a6a99629a8594bfb294cc7329bfb7b227f12e1f7c11bc163b8577","affectsGlobalScope":true,"impliedFormat":1},{"version":"81cac4cbc92c0c839c70f8ffb94eb61e2d32dc1c3cf6d95844ca099463cf37ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"b0124885ef82641903d232172577f2ceb5d3e60aed4da1153bab4221e1f6dd4e","affectsGlobalScope":true,"impliedFormat":1},{"version":"0eb85d6c590b0d577919a79e0084fa1744c1beba6fd0d4e951432fa1ede5510a","affectsGlobalScope":true,"impliedFormat":1},{"version":"da233fc1c8a377ba9e0bed690a73c290d843c2c3d23a7bd7ec5cd3d7d73ba1e0","affectsGlobalScope":true,"impliedFormat":1},{"version":"d154ea5bb7f7f9001ed9153e876b2d5b8f5c2bb9ec02b3ae0d239ec769f1f2ae","affectsGlobalScope":true,"impliedFormat":1},{"version":"bb2d3fb05a1d2ffbca947cc7cbc95d23e1d053d6595391bd325deb265a18d36c","affectsGlobalScope":true,"impliedFormat":1},{"version":"c80df75850fea5caa2afe43b9949338ce4e2de086f91713e9af1a06f973872b8","affectsGlobalScope":true,"impliedFormat":1},{"version":"9d57b2b5d15838ed094aa9ff1299eecef40b190722eb619bac4616657a05f951","affectsGlobalScope":true,"impliedFormat":1},{"version":"6c51b5dd26a2c31dbf37f00cfc32b2aa6a92e19c995aefb5b97a3a64f1ac99de","affectsGlobalScope":true,"impliedFormat":1},{"version":"6e7997ef61de3132e4d4b2250e75343f487903ddf5370e7ce33cf1b9db9a63ed","affectsGlobalScope":true,"impliedFormat":1},{"version":"2ad234885a4240522efccd77de6c7d99eecf9b4de0914adb9a35c0c22433f993","affectsGlobalScope":true,"impliedFormat":1},{"version":"5e5e095c4470c8bab227dbbc61374878ecead104c74ab9960d3adcccfee23205","affectsGlobalScope":true,"impliedFormat":1},{"version":"09aa50414b80c023553090e2f53827f007a301bc34b0495bfb2c3c08ab9ad1eb","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7f680a43f8cd12a6b6122c07c54ba40952b0c8aa140dcfcf32eb9e6cb028596","affectsGlobalScope":true,"impliedFormat":1},{"version":"3787b83e297de7c315d55d4a7c546ae28e5f6c0a361b7a1dcec1f1f50a54ef11","affectsGlobalScope":true,"impliedFormat":1},{"version":"e7e8e1d368290e9295ef18ca23f405cf40d5456fa9f20db6373a61ca45f75f40","affectsGlobalScope":true,"impliedFormat":1},{"version":"faf0221ae0465363c842ce6aa8a0cbda5d9296940a8e26c86e04cc4081eea21e","affectsGlobalScope":true,"impliedFormat":1},{"version":"06393d13ea207a1bfe08ec8d7be562549c5e2da8983f2ee074e00002629d1871","affectsGlobalScope":true,"impliedFormat":1},{"version":"2768ef564cfc0689a1b76106c421a2909bdff0acbe87da010785adab80efdd5c","affectsGlobalScope":true,"impliedFormat":1},{"version":"b248e32ca52e8f5571390a4142558ae4f203ae2f94d5bac38a3084d529ef4e58","affectsGlobalScope":true,"impliedFormat":1},{"version":"6c55633c733c8378db65ac3da7a767c3cf2cf3057f0565a9124a16a3a2019e87","affectsGlobalScope":true,"impliedFormat":1},{"version":"fb4416144c1bf0323ccbc9afb0ab289c07312214e8820ad17d709498c865a3fe","affectsGlobalScope":true,"impliedFormat":1},{"version":"5b0ca94ec819d68d33da516306c15297acec88efeb0ae9e2b39f71dbd9685ef7","affectsGlobalScope":true,"impliedFormat":1},{"version":"34c839eaaa6d78c8674ae2c37af2236dee6831b13db7b4ef4df3ec889a04d4f2","affectsGlobalScope":true,"impliedFormat":1},{"version":"34478567f8a80171f88f2f30808beb7da15eac0538ae91282dd33dce928d98ed","affectsGlobalScope":true,"impliedFormat":1},{"version":"ab7d58e6161a550ff92e5aff755dc37fe896245348332cd5f1e1203479fe0ed1","affectsGlobalScope":true,"impliedFormat":1},{"version":"6bda95ea27a59a276e46043b7065b55bd4b316c25e70e29b572958fa77565d43","affectsGlobalScope":true,"impliedFormat":1},{"version":"aedb8de1abb2ff1095c153854a6df7deae4a5709c37297f9d6e9948b6806fa66","affectsGlobalScope":true,"impliedFormat":1},{"version":"a4da0551fd39b90ca7ce5f68fb55d4dc0c1396d589b612e1902f68ee090aaada","affectsGlobalScope":true,"impliedFormat":1},{"version":"11ffe3c281f375fff9ffdde8bbec7669b4dd671905509079f866f2354a788064","affectsGlobalScope":true,"impliedFormat":1},{"version":"52d1bb7ab7a3306fd0375c8bff560feed26ed676a5b0457fa8027b563aecb9a4","affectsGlobalScope":true,"impliedFormat":1},{"version":"f1c9fe42b65437a61104e601eb298c5c859fb522b483f1bdb700eed67a16f980","impliedFormat":1},{"version":"39605640330a122a0bf7d90ecf13d9012991adb2fa4a63d04843c94394f0f96d","impliedFormat":99},{"version":"7501fd9b2fc1fb3bc6abe499573b81db98d2954dc25df9a421973c5faaab4941","signature":"51eeac533c6eb5567faa2e43ac43d9fe25bd39581165f2f11af315bcac8efa14","impliedFormat":99},{"version":"b9e4ef1e69e9cd5adb0433eb6695cac57e02d0b5661fdc8f180a1728804102e1","signature":"ad9ea8a35fadce7abfe86228c0ff466dd7fe45a0aa6634b696d426d2c40e3f58","impliedFormat":99},{"version":"ca1f3e7d02f1073f62f1db50101c84f7bbfbc4abe74da5f2edc961fe9045c7f5","signature":"aa0e9a9436f9e58e533e0e218ed9e1ebfa12aa72d5a684c295f034640db3b8f0","impliedFormat":99},{"version":"f7b2cc01d2477492f72e74e50997d4078a36d0c1ed9dcc18296c2741ae428de4","signature":"52ee7b65db088422f752fa8a03abd082b6e81ccd3555629a4d2996c75a3ea784","impliedFormat":99},{"version":"f841813d6e9df0f9e0180f69b4963964544886b9b59c5d75a0a4b3de45efdceb","signature":"a36a302ce150fc6aba361bf2c3f4c4f3ea6ad1a39c4a1b876df3191774974a41","impliedFormat":99},{"version":"c35f64730d5ddb935dba2b79506f5c8a851b2c40646637c7070a4033972bd73a","signature":"0700ea2ece0b6e7609f86bc93d1d4713fd3f53be3ed4d3384baddd9daff050aa","impliedFormat":99},{"version":"4017cfb925dd1318b932861fe1789154f6063bbbf4608bf47d2acc07e3887625","signature":"8b070b73bb6b42225b7c3b6625bda6664954cc3712229b18958a8943b340ae55","impliedFormat":99},{"version":"aa9efc0c0f844b992299237fc548c0d87a010e33d680ec3ef8dbfd1c7fdd4b39","signature":"5615bcac5653c419404afd7a69d3a2ea065d6d8d73d76f645dc72775da1bce2a","impliedFormat":99},{"version":"f72d2ef8589cbc9ef38bc0a1ce8e8226886673553f135c2ec7bab480a51a1b14","signature":"0949e43a56894d36a28c69ef7226bb234ea74de6bb8db9c88ccf270be3b15b52","impliedFormat":99},{"version":"12ff3a65e83059a171d45b077f870c9847c4ddffc7cb0afe9cb3d3086ec26ed9","signature":"96d6443ed4046f8418464504489b9f770f7a438b3bc7bf460fb86471d117e9a4","impliedFormat":99},{"version":"29488db8cc9b41928088c0a874a9740bee7c05b3aee6e02d8b1136aacbb3ea57","signature":"b4117081407f355734a73e4f2051edeafff14541bacaa61b2b5b74de3a6d9f91","impliedFormat":99},{"version":"cc898ec7bce7af4fb56cfc04a7bb2efd3d2b7d98ac92b74b2b4e67e7ddbf7cc2","signature":"617438c8ffeebd4b427114557e1a41f99cd439d9757e1daf742e1ce4e866e050","impliedFormat":99},{"version":"7f14dc4040d79c8027bba900d0009a387480c8fbcaef946540e7d55cb25d477d","signature":"02349a2b4e4df02eeb877449a91fa899932d9e2a7b8ef30b47cd5820af6ab06e","impliedFormat":99},{"version":"4cbe58c97ab6d95e9d3b88062a9a09fc9c4dc9173d416c2c03d3c60de633afc8","signature":"66d2b4311e142ded625c47020aba04457dc1827b2abe4a0bf5e4282b61927b41","impliedFormat":99},{"version":"4aa8cf2c03a4bef578adb195fa0048172418ddc37ef1a43521b74e659a901b3c","signature":"508df7438e5b78be306e1383ab15dbb7119fb2ca4cb13cd9cf26e0b2489afb65","impliedFormat":99},{"version":"6263b4a797ae57e4fa8f9f034db454d13b00e5f497f33d63ae48f391b3965bb2","signature":"ce5c319de9485f5bcdefb59099b3e4f23bf0f27fc8e3bbe7282f862a9f860b49","impliedFormat":99},{"version":"8ffaac172d85e0da751e89c9115923b322afd5db8b8971b7e39a5f449e0f2d72","signature":"847f3e5260297cd02349d4fdf0ade2a89e11767d04441dd7e909bd44cb7e359f","impliedFormat":99},{"version":"04f0e5540074077b5194e4e50f045b07ea1c0d4ba639f2a90c25d415be93d62a","impliedFormat":99},{"version":"05c0a6903b06e02a54a65557ce552a38890e1eae2d4924fdc63f5d8c7d48a51f","signature":"ddbb7587357abb10688237ca0e2115ff0b141bc5addf52063ba8e05c7904c183","impliedFormat":99},{"version":"8df9a1e93f38ef9e5a02ac6d69550714fa74c0aa2b2417d1e0c935270bbb2845","signature":"c23f869061db4adee9e58bfe744589b000cb97989e1c658315b86fc61aa7cb24","impliedFormat":99},{"version":"d7945a051dd621e39b53921bbf255a067fcdcdd1d2e57749dca4de8e66115251","signature":"4d806524986070b7c9f6019a46f045e083570cd6eaa6b7bb7da0d438e1ea9d9b","impliedFormat":99},{"version":"bc3158925d8f0417aea29d03f80f8bf7fc01a75f1d8c93239ee794b4b2a40fa7","signature":"0a3f05296d25399d19f2dbf65a8537022f4e8ec42258892a801664d02b66e169","impliedFormat":99},{"version":"c2a3209fd29ed0b0daa24d258b108f7b4e4ba2656a99e529ceedd4a044b2edb8","impliedFormat":99},{"version":"a0bd6bccba91b399e4e98bb50ef2064f2dd1e5566151911526368667fb27f151","impliedFormat":99},{"version":"1b38d11a73ef55b188c688ce14f14c1805409afc8052822a32fbaa5154af78fa","signature":"4e89973a43a5c0e304e3b4adacfd647525168d6128ed218841f085610b36123b","impliedFormat":99},{"version":"0e258abf89e69f6157a7736d28d59a5403e0c477fe34c45ef3d1752e500a7408","signature":"bccb8a70a6ea729f469f9a6b3da0e36ee1e64ae3ad7c58e80fb60dc8b6634e23","impliedFormat":99},{"version":"eb29076a307e2750601d2eaf733b7b9b17c69d0156d47a2ba14cebf1ed66b0ce","signature":"76b1d15c83a9fd9909fd81e32024727743ae506de24a1bebc60719ad93cce0db","impliedFormat":99},{"version":"7e771891adaa85b690266bc37bd6eb43bc57eecc4b54693ead36467e7369952a","impliedFormat":1},{"version":"a69c09dbea52352f479d3e7ac949fde3d17b195abe90b045d619f747b38d6d1a","impliedFormat":1},{"version":"ca72190df0eb9b09d4b600821c8c7b6c9747b75a1c700c4d57dc0bb72abc074c","affectsGlobalScope":true,"impliedFormat":1},{"version":"11e2d554398d2bd460e7d06b2fa5827a297c8acfbe00b4f894a224ac0862857f","impliedFormat":1},{"version":"fc811ced095f38ad4438bb94a8d665c63bf4943e58a71ada16627add5ad93226","affectsGlobalScope":true,"impliedFormat":1},{"version":"374ca798f244e464346f14301dc2a8b4b111af1a83b49fffef5906c338a1f922","impliedFormat":1},{"version":"5a94487653355b56018122d92392beb2e5f4a6c63ba5cef83bbe1c99775ef713","impliedFormat":1},{"version":"d5135ad93b33adcce80b18f8065087934cdc1730d63db58562edcf017e1aad9b","affectsGlobalScope":true,"impliedFormat":1},{"version":"82408ed3e959ddc60d3e9904481b5a8dc16469928257af22a3f7d1a3bc7fd8c4","impliedFormat":1},{"version":"5eb881ed2a0d5b17ea36df5cd4c4be500e460c412f270c3170e906bec65580ac","impliedFormat":1},{"version":"bb9c4ffa5e6290c6980b63c815cdd1625876dadb2efaf77edbe82984be93e55e","impliedFormat":1},{"version":"489532ff54b714f0e0939947a1c560e516d3ae93d51d639ab02e907a0e950114","impliedFormat":1},{"version":"f30bb836526d930a74593f7b0f5c1c46d10856415a8f69e5e2fc3db80371e362","impliedFormat":1},{"version":"14b5aa23c5d0ae1907bc696ac7b6915d88f7d85799cc0dc2dcf98fbce2c5a67c","impliedFormat":1},{"version":"5c439dafdc09abe4d6c260a96b822fa0ba5be7203c71a63ab1f1423cd9e838ea","impliedFormat":1},{"version":"6b526a5ec4a401ca7c26cfe6a48e641d8f30af76673bad3b06a1b4504594a960","affectsGlobalScope":true,"impliedFormat":1},{"version":"816ad2e607a96de5bcac7d437f843f5afd8957f1fa5eefa6bba8e4ed7ca8fd84","affectsGlobalScope":true,"impliedFormat":1},{"version":"cec36af22f514322f870e81d30675c78df82ae8bf4863f5fd4e4424c040c678d","impliedFormat":1},{"version":"d903fafe96674bc0b2ac38a5be4a8fc07b14c2548d1cdb165a80ea24c44c0c54","impliedFormat":1},{"version":"5eec82ac21f84d83586c59a16b9b8502d34505d1393393556682fe7e7fde9ef2","impliedFormat":1},{"version":"04eb6578a588d6a46f50299b55f30e3a04ef27d0c5a46c57d8fcc211cd530faa","impliedFormat":1},{"version":"8d3c583a07e0c37e876908c2d5da575019f689df8d9fa4c081d99119d53dba22","impliedFormat":1},{"version":"2c828a5405191d006115ab34e191b8474bc6c86ffdc401d1a9864b1b6e088a58","impliedFormat":1},{"version":"e630e5528e899219ae319e83bef54bf3bcb91b01d76861ecf881e8e614b167f0","affectsGlobalScope":true,"impliedFormat":1},{"version":"bcebb922784739bdb34c18ee51095d25a92b560c78ccd2eaacd6bd00f7443d83","impliedFormat":1},{"version":"7ee6ed878c4528215c82b664fe0cfe80e8b4da6c0d4cc80869367868774db8b1","impliedFormat":1},{"version":"b0973c3cbcdc59b37bf477731d468696ecaf442593ec51bab497a613a580fe30","impliedFormat":1},{"version":"4989e92ba5b69b182d2caaea6295af52b7dc73a4f7a2e336a676722884e7139d","affectsGlobalScope":true,"impliedFormat":1},{"version":"b3624aed92dab6da8484280d3cb3e2f4130ec3f4ef3f8201c95144ae9e898bb6","affectsGlobalScope":true,"impliedFormat":1},{"version":"5153a2fd150e46ce57bb3f8db1318d33f6ad3261ed70ceeff92281c0608c74a3","impliedFormat":1},{"version":"210d54cd652ec0fec8c8916e4af59bb341065576ecda039842f9ffb2e908507c","impliedFormat":1},{"version":"36b03690b628eab08703d63f04eaa89c5df202e5f1edf3989f13ad389cd2c091","impliedFormat":1},{"version":"0effadd232a20498b11308058e334d3339cc5bf8c4c858393e38d9d4c0013dcf","impliedFormat":1},{"version":"25846d43937c672bab7e8195f3d881f93495df712ee901860effc109918938cc","impliedFormat":1},{"version":"fd93cee2621ff42dabe57b7be402783fd1aa69ece755bcba1e0290547ae60513","impliedFormat":1},{"version":"1b952304137851e45bc009785de89ada562d9376177c97e37702e39e60c2f1ff","impliedFormat":1},{"version":"69ee23dd0d215b09907ad30d23f88b7790c93329d1faf31d7835552a10cf7cbf","impliedFormat":1},{"version":"44b8b584a338b190a59f4f6929d072431950c7bd92ec2694821c11bce180c8a5","impliedFormat":1},{"version":"23b89798789dffbd437c0c423f5d02d11f9736aea73d6abf16db4f812ff36eda","impliedFormat":1},{"version":"09326ae5f7e3d49be5cd9ea00eb814770e71870a438faa2efd8bdd9b4db21320","impliedFormat":1},{"version":"3c4ba1dd9b12ffa284b565063108f2f031d150ea15b8fafbdc17f5d2a07251f3","affectsGlobalScope":true,"impliedFormat":1},{"version":"e10177274a35a9d07c825615340b2fcde2f610f53f3fb40269fd196b4288dda6","impliedFormat":1},{"version":"c4577fb855ca259bdbf3ea663ca73988ce5f84251a92b4aef80a1f4122b6f98e","impliedFormat":1},{"version":"3c13ef48634e7b5012fcf7e8fce7496352c2d779a7201389ca96a2a81ee4314d","impliedFormat":1},{"version":"5d0a25ec910fa36595f85a67ac992d7a53dd4064a1ba6aea1c9f14ab73a023f2","impliedFormat":1},{"version":"f0900cd5d00fe1263ff41201fb8073dbeb984397e4af3b8002a5c207a30bdc33","affectsGlobalScope":true,"impliedFormat":1},{"version":"ff07a9a03c65732ccc59b3c65bc584173da093bd563a6565411c01f5703bd3cb","affectsGlobalScope":true,"impliedFormat":1},{"version":"06d7c42d256f0ce6afe1b2b6cfbc97ab391f29dadb00dd0ae8e8f23f5bc916c3","impliedFormat":1},{"version":"ec4bd1b200670fb567920db572d6701ed42a9641d09c4ff6869768c8f81b404c","impliedFormat":1},{"version":"e59a892d87e72733e2a9ca21611b9beb52977be2696c7ba4b216cbbb9a48f5aa","impliedFormat":1},{"version":"da26af7362f53d122283bc69fed862b9a9fe27e01bc6a69d1d682e0e5a4df3e6","affectsGlobalScope":true,"impliedFormat":1},{"version":"8a300fa9b698845a1f9c41ecbe2c5966634582a8e2020d51abcace9b55aa959e","impliedFormat":1},{"version":"ab9b9a36e5284fd8d3bf2f7d5fcbc60052f25f27e4d20954782099282c60d23e","affectsGlobalScope":true,"impliedFormat":1},{"version":"ed2a670a77a1b80653c5bde2d813b0ab2e92872cc9b2b611ce11050b95139be6","impliedFormat":1},{"version":"409b21f3d0c198cc4866b941cd9303809a13230e2b9b3c1508fe61348a8b43ed","impliedFormat":1},{"version":"49afdedca00d22b171678e3cf9c47b7e0c1846fd4905a01d68f0145eb90add94","impliedFormat":1},{"version":"7a1b0fbc4287cb7513c0a10d9b53f5acc32d3ced53b2d786711901d483c4dbb4","impliedFormat":1},{"version":"8408c66a83053c21d93e73c1f6773647ccdb60fb9468f99341e389f3bfa35ad7","impliedFormat":1},{"version":"51108a0b63dc5dd793d26c1b185df7cfa1d1bf1a6e4ad9ce6f9d7ca8eb65b4ed","signature":"8a0ab25856a3fcd2c10da218932bb157fcab3ae61294c3506200f28f5d19b9c1","impliedFormat":99},{"version":"bff5e7e514980487864d34f69b6eda6f93506aff6dd9ced75f9a172ded1a71b4","impliedFormat":99},{"version":"f87022015c1924d3d60ae66c192366518af8617f7243af5af17d46a1d4d09764","signature":"9e6e67d4df1a320ac0ec7e2b58e98b332c2b4a7b2d88e1fe7463634a81f219e0","impliedFormat":99},{"version":"2c425702763ca7d738b2f0080be64d366a0818106a73c2595ed3ea51967f18c8","impliedFormat":1},{"version":"91f4e4de96699e0a21d50885d00d1dce8695f78788e3bdf40d33a299896be442","signature":"955a24e28310e9b71695b601e309957702e2da09e67f5bc5359bfae4a603e9b6","impliedFormat":99},{"version":"ac030f3c41a1797c673137478c675da6542c0676341c85f68b93fcecaaeb4778","impliedFormat":99},{"version":"c0c2b6bb02ec7f862cb53fe5455c4333387396423b5d5e8dd2ce1a2ef294fc90","signature":"15b413ec98335b7ec0d6068d0b10ae7d4cf794b8c93cb923bed2364ff85d372c","impliedFormat":99},{"version":"1893a547b8fbe550e167f6e8c9ae7c93bda50a72121c83aac21902fd333c2274","impliedFormat":99},{"version":"83a9092010dcc4c16daad986e5b20441e44f8aec15d86061f00039aeba564c86","signature":"b5d85765816c375b5f0160a23102f5e110247067a66fd25efd4dfef8757692cd","impliedFormat":99},{"version":"afde802c7508bfa466977ea232329057a307f777c8499ee651b7abf65d65c503","signature":"de24ca8d9277f1e78c0a904ab762dca156aa55b6ae6fb2bb27c39c9193ca9b93","impliedFormat":99},{"version":"933b1427a2650bc13cd174ea7572fb114b2536fa14c5fc2e55c983bd632a525f","impliedFormat":99},{"version":"dc9806a1a14bc9f601a6e16f016ccb22b045e84d3d3ccaf49c4e05fb49b30fb7","signature":"c9b16149b0bcedd5843245a14a41729109ec43f7b9ca8dad7660d6247766c290","impliedFormat":99},{"version":"46a360e67861a830045b0a33cdb99708cb41fbe00a58def5c08716f1816701b0","signature":"e2818909ec58404f3a37a96893be135599bda8581f76ed311370fa4c4b3220a2","impliedFormat":99},{"version":"3896464bb7e25fceebbd9c8a0b443caaa9b68ec323f46191c36b84293c852a19","impliedFormat":1},{"version":"6c1e688f95fcaf53b1e41c0fdadf2c1cfc96fa924eaf7f9fdb60f96deb0a4986","impliedFormat":1},{"version":"0d14fa22c41fdc7277e6f71473b20ebc07f40f00e38875142335d5b63cdfc9d2","impliedFormat":1},{"version":"db25694be959314fd1e868d72e567746db1db9e2001fae545d12d2a8c1bba1b8","impliedFormat":1},{"version":"43883cf3635bb1846cbdc6c363787b76227677388c74f7313e3f0edb380840fa","impliedFormat":1},{"version":"2d47012580f859dae201d2eef898a416bdae719dffc087dfd06aefe3de2f9c8d","impliedFormat":1},{"version":"3e70a7e67c2cb16f8cd49097360c0309fe9d1e3210ff9222e9dac1f8df9d4fb6","impliedFormat":1},{"version":"ab68d2a3e3e8767c3fba8f80de099a1cfc18c0de79e42cb02ae66e22dfe14a66","impliedFormat":1},{"version":"2cec1a31729b9b01e9294c33fc9425d336eff067282809761ad2e74425d6d2a5","impliedFormat":1},{"version":"eb9e147dbb7289f09af3b161483c09a9175c3b222ed587f4a3c0112841e7d6ff","affectsGlobalScope":true,"impliedFormat":1}],"options":{"allowSyntheticDefaultImports":true,"composite":true,"declaration":true,"declarationMap":true,"downlevelIteration":true,"esModuleInterop":true,"importHelpers":true,"inlineSourceMap":true,"module":199,"noUnusedLocals":true,"outDir":"./dest","rootDir":"./src","strict":true,"target":7,"tsBuildInfoFile":"./.tsbuildinfo"},"fileIdsList":[[131],[131,159],[131,161,164],[131,138,139],[101,131,138,139,140],[131,139],[85,131],[88,131],[89,94,122,131],[90,101,102,109,119,130,131],[90,91,101,109,131],[92,131],[93,94,102,110,131],[94,119,127,131],[95,97,101,109,131],[96,131],[97,98,131],[101,131],[99,101,131],[101,102,103,119,130,131],[101,102,103,116,119,122,131],[131,135],[97,104,109,119,130,131],[101,102,104,105,109,119,127,130,131],[104,106,119,127,130,131],[85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137],[101,107,131],[108,130,131],[97,101,109,119,131],[110,131],[111,131],[88,112,131],[113,129,131,135],[114,131],[115,131],[101,116,117,131],[116,118,131,133],[89,101,119,120,121,122,131],[89,119,121,131],[119,120,131],[122,131],[123,131],[101,125,126,131],[125,126,131],[94,109,119,127,131],[128,131],[109,129,131],[89,104,115,130,131],[94,131],[119,131,132],[131,133],[131,134],[89,94,101,103,112,119,130,131,133,135],[119,131,136],[131,157,163],[131,161],[131,158,162],[131,160],[56,131,144,148,150],[56,131],[56,71,72,73,74,131],[56,63,131],[56,64,70,131],[56,68,70,101,131],[56,61,65,66,101,131],[56,61,62,63,64,65,66,67,68,69,75,80,131],[56,63,101,131],[56,77,79,131],[56,64,76,131,135],[56,63,131,135],[56,68,78,101,131,135],[56,57,62,63,64,101,131],[56,62,63,66,68,131],[56,60,131],[56,57,131],[56,60,131,149],[56,57,58,59,89,94,131],[56,83,131,143],[56,60,81,131],[56,84,131,141,142],[56,60,81,82,131],[56,131,152],[56,131,145,147],[56,84,131,141,142,146],[56,60,81,82,131,135],[56,60,81,131,135],[56,57,82,131],[144,148,150],[63],[64,70],[68,101],[61,65,66],[63,101],[64,76,135],[63,135],[64,101],[68],[60],[57],[57,89],[84],[82],[60,81]],"referencedMap":[[157,1],[160,2],[159,1],[139,1],[156,1],[165,3],[140,1],[146,4],[141,5],[142,6],[85,7],[86,7],[88,8],[89,9],[90,10],[91,11],[92,12],[93,13],[94,14],[95,15],[96,16],[97,17],[98,17],[100,18],[99,19],[101,18],[102,20],[103,21],[87,22],[137,1],[104,23],[105,24],[106,25],[138,26],[107,27],[108,28],[109,29],[110,30],[111,31],[112,32],[113,33],[114,34],[115,35],[116,36],[117,36],[118,37],[119,38],[121,39],[120,40],[122,41],[123,42],[124,1],[125,43],[126,44],[127,45],[128,46],[129,47],[130,48],[131,49],[132,50],[133,51],[134,52],[135,53],[136,54],[158,1],[164,55],[162,56],[163,57],[161,58],[56,1],[11,1],[13,1],[12,1],[2,1],[14,1],[15,1],[16,1],[17,1],[18,1],[19,1],[20,1],[21,1],[3,1],[4,1],[25,1],[22,1],[23,1],[24,1],[26,1],[27,1],[28,1],[5,1],[29,1],[30,1],[31,1],[32,1],[6,1],[36,1],[33,1],[34,1],[35,1],[37,1],[7,1],[38,1],[43,1],[44,1],[39,1],[40,1],[41,1],[42,1],[8,1],[48,1],[45,1],[46,1],[47,1],[49,1],[9,1],[50,1],[51,1],[52,1],[53,1],[54,1],[1,1],[10,1],[55,1],[57,1],[151,59],[58,60],[75,61],[70,62],[73,63],[74,64],[71,63],[72,64],[61,60],[67,65],[62,60],[81,66],[64,62],[68,67],[63,60],[66,60],[80,68],[77,69],[76,70],[79,71],[78,70],[65,72],[69,73],[149,74],[59,75],[150,76],[60,77],[144,78],[154,79],[143,80],[83,81],[84,60],[153,82],[148,83],[147,84],[145,85],[155,86],[82,79],[152,87]],"exportedModulesMap":[[157,1],[160,2],[159,1],[139,1],[156,1],[165,3],[140,1],[146,4],[141,5],[142,6],[85,7],[86,7],[88,8],[89,9],[90,10],[91,11],[92,12],[93,13],[94,14],[95,15],[96,16],[97,17],[98,17],[100,18],[99,19],[101,18],[102,20],[103,21],[87,22],[137,1],[104,23],[105,24],[106,25],[138,26],[107,27],[108,28],[109,29],[110,30],[111,31],[112,32],[113,33],[114,34],[115,35],[116,36],[117,36],[118,37],[119,38],[121,39],[120,40],[122,41],[123,42],[124,1],[125,43],[126,44],[127,45],[128,46],[129,47],[130,48],[131,49],[132,50],[133,51],[134,52],[135,53],[136,54],[158,1],[164,55],[162,56],[163,57],[161,58],[56,1],[11,1],[13,1],[12,1],[2,1],[14,1],[15,1],[16,1],[17,1],[18,1],[19,1],[20,1],[21,1],[3,1],[4,1],[25,1],[22,1],[23,1],[24,1],[26,1],[27,1],[28,1],[5,1],[29,1],[30,1],[31,1],[32,1],[6,1],[36,1],[33,1],[34,1],[35,1],[37,1],[7,1],[38,1],[43,1],[44,1],[39,1],[40,1],[41,1],[42,1],[8,1],[48,1],[45,1],[46,1],[47,1],[49,1],[9,1],[50,1],[51,1],[52,1],[53,1],[54,1],[1,1],[10,1],[55,1],[57,1],[151,88],[75,61],[70,89],[73,90],[74,91],[71,90],[72,91],[67,92],[81,66],[64,89],[68,93],[80,68],[77,94],[76,95],[79,91],[78,95],[65,96],[69,97],[149,98],[59,99],[150,76],[60,100],[144,78],[154,98],[143,101],[83,102],[153,82],[148,83],[147,101],[145,102],[155,98],[82,103],[152,102]],"semanticDiagnosticsPerFile":[157,160,159,139,156,165,140,146,141,142,85,86,88,89,90,91,92,93,94,95,96,97,98,100,99,101,102,103,87,137,104,105,106,138,107,108,109,110,111,112,113,114,115,116,117,118,119,121,120,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,158,164,162,163,161,56,11,13,12,2,14,15,16,17,18,19,20,21,3,4,25,22,23,24,26,27,28,5,29,30,31,32,6,36,33,34,35,37,7,38,43,44,39,40,41,42,8,48,45,46,47,49,9,50,51,52,53,54,1,10,55,57,151,58,75,70,73,74,71,72,61,67,62,81,64,68,63,66,80,77,76,79,78,65,69,149,59,150,60,144,154,143,83,84,153,148,147,145,155,82,152],"latestChangedDtsFile":"./dest/worker/node/start_node_module.d.ts"},"version":"4.9.5"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/Dockerfile b/circuits/ts/.yalc/@aztec/wasm-worker/Dockerfile new file mode 100644 index 00000000000..ebffe4d970b --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/Dockerfile @@ -0,0 +1,14 @@ +FROM 278380418400.dkr.ecr.eu-west-2.amazonaws.com/yarn-project-base AS builder + +COPY wasm-worker wasm-worker +WORKDIR /usr/src/yarn-project/wasm-worker +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 alpine:latest +COPY --from=builder /usr/src/yarn-project/wasm-worker /usr/src/yarn-project/wasm-worker +WORKDIR /usr/src/yarn-project/wasm-worker +ENTRYPOINT ["yarn"] \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/README.md b/circuits/ts/.yalc/@aztec/wasm-worker/README.md new file mode 100644 index 00000000000..7e8fbbb90ca --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/README.md @@ -0,0 +1,10 @@ +# wasm-worker + +Exposes functionality to create asynchronous workers that host webassembly. +The package is generic, but its tests require a barretenberg.wasm. +They assume that you have a file structure as follows: + +- aztec3-packages/yarn-project/wasm-worker +- barretenberg + clone of https://github.com/AztecProtocol/barretenberg + which has ./cpp/build-wasm/bin/barretenberg.wasm from running cpp/bootstrap.sh diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/index.d.ts b/circuits/ts/.yalc/@aztec/wasm-worker/dest/index.d.ts new file mode 100644 index 00000000000..677edb7b9d4 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/index.d.ts @@ -0,0 +1,5 @@ +export { WebDataStore } from './worker/browser/index.js'; +export { NodeDataStore } from './worker/node/index.js'; +export { WasmModule } from './wasm/index.js'; +export { AsyncCallState, AsyncFnState } from './wasm/index.js'; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/index.d.ts.map b/circuits/ts/.yalc/@aztec/wasm-worker/dest/index.d.ts.map new file mode 100644 index 00000000000..4d726409ec5 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEvD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/index.js b/circuits/ts/.yalc/@aztec/wasm-worker/dest/index.js new file mode 100644 index 00000000000..812f7c9e002 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/index.js @@ -0,0 +1,5 @@ +export { WebDataStore } from './worker/browser/index.js'; +export { NodeDataStore } from './worker/node/index.js'; +export { WasmModule } from './wasm/index.js'; +export { AsyncCallState } from './wasm/index.js'; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQ3pELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUV2RCxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDN0MsT0FBTyxFQUFFLGNBQWMsRUFBZ0IsTUFBTSxpQkFBaUIsQ0FBQyJ9 \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/memory_fifo.d.ts b/circuits/ts/.yalc/@aztec/wasm-worker/dest/memory_fifo.d.ts new file mode 100644 index 00000000000..de592d842b4 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/memory_fifo.d.ts @@ -0,0 +1,46 @@ +/** + * A simple fifo queue. It can grow unbounded. It can have multiple producers and consumers. + * Putting an item onto the queue always succeeds, unless either end() or cancel() has been called in which case + * the item being pushed is simply discarded. + */ +export declare class MemoryFifo { + private waiting; + private items; + private flushing; + /** + * Length of queue. + * @returns integer. + */ + length(): number; + /** + * Returns next item within the queue, or blocks until and item has been put into the queue. + * If given a timeout, the promise will reject if no item is received after `timeout` seconds. + * If the queue is flushing, `null` is returned. + * @param timeout - In seconds. + * @returns Promise of result. + */ + get(timeout?: number): Promise; + /** + * Put an item onto back of the queue. + * @param item - The item to enqueue. + */ + put(item: T): void; + /** + * Once ended, no further items are added to queue. Consumers will consume remaining items within the queue. + * The queue is not reusable after calling `end()`. + * Any consumers waiting for an item receive null. + */ + end(): void; + /** + * Once cancelled, all items are discarded from the queue, and no further items are added to the queue. + * The queue is not reusable after calling `cancel()`. + * Any consumers waiting for an item receive null. + */ + cancel(): void; + /** + * Helper method that can be used to continously consume and process items on the queue. + * @param handler - The item handler function. + */ + process(handler: (item: T) => Promise): Promise; +} +//# sourceMappingURL=memory_fifo.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/memory_fifo.d.ts.map b/circuits/ts/.yalc/@aztec/wasm-worker/dest/memory_fifo.d.ts.map new file mode 100644 index 00000000000..9bb1710ce16 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/memory_fifo.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"memory_fifo.d.ts","sourceRoot":"","sources":["../src/memory_fifo.ts"],"names":[],"mappings":"AACA;;;;GAIG;AACH,qBAAa,UAAU,CAAC,CAAC;IACvB,OAAO,CAAC,OAAO,CAAoC;IACnD,OAAO,CAAC,KAAK,CAAW;IACxB,OAAO,CAAC,QAAQ,CAAS;IAEzB;;;OAGG;IACI,MAAM;IAIb;;;;;;OAMG;IACI,GAAG,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAyB/C;;;OAGG;IACI,GAAG,CAAC,IAAI,EAAE,CAAC;IAUlB;;;;OAIG;IACI,GAAG;IAKV;;;;OAIG;IACI,MAAM;IAMb;;;OAGG;IACU,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC;CAazD"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/memory_fifo.js b/circuits/ts/.yalc/@aztec/wasm-worker/dest/memory_fifo.js new file mode 100644 index 00000000000..f742e3a773c --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/memory_fifo.js @@ -0,0 +1,101 @@ +// TODO should come from a dependency +/** + * A simple fifo queue. It can grow unbounded. It can have multiple producers and consumers. + * Putting an item onto the queue always succeeds, unless either end() or cancel() has been called in which case + * the item being pushed is simply discarded. + */ +export class MemoryFifo { + constructor() { + this.waiting = []; + this.items = []; + this.flushing = false; + } + /** + * Length of queue. + * @returns integer. + */ + length() { + return this.items.length; + } + /** + * Returns next item within the queue, or blocks until and item has been put into the queue. + * If given a timeout, the promise will reject if no item is received after `timeout` seconds. + * If the queue is flushing, `null` is returned. + * @param timeout - In seconds. + * @returns Promise of result. + */ + get(timeout) { + if (this.items.length) { + return Promise.resolve(this.items.shift()); + } + if (this.items.length === 0 && this.flushing) { + return Promise.resolve(null); + } + return new Promise((resolve, reject) => { + this.waiting.push(resolve); + if (timeout) { + setTimeout(() => { + const index = this.waiting.findIndex(r => r === resolve); + if (index > -1) { + this.waiting.splice(index, 1); + const err = new Error('Timeout getting item from queue.'); + reject(err); + } + }, timeout * 1000); + } + }); + } + /** + * Put an item onto back of the queue. + * @param item - The item to enqueue. + */ + put(item) { + if (this.flushing) { + return; + } + else if (this.waiting.length) { + this.waiting.shift()(item); + } + else { + this.items.push(item); + } + } + /** + * Once ended, no further items are added to queue. Consumers will consume remaining items within the queue. + * The queue is not reusable after calling `end()`. + * Any consumers waiting for an item receive null. + */ + end() { + this.flushing = true; + this.waiting.forEach(resolve => resolve(null)); + } + /** + * Once cancelled, all items are discarded from the queue, and no further items are added to the queue. + * The queue is not reusable after calling `cancel()`. + * Any consumers waiting for an item receive null. + */ + cancel() { + this.flushing = true; + this.items = []; + this.waiting.forEach(resolve => resolve(null)); + } + /** + * Helper method that can be used to continously consume and process items on the queue. + * @param handler - The item handler function. + */ + async process(handler) { + try { + while (true) { + const item = await this.get(); + if (item === null) { + break; + } + await handler(item); + } + } + catch (err) { + console.error('Queue handler exception:', err); + } + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVtb3J5X2ZpZm8uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvbWVtb3J5X2ZpZm8udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEscUNBQXFDO0FBQ3JDOzs7O0dBSUc7QUFDSCxNQUFNLE9BQU8sVUFBVTtJQUF2QjtRQUNVLFlBQU8sR0FBaUMsRUFBRSxDQUFDO1FBQzNDLFVBQUssR0FBUSxFQUFFLENBQUM7UUFDaEIsYUFBUSxHQUFHLEtBQUssQ0FBQztJQThGM0IsQ0FBQztJQTVGQzs7O09BR0c7SUFDSSxNQUFNO1FBQ1gsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQztJQUMzQixDQUFDO0lBRUQ7Ozs7OztPQU1HO0lBQ0ksR0FBRyxDQUFDLE9BQWdCO1FBQ3pCLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLEVBQUU7WUFDckIsT0FBTyxPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxFQUFHLENBQUMsQ0FBQztTQUM3QztRQUVELElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLEtBQUssQ0FBQyxJQUFJLElBQUksQ0FBQyxRQUFRLEVBQUU7WUFDNUMsT0FBTyxPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO1NBQzlCO1FBRUQsT0FBTyxJQUFJLE9BQU8sQ0FBVyxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsRUFBRTtZQUMvQyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUUzQixJQUFJLE9BQU8sRUFBRTtnQkFDWCxVQUFVLENBQUMsR0FBRyxFQUFFO29CQUNkLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxLQUFLLE9BQU8sQ0FBQyxDQUFDO29CQUN6RCxJQUFJLEtBQUssR0FBRyxDQUFDLENBQUMsRUFBRTt3QkFDZCxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUM7d0JBQzlCLE1BQU0sR0FBRyxHQUFHLElBQUksS0FBSyxDQUFDLGtDQUFrQyxDQUFDLENBQUM7d0JBQzFELE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQztxQkFDYjtnQkFDSCxDQUFDLEVBQUUsT0FBTyxHQUFHLElBQUksQ0FBQyxDQUFDO2FBQ3BCO1FBQ0gsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQ7OztPQUdHO0lBQ0ksR0FBRyxDQUFDLElBQU87UUFDaEIsSUFBSSxJQUFJLENBQUMsUUFBUSxFQUFFO1lBQ2pCLE9BQU87U0FDUjthQUFNLElBQUksSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLEVBQUU7WUFDOUIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztTQUM3QjthQUFNO1lBQ0wsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7U0FDdkI7SUFDSCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNJLEdBQUc7UUFDUixJQUFJLENBQUMsUUFBUSxHQUFHLElBQUksQ0FBQztRQUNyQixJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQ2pELENBQUM7SUFFRDs7OztPQUlHO0lBQ0ksTUFBTTtRQUNYLElBQUksQ0FBQyxRQUFRLEdBQUcsSUFBSSxDQUFDO1FBQ3JCLElBQUksQ0FBQyxLQUFLLEdBQUcsRUFBRSxDQUFDO1FBQ2hCLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDakQsQ0FBQztJQUVEOzs7T0FHRztJQUNJLEtBQUssQ0FBQyxPQUFPLENBQUMsT0FBbUM7UUFDdEQsSUFBSTtZQUNGLE9BQU8sSUFBSSxFQUFFO2dCQUNYLE1BQU0sSUFBSSxHQUFHLE1BQU0sSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO2dCQUM5QixJQUFJLElBQUksS0FBSyxJQUFJLEVBQUU7b0JBQ2pCLE1BQU07aUJBQ1A7Z0JBQ0QsTUFBTSxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7YUFDckI7U0FDRjtRQUFDLE9BQU8sR0FBRyxFQUFFO1lBQ1osT0FBTyxDQUFDLEtBQUssQ0FBQywwQkFBMEIsRUFBRSxHQUFHLENBQUMsQ0FBQztTQUNoRDtJQUNILENBQUM7Q0FDRiJ9 \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/index.d.ts b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/index.d.ts new file mode 100644 index 00000000000..9432a480ed8 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/index.d.ts @@ -0,0 +1,5 @@ +export * from './worker_connector.js'; +export * from './worker_listener.js'; +export * from './shared_worker_connector.js'; +export * from './shared_worker_listener.js'; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/index.d.ts.map b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/index.d.ts.map new file mode 100644 index 00000000000..381d5165ffc --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/transport/browser/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,6BAA6B,CAAC"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/index.js b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/index.js new file mode 100644 index 00000000000..d0103503cb4 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/index.js @@ -0,0 +1,5 @@ +export * from './worker_connector.js'; +export * from './worker_listener.js'; +export * from './shared_worker_connector.js'; +export * from './shared_worker_listener.js'; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvdHJhbnNwb3J0L2Jyb3dzZXIvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsY0FBYyx1QkFBdUIsQ0FBQztBQUN0QyxjQUFjLHNCQUFzQixDQUFDO0FBQ3JDLGNBQWMsOEJBQThCLENBQUM7QUFDN0MsY0FBYyw2QkFBNkIsQ0FBQyJ9 \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/message_port_socket.d.ts b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/message_port_socket.d.ts new file mode 100644 index 00000000000..65fcce26e3e --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/message_port_socket.d.ts @@ -0,0 +1,28 @@ +import { Socket } from '../interface/socket.js'; +/** + * An implementation of a TransportSocket using MessagePorts. + */ +export declare class MessagePortSocket implements Socket { + private port; + /** + * Create a MessagePortSocket. + * @param port - MessagePort object to wrap. + */ + constructor(port: MessagePort); + /** + * Send a message over our message port. + * @param msg - The message. + * @param transfer - Objects to transfer ownership of. + */ + send(msg: any, transfer?: Transferable[]): Promise; + /** + * Add a message handler. + * @param cb - The handler. + */ + registerHandler(cb: (msg: any) => any): void; + /** + * Close this message port. + */ + close(): void; +} +//# sourceMappingURL=message_port_socket.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/message_port_socket.d.ts.map b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/message_port_socket.d.ts.map new file mode 100644 index 00000000000..077d4623f51 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/message_port_socket.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"message_port_socket.d.ts","sourceRoot":"","sources":["../../../src/transport/browser/message_port_socket.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAEhD;;GAEG;AACH,qBAAa,iBAAkB,YAAW,MAAM;IAKlC,OAAO,CAAC,IAAI;IAJxB;;;OAGG;gBACiB,IAAI,EAAE,WAAW;IAErC;;;;OAIG;IACH,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,GAAE,YAAY,EAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAK5D;;;OAGG;IACH,eAAe,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,GAAG,GAAG,IAAI;IAI5C;;OAEG;IACH,KAAK;CAKN"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/message_port_socket.js b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/message_port_socket.js new file mode 100644 index 00000000000..03387a31f8c --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/message_port_socket.js @@ -0,0 +1,37 @@ +/** + * An implementation of a TransportSocket using MessagePorts. + */ +export class MessagePortSocket { + /** + * Create a MessagePortSocket. + * @param port - MessagePort object to wrap. + */ + constructor(port) { + this.port = port; + } + /** + * Send a message over our message port. + * @param msg - The message. + * @param transfer - Objects to transfer ownership of. + */ + send(msg, transfer = []) { + this.port.postMessage(msg, transfer); + return Promise.resolve(); + } + /** + * Add a message handler. + * @param cb - The handler. + */ + registerHandler(cb) { + this.port.onmessage = event => cb(event.data); + } + /** + * Close this message port. + */ + close() { + void this.send(undefined); + this.port.onmessage = null; + this.port.close(); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVzc2FnZV9wb3J0X3NvY2tldC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy90cmFuc3BvcnQvYnJvd3Nlci9tZXNzYWdlX3BvcnRfc29ja2V0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUVBOztHQUVHO0FBQ0gsTUFBTSxPQUFPLGlCQUFpQjtJQUM1Qjs7O09BR0c7SUFDSCxZQUFvQixJQUFpQjtRQUFqQixTQUFJLEdBQUosSUFBSSxDQUFhO0lBQUcsQ0FBQztJQUV6Qzs7OztPQUlHO0lBQ0gsSUFBSSxDQUFDLEdBQVEsRUFBRSxXQUEyQixFQUFFO1FBQzFDLElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLEdBQUcsRUFBRSxRQUFRLENBQUMsQ0FBQztRQUNyQyxPQUFPLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQztJQUMzQixDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsZUFBZSxDQUFDLEVBQXFCO1FBQ25DLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxHQUFHLEtBQUssQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUNoRCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxLQUFLO1FBQ0gsS0FBSyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQzFCLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksQ0FBQztRQUMzQixJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQ3BCLENBQUM7Q0FDRiJ9 \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/shared_worker_connector.d.ts b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/shared_worker_connector.d.ts new file mode 100644 index 00000000000..032f9df12b3 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/shared_worker_connector.d.ts @@ -0,0 +1,19 @@ +import { Connector } from '../interface/connector.js'; +import { MessagePortSocket } from './message_port_socket.js'; +/** + * Connector implementation which wraps a SharedWorker. + */ +export declare class SharedWorkerConnector implements Connector { + private worker; + /** + * Create a SharedWorkerConnector. + * @param worker - A shared worker. + */ + constructor(worker: SharedWorker); + /** + * Create a Socket implementation with our mesage port. + * @returns The socket. + */ + createSocket(): Promise; +} +//# sourceMappingURL=shared_worker_connector.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/shared_worker_connector.d.ts.map b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/shared_worker_connector.d.ts.map new file mode 100644 index 00000000000..b745dd62aed --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/shared_worker_connector.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"shared_worker_connector.d.ts","sourceRoot":"","sources":["../../../src/transport/browser/shared_worker_connector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D;;GAEG;AACH,qBAAa,qBAAsB,YAAW,SAAS;IAKzC,OAAO,CAAC,MAAM;IAJ1B;;;OAGG;gBACiB,MAAM,EAAE,YAAY;IAExC;;;OAGG;IACH,YAAY;CAGb"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/shared_worker_connector.js b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/shared_worker_connector.js new file mode 100644 index 00000000000..fa8778b40a9 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/shared_worker_connector.js @@ -0,0 +1,21 @@ +import { MessagePortSocket } from './message_port_socket.js'; +/** + * Connector implementation which wraps a SharedWorker. + */ +export class SharedWorkerConnector { + /** + * Create a SharedWorkerConnector. + * @param worker - A shared worker. + */ + constructor(worker) { + this.worker = worker; + } + /** + * Create a Socket implementation with our mesage port. + * @returns The socket. + */ + createSocket() { + return Promise.resolve(new MessagePortSocket(this.worker.port)); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2hhcmVkX3dvcmtlcl9jb25uZWN0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvdHJhbnNwb3J0L2Jyb3dzZXIvc2hhcmVkX3dvcmtlcl9jb25uZWN0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFFN0Q7O0dBRUc7QUFDSCxNQUFNLE9BQU8scUJBQXFCO0lBQ2hDOzs7T0FHRztJQUNILFlBQW9CLE1BQW9CO1FBQXBCLFdBQU0sR0FBTixNQUFNLENBQWM7SUFBRyxDQUFDO0lBRTVDOzs7T0FHRztJQUNILFlBQVk7UUFDVixPQUFPLE9BQU8sQ0FBQyxPQUFPLENBQUMsSUFBSSxpQkFBaUIsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDbEUsQ0FBQztDQUNGIn0= \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/shared_worker_listener.d.ts b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/shared_worker_listener.d.ts new file mode 100644 index 00000000000..e6e93d9b214 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/shared_worker_listener.d.ts @@ -0,0 +1,38 @@ +/// +import EventEmitter from 'events'; +import { Listener } from '../interface/listener.js'; +/** + * See https://developer.mozilla.org/en-US/docs/Web/API/SharedWorkerGlobalScope. + */ +declare interface SharedWorkerGlobalScope { + /** + * Fired on shared workers when a new client connects. + */ + onconnect: any; +} +/** + * Listens for connections to a shared worker. + */ +export declare class SharedWorkerListener extends EventEmitter implements Listener { + private worker; + /** + * + * @param worker + */ + constructor(worker: SharedWorkerGlobalScope); + /** + * + */ + open(): void; + /** + * + */ + close(): void; + /** + * + * @param event + */ + private handleMessageEvent; +} +export {}; +//# sourceMappingURL=shared_worker_listener.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/shared_worker_listener.d.ts.map b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/shared_worker_listener.d.ts.map new file mode 100644 index 00000000000..72ac8c251e3 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/shared_worker_listener.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"shared_worker_listener.d.ts","sourceRoot":"","sources":["../../../src/transport/browser/shared_worker_listener.ts"],"names":[],"mappings":";AAAA,OAAO,YAAY,MAAM,QAAQ,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAGpD;;GAEG;AACH,OAAO,WAAW,uBAAuB;IACvC;;OAEG;IACH,SAAS,EAAE,GAAG,CAAC;CAChB;AAED;;GAEG;AACH,qBAAa,oBAAqB,SAAQ,YAAa,YAAW,QAAQ;IAK5D,OAAO,CAAC,MAAM;IAJ1B;;;OAGG;gBACiB,MAAM,EAAE,uBAAuB;IAInD;;OAEG;IACH,IAAI;IAIJ;;OAEG;IACH,KAAK;IAIL;;;OAGG;IACH,OAAO,CAAC,kBAAkB,CAMxB;CACH"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/shared_worker_listener.js b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/shared_worker_listener.js new file mode 100644 index 00000000000..e0cec42374b --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/shared_worker_listener.js @@ -0,0 +1,39 @@ +import EventEmitter from 'events'; +import { MessagePortSocket } from './message_port_socket.js'; +/** + * Listens for connections to a shared worker. + */ +export class SharedWorkerListener extends EventEmitter { + /** + * + * @param worker + */ + constructor(worker) { + super(); + this.worker = worker; + /** + * + * @param event + */ + this.handleMessageEvent = (event) => { + const [port] = event.ports; + if (!port) { + return; + } + this.emit('new_socket', new MessagePortSocket(port)); + }; + } + /** + * + */ + open() { + this.worker.onconnect = this.handleMessageEvent; + } + /** + * + */ + close() { + this.worker.onconnect = () => { }; + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2hhcmVkX3dvcmtlcl9saXN0ZW5lci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy90cmFuc3BvcnQvYnJvd3Nlci9zaGFyZWRfd29ya2VyX2xpc3RlbmVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sWUFBWSxNQUFNLFFBQVEsQ0FBQztBQUVsQyxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQVk3RDs7R0FFRztBQUNILE1BQU0sT0FBTyxvQkFBcUIsU0FBUSxZQUFZO0lBQ3BEOzs7T0FHRztJQUNILFlBQW9CLE1BQStCO1FBQ2pELEtBQUssRUFBRSxDQUFDO1FBRFUsV0FBTSxHQUFOLE1BQU0sQ0FBeUI7UUFrQm5EOzs7V0FHRztRQUNLLHVCQUFrQixHQUFHLENBQUMsS0FBbUIsRUFBRSxFQUFFO1lBQ25ELE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxLQUFLLENBQUMsS0FBSyxDQUFDO1lBQzNCLElBQUksQ0FBQyxJQUFJLEVBQUU7Z0JBQ1QsT0FBTzthQUNSO1lBQ0QsSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLEVBQUUsSUFBSSxpQkFBaUIsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO1FBQ3ZELENBQUMsQ0FBQztJQTFCRixDQUFDO0lBRUQ7O09BRUc7SUFDSCxJQUFJO1FBQ0YsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLEdBQUcsSUFBSSxDQUFDLGtCQUFrQixDQUFDO0lBQ2xELENBQUM7SUFFRDs7T0FFRztJQUNILEtBQUs7UUFDSCxJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsR0FBRyxHQUFHLEVBQUUsR0FBRSxDQUFDLENBQUM7SUFDbkMsQ0FBQztDQWFGIn0= \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/worker_connector.d.ts b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/worker_connector.d.ts new file mode 100644 index 00000000000..a7eba90c1ac --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/worker_connector.d.ts @@ -0,0 +1,18 @@ +import { Connector } from '../interface/connector.js'; +import { MessagePortSocket } from './message_port_socket.js'; +/** + * + */ +export declare class WorkerConnector implements Connector { + private worker; + /** + * + * @param worker + */ + constructor(worker: Worker); + /** + * + */ + createSocket(): Promise; +} +//# sourceMappingURL=worker_connector.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/worker_connector.d.ts.map b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/worker_connector.d.ts.map new file mode 100644 index 00000000000..a0af81a8776 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/worker_connector.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"worker_connector.d.ts","sourceRoot":"","sources":["../../../src/transport/browser/worker_connector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D;;GAEG;AACH,qBAAa,eAAgB,YAAW,SAAS;IAKnC,OAAO,CAAC,MAAM;IAJ1B;;;OAGG;gBACiB,MAAM,EAAE,MAAM;IAElC;;OAEG;IACH,YAAY;CAKb"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/worker_connector.js b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/worker_connector.js new file mode 100644 index 00000000000..4faae6403cf --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/worker_connector.js @@ -0,0 +1,22 @@ +import { MessagePortSocket } from './message_port_socket.js'; +/** + * + */ +export class WorkerConnector { + /** + * + * @param worker + */ + constructor(worker) { + this.worker = worker; + } + /** + * + */ + createSocket() { + const channel = new MessageChannel(); + this.worker.postMessage('', [channel.port2]); + return Promise.resolve(new MessagePortSocket(channel.port1)); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid29ya2VyX2Nvbm5lY3Rvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy90cmFuc3BvcnQvYnJvd3Nlci93b3JrZXJfY29ubmVjdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBRTdEOztHQUVHO0FBQ0gsTUFBTSxPQUFPLGVBQWU7SUFDMUI7OztPQUdHO0lBQ0gsWUFBb0IsTUFBYztRQUFkLFdBQU0sR0FBTixNQUFNLENBQVE7SUFBRyxDQUFDO0lBRXRDOztPQUVHO0lBQ0gsWUFBWTtRQUNWLE1BQU0sT0FBTyxHQUFHLElBQUksY0FBYyxFQUFFLENBQUM7UUFDckMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxXQUFXLENBQUMsRUFBRSxFQUFFLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7UUFDN0MsT0FBTyxPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksaUJBQWlCLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7SUFDL0QsQ0FBQztDQUNGIn0= \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/worker_listener.d.ts b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/worker_listener.d.ts new file mode 100644 index 00000000000..135a82ed2c4 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/worker_listener.d.ts @@ -0,0 +1,38 @@ +/// +import EventEmitter from 'events'; +import { Listener } from '../interface/listener.js'; +/** + * + */ +declare interface DedicatedWorkerGlobalScope { + /** + * + */ + onmessage: any; +} +/** + * + */ +export declare class WorkerListener extends EventEmitter implements Listener { + private worker; + /** + * + * @param worker + */ + constructor(worker: DedicatedWorkerGlobalScope); + /** + * + */ + open(): void; + /** + * + */ + close(): void; + /** + * + * @param event + */ + private handleMessageEvent; +} +export {}; +//# sourceMappingURL=worker_listener.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/worker_listener.d.ts.map b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/worker_listener.d.ts.map new file mode 100644 index 00000000000..778536fc69b --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/worker_listener.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"worker_listener.d.ts","sourceRoot":"","sources":["../../../src/transport/browser/worker_listener.ts"],"names":[],"mappings":";AAAA,OAAO,YAAY,MAAM,QAAQ,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAGpD;;GAEG;AACH,OAAO,WAAW,0BAA0B;IAC1C;;OAEG;IACH,SAAS,EAAE,GAAG,CAAC;CAChB;AAED;;GAEG;AACH,qBAAa,cAAe,SAAQ,YAAa,YAAW,QAAQ;IAKtD,OAAO,CAAC,MAAM;IAJ1B;;;OAGG;gBACiB,MAAM,EAAE,0BAA0B;IAItD;;OAEG;IACH,IAAI;IAIJ;;OAEG;IACH,KAAK;IAIL;;;OAGG;IACH,OAAO,CAAC,kBAAkB,CAMxB;CACH"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/worker_listener.js b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/worker_listener.js new file mode 100644 index 00000000000..75430d08d97 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/worker_listener.js @@ -0,0 +1,39 @@ +import EventEmitter from 'events'; +import { MessagePortSocket } from './message_port_socket.js'; +/** + * + */ +export class WorkerListener extends EventEmitter { + /** + * + * @param worker + */ + constructor(worker) { + super(); + this.worker = worker; + /** + * + * @param event + */ + this.handleMessageEvent = (event) => { + const [port] = event.ports; + if (!port) { + return; + } + this.emit('new_socket', new MessagePortSocket(port)); + }; + } + /** + * + */ + open() { + this.worker.onmessage = this.handleMessageEvent; + } + /** + * + */ + close() { + this.worker.onmessage = () => { }; + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid29ya2VyX2xpc3RlbmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3RyYW5zcG9ydC9icm93c2VyL3dvcmtlcl9saXN0ZW5lci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLFlBQVksTUFBTSxRQUFRLENBQUM7QUFFbEMsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFZN0Q7O0dBRUc7QUFDSCxNQUFNLE9BQU8sY0FBZSxTQUFRLFlBQVk7SUFDOUM7OztPQUdHO0lBQ0gsWUFBb0IsTUFBa0M7UUFDcEQsS0FBSyxFQUFFLENBQUM7UUFEVSxXQUFNLEdBQU4sTUFBTSxDQUE0QjtRQWtCdEQ7OztXQUdHO1FBQ0ssdUJBQWtCLEdBQUcsQ0FBQyxLQUFtQixFQUFFLEVBQUU7WUFDbkQsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLEtBQUssQ0FBQyxLQUFLLENBQUM7WUFDM0IsSUFBSSxDQUFDLElBQUksRUFBRTtnQkFDVCxPQUFPO2FBQ1I7WUFDRCxJQUFJLENBQUMsSUFBSSxDQUFDLFlBQVksRUFBRSxJQUFJLGlCQUFpQixDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7UUFDdkQsQ0FBQyxDQUFDO0lBMUJGLENBQUM7SUFFRDs7T0FFRztJQUNILElBQUk7UUFDRixJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsR0FBRyxJQUFJLENBQUMsa0JBQWtCLENBQUM7SUFDbEQsQ0FBQztJQUVEOztPQUVHO0lBQ0gsS0FBSztRQUNILElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxHQUFHLEdBQUcsRUFBRSxHQUFFLENBQUMsQ0FBQztJQUNuQyxDQUFDO0NBYUYifQ== \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/create_dispatch_fn.d.ts b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/create_dispatch_fn.d.ts new file mode 100644 index 00000000000..fdb3921facf --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/create_dispatch_fn.d.ts @@ -0,0 +1,21 @@ +/** + * + */ +export interface DispatchMsg { + /** + * + */ + fn: string; + /** + * + */ + args: any[]; +} +/** + * + */ +export declare function createDispatchFn(targetFn: () => any, debug?: { + (...data: any[]): void; + (message?: any, ...optionalParams: any[]): void; +}): ({ fn, args }: DispatchMsg) => Promise; +//# sourceMappingURL=create_dispatch_fn.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/create_dispatch_fn.d.ts.map b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/create_dispatch_fn.d.ts.map new file mode 100644 index 00000000000..a8e465a9c16 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/create_dispatch_fn.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"create_dispatch_fn.d.ts","sourceRoot":"","sources":["../../../src/transport/dispatch/create_dispatch_fn.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;IACX;;OAEG;IACH,IAAI,EAAE,GAAG,EAAE,CAAC;CACb;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,EAAE,KAAK;;;CAAgB,kBAC7C,WAAW,kBAKxC"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/create_dispatch_fn.js b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/create_dispatch_fn.js new file mode 100644 index 00000000000..09b635703d4 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/create_dispatch_fn.js @@ -0,0 +1,11 @@ +/** + * + */ +export function createDispatchFn(targetFn, debug = console.error) { + return async ({ fn, args }) => { + const target = targetFn(); + debug(`dispatching to ${target}: ${fn}`, args); + return await target[fn](...args); + }; +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3JlYXRlX2Rpc3BhdGNoX2ZuLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3RyYW5zcG9ydC9kaXNwYXRjaC9jcmVhdGVfZGlzcGF0Y2hfZm4udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBY0E7O0dBRUc7QUFDSCxNQUFNLFVBQVUsZ0JBQWdCLENBQUMsUUFBbUIsRUFBRSxLQUFLLEdBQUcsT0FBTyxDQUFDLEtBQUs7SUFDekUsT0FBTyxLQUFLLEVBQUUsRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFlLEVBQUUsRUFBRTtRQUN6QyxNQUFNLE1BQU0sR0FBRyxRQUFRLEVBQUUsQ0FBQztRQUMxQixLQUFLLENBQUMsa0JBQWtCLE1BQU0sS0FBSyxFQUFFLEVBQUUsRUFBRSxJQUFJLENBQUMsQ0FBQztRQUMvQyxPQUFPLE1BQU0sTUFBTSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUM7SUFDbkMsQ0FBQyxDQUFDO0FBQ0osQ0FBQyJ9 \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/create_dispatch_proxy.d.ts b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/create_dispatch_proxy.d.ts new file mode 100644 index 00000000000..27edab62dc3 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/create_dispatch_proxy.d.ts @@ -0,0 +1,50 @@ +import { DispatchMsg } from './create_dispatch_fn.js'; +import { TransportClient } from '../transport_client.js'; +import { TransferDescriptor } from '../interface/transferable.js'; +type FilterOutAttributes = { + [Key in keyof Base]: Base[Key] extends (...args: any) => any ? Base[Key] : never; +}; +type PromisifyFunction any> = (...args: Parameters) => Promise>; +type Promisify any; +}> = { + [Key in keyof Base]: ReturnType extends Promise ? Base[Key] : PromisifyFunction; +}; +/** + * Unpack transfer types + */ +type TransferTypes = { + [Index in keyof Tuple]: Tuple[Index] | (Tuple[Index] extends Transferable ? TransferDescriptor : never); +}; +/** + * Annoying: https://github.com/microsoft/TypeScript/issues/29919 + * There's a bug that means we can't map over the tuple or function parameter types to make them transferrable, if + * we use the Parameters builtin, and then try to map. + * So instead we inline the Parameters builtin and apply the TransferTypes to the parameters within the inline. + * Once the above is fixed we could in theory just do: + * + * type MakeFunctionTransferrable any> = ( + * ...args: TransferTypes> + * ) => ReturnType;. + */ +type MakeFunctionTransferrable any> = (...args: TFunction extends (...args: infer P) => any ? TransferTypes

: never) => ReturnType; +type Transferrable any; +}> = { + [Key in keyof Base]: MakeFunctionTransferrable; +}; +export type Proxify = Promisify>>; +export declare function createDispatchProxyFromFn(class_: { + new (...args: any[]): T; +}, requestFn: (fn: string) => (...args: any[]) => Promise): Proxify; +/** + * Create a proxy object of our class T that uses transportClient + * @param class_ - Our class T. + * @param transportClient - The transport infrastructure. + * @returns A proxy over T. + */ +export declare function createDispatchProxy(class_: { + new (...args: any[]): T; +}, transportClient: TransportClient): Proxify; +export {}; +//# sourceMappingURL=create_dispatch_proxy.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/create_dispatch_proxy.d.ts.map b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/create_dispatch_proxy.d.ts.map new file mode 100644 index 00000000000..8e5e12339be --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/create_dispatch_proxy.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"create_dispatch_proxy.d.ts","sourceRoot":"","sources":["../../../src/transport/dispatch/create_dispatch_proxy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEzD,OAAO,EAAwB,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAExF,KAAK,mBAAmB,CAAC,IAAI,IAAI;KAC9B,GAAG,IAAI,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,KAAK,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK;CACjF,CAAC;AAEF,KAAK,iBAAiB,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,KAAK,GAAG,IAAI,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AAE7G,KAAK,SAAS,CAAC,IAAI,SAAS;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,EAAE,GAAG,KAAK,GAAG,CAAA;CAAE,IAAI;KACrE,GAAG,IAAI,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,SAAS,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,iBAAiB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;CAC3G,CAAC;AAEF;;GAEG;AACH,KAAK,aAAa,CAAC,KAAK,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,CAAC,IAAI;KAChD,KAAK,IAAI,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,YAAY,GAAG,kBAAkB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC;CACtH,CAAC;AAEF;;;;;;;;;;GAUG;AACH,KAAK,yBAAyB,CAAC,SAAS,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,KAAK,GAAG,IAAI,CACxE,GAAG,IAAI,EAAE,SAAS,SAAS,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,KAAK,GAAG,GAAG,aAAa,CAAC,CAAC,CAAC,GAAG,KAAK,KAC5E,UAAU,CAAC,SAAS,CAAC,CAAC;AAE3B,KAAK,aAAa,CAAC,IAAI,SAAS;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAA;CAAE,IAAI;KAC3E,GAAG,IAAI,MAAM,IAAI,GAAG,yBAAyB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;CAC1D,CAAC;AAEF,MAAM,MAAM,OAAO,CAAC,CAAC,IAAI,SAAS,CAAC,aAAa,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAE1E,wBAAgB,yBAAyB,CAAC,CAAC,EACzC,MAAM,EAAE;IAAE,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;CAAE,EACnC,SAAS,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,GAAG,CAAC,GAC1D,OAAO,CAAC,CAAC,CAAC,CASZ;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EACnC,MAAM,EAAE;IAAE,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;CAAE,EACnC,eAAe,EAAE,eAAe,CAAC,WAAW,CAAC,GAC5C,OAAO,CAAC,CAAC,CAAC,CAqBZ"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/create_dispatch_proxy.js b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/create_dispatch_proxy.js new file mode 100644 index 00000000000..49833dfc748 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/create_dispatch_proxy.js @@ -0,0 +1,38 @@ +import { EventEmitter } from 'events'; +import { isTransferDescriptor } from '../interface/transferable.js'; +export function createDispatchProxyFromFn(class_, requestFn) { + const proxy = class_.prototype instanceof EventEmitter ? new EventEmitter() : {}; + for (const fn of Object.getOwnPropertyNames(class_.prototype)) { + if (fn === 'constructor') { + continue; + } + proxy[fn] = requestFn(fn); + } + return proxy; +} +/** + * Create a proxy object of our class T that uses transportClient + * @param class_ - Our class T. + * @param transportClient - The transport infrastructure. + * @returns A proxy over T. + */ +export function createDispatchProxy(class_, transportClient) { + // Create a proxy of class_ that passes along methods over our transportClient + const proxy = createDispatchProxyFromFn(class_, (fn) => (...args) => { + // Pass our proxied function name and arguments over our transport client + const transfer = args.reduce((acc, a) => (isTransferDescriptor(a) ? [...acc, ...a.transferables] : acc), []); + args = args.map(a => (isTransferDescriptor(a) ? a.send : a)); + return transportClient.request({ fn, args }, transfer); + }); + if (proxy instanceof EventEmitter) { + // Handle proxied 'emit' calls if our proxy object is an EventEmitter + transportClient.on('event_msg', ({ fn, args }) => { + if (fn === 'emit') { + const [eventName, ...restArgs] = args; + proxy.emit(eventName, ...restArgs); + } + }); + } + return proxy; +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3JlYXRlX2Rpc3BhdGNoX3Byb3h5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3RyYW5zcG9ydC9kaXNwYXRjaC9jcmVhdGVfZGlzcGF0Y2hfcHJveHkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBRUEsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLFFBQVEsQ0FBQztBQUN0QyxPQUFPLEVBQUUsb0JBQW9CLEVBQXNCLE1BQU0sOEJBQThCLENBQUM7QUF3Q3hGLE1BQU0sVUFBVSx5QkFBeUIsQ0FDdkMsTUFBbUMsRUFDbkMsU0FBMkQ7SUFFM0QsTUFBTSxLQUFLLEdBQVEsTUFBTSxDQUFDLFNBQVMsWUFBWSxZQUFZLENBQUMsQ0FBQyxDQUFDLElBQUksWUFBWSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztJQUN0RixLQUFLLE1BQU0sRUFBRSxJQUFJLE1BQU0sQ0FBQyxtQkFBbUIsQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLEVBQUU7UUFDN0QsSUFBSSxFQUFFLEtBQUssYUFBYSxFQUFFO1lBQ3hCLFNBQVM7U0FDVjtRQUNELEtBQUssQ0FBQyxFQUFFLENBQUMsR0FBRyxTQUFTLENBQUMsRUFBRSxDQUFDLENBQUM7S0FDM0I7SUFDRCxPQUFPLEtBQUssQ0FBQztBQUNmLENBQUM7QUFFRDs7Ozs7R0FLRztBQUNILE1BQU0sVUFBVSxtQkFBbUIsQ0FDakMsTUFBbUMsRUFDbkMsZUFBNkM7SUFFN0MsOEVBQThFO0lBQzlFLE1BQU0sS0FBSyxHQUFHLHlCQUF5QixDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQVUsRUFBRSxFQUFFLENBQUMsQ0FBQyxHQUFHLElBQVcsRUFBRSxFQUFFO1FBQ2pGLHlFQUF5RTtRQUN6RSxNQUFNLFFBQVEsR0FBbUIsSUFBSSxDQUFDLE1BQU0sQ0FDMUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLG9CQUFvQixDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsR0FBRyxFQUFFLEdBQUcsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsRUFDMUUsRUFBb0IsQ0FDckIsQ0FBQztRQUNGLElBQUksR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUM3RCxPQUFPLGVBQWUsQ0FBQyxPQUFPLENBQUMsRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFFLEVBQUUsUUFBUSxDQUFDLENBQUM7SUFDekQsQ0FBQyxDQUFDLENBQUM7SUFDSCxJQUFJLEtBQUssWUFBWSxZQUFZLEVBQUU7UUFDakMscUVBQXFFO1FBQ3JFLGVBQWUsQ0FBQyxFQUFFLENBQUMsV0FBVyxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFFLEVBQUUsRUFBRTtZQUMvQyxJQUFJLEVBQUUsS0FBSyxNQUFNLEVBQUU7Z0JBQ2pCLE1BQU0sQ0FBQyxTQUFTLEVBQUUsR0FBRyxRQUFRLENBQUMsR0FBRyxJQUFJLENBQUM7Z0JBQ3RDLEtBQUssQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLEdBQUcsUUFBUSxDQUFDLENBQUM7YUFDcEM7UUFDSCxDQUFDLENBQUMsQ0FBQztLQUNKO0lBQ0QsT0FBTyxLQUFLLENBQUM7QUFDZixDQUFDIn0= \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/messages.d.ts b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/messages.d.ts new file mode 100644 index 00000000000..c8e36c087a4 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/messages.d.ts @@ -0,0 +1,45 @@ +/** + * Represents a transport bus request. + */ +export interface RequestMessage { + /** + * The message ID. + */ + msgId: number; + /** + * The data. + */ + payload: Payload; +} +/** + * Represents a transport bus response. + */ +export interface ResponseMessage { + /** + * The message ID. + */ + msgId: number; + /** + * The data. + */ + payload?: Payload; + /** + * The error, if any. + */ + error?: string; +} +/** + * A message stemming from an event. + */ +export interface EventMessage { + /** + * The event data. + */ + payload: Payload; +} +/** + * Is this an event message? + * @returns If the msgId was blank. + */ +export declare function isEventMessage(msg: ResponseMessage | EventMessage): msg is EventMessage; +//# sourceMappingURL=messages.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/messages.d.ts.map b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/messages.d.ts.map new file mode 100644 index 00000000000..115e820679b --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/messages.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../../src/transport/dispatch/messages.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,cAAc,CAAC,OAAO;IACrC;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe,CAAC,OAAO;IACtC;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY,CAAC,OAAO;IACnC;;OAEG;IACH,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,OAAO,EACpC,GAAG,EAAE,eAAe,CAAC,OAAO,CAAC,GAAG,YAAY,CAAC,OAAO,CAAC,GACpD,GAAG,IAAI,YAAY,CAAC,OAAO,CAAC,CAE9B"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/messages.js b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/messages.js new file mode 100644 index 00000000000..b5d76595237 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/messages.js @@ -0,0 +1,8 @@ +/** + * Is this an event message? + * @returns If the msgId was blank. + */ +export function isEventMessage(msg) { + return msg.msgId === undefined; +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVzc2FnZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvdHJhbnNwb3J0L2Rpc3BhdGNoL21lc3NhZ2VzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQTBDQTs7O0dBR0c7QUFDSCxNQUFNLFVBQVUsY0FBYyxDQUM1QixHQUFxRDtJQUVyRCxPQUFRLEdBQWdDLENBQUMsS0FBSyxLQUFLLFNBQVMsQ0FBQztBQUMvRCxDQUFDIn0= \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/index.d.ts b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/index.d.ts new file mode 100644 index 00000000000..0989a811a39 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/index.d.ts @@ -0,0 +1,12 @@ +export * from './dispatch/create_dispatch_fn.js'; +export * from './dispatch/create_dispatch_proxy.js'; +export * from './dispatch/messages.js'; +export * from './interface/connector.js'; +export * from './interface/listener.js'; +export * from './interface/socket.js'; +export * from './interface/transferable.js'; +export * from './transport_client.js'; +export * from './transport_server.js'; +export * from './browser/index.js'; +export * from './node/index.js'; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/index.d.ts.map b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/index.d.ts.map new file mode 100644 index 00000000000..d5bded64e1d --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/transport/index.ts"],"names":[],"mappings":"AAAA,cAAc,kCAAkC,CAAC;AACjD,cAAc,qCAAqC,CAAC;AACpD,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/index.js b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/index.js new file mode 100644 index 00000000000..70b1b56c44c --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/index.js @@ -0,0 +1,12 @@ +export * from './dispatch/create_dispatch_fn.js'; +export * from './dispatch/create_dispatch_proxy.js'; +export * from './dispatch/messages.js'; +export * from './interface/connector.js'; +export * from './interface/listener.js'; +export * from './interface/socket.js'; +export * from './interface/transferable.js'; +export * from './transport_client.js'; +export * from './transport_server.js'; +export * from './browser/index.js'; +export * from './node/index.js'; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdHJhbnNwb3J0L2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLGNBQWMsa0NBQWtDLENBQUM7QUFDakQsY0FBYyxxQ0FBcUMsQ0FBQztBQUNwRCxjQUFjLHdCQUF3QixDQUFDO0FBQ3ZDLGNBQWMsMEJBQTBCLENBQUM7QUFDekMsY0FBYyx5QkFBeUIsQ0FBQztBQUN4QyxjQUFjLHVCQUF1QixDQUFDO0FBQ3RDLGNBQWMsNkJBQTZCLENBQUM7QUFDNUMsY0FBYyx1QkFBdUIsQ0FBQztBQUN0QyxjQUFjLHVCQUF1QixDQUFDO0FBQ3RDLGNBQWMsb0JBQW9CLENBQUM7QUFDbkMsY0FBYyxpQkFBaUIsQ0FBQyJ9 \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/connector.d.ts b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/connector.d.ts new file mode 100644 index 00000000000..828e9aab7b2 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/connector.d.ts @@ -0,0 +1,8 @@ +import { Socket } from './socket.js'; +/** + * Opens a socket with corresponding TransportListener. + */ +export interface Connector { + createSocket(): Promise; +} +//# sourceMappingURL=connector.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/connector.d.ts.map b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/connector.d.ts.map new file mode 100644 index 00000000000..62006c17ceb --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/connector.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"connector.d.ts","sourceRoot":"","sources":["../../../src/transport/interface/connector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;CACjC"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/connector.js b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/connector.js new file mode 100644 index 00000000000..7d5ac106da9 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/connector.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29ubmVjdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3RyYW5zcG9ydC9pbnRlcmZhY2UvY29ubmVjdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiIifQ== \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/listener.d.ts b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/listener.d.ts new file mode 100644 index 00000000000..4d0baa43572 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/listener.d.ts @@ -0,0 +1,13 @@ +/// +import EventEmitter from 'events'; +import { Socket } from './socket.js'; +/** + * Once opened, an implementation of a TransportListener will emit `new_socket` events as new clients connect. + * Possible implementations could include MessageChannels or WebSockets. + */ +export interface Listener extends EventEmitter { + open(): void; + close(): void; + on(name: 'new_socket', cb: (client: Socket) => void): this; +} +//# sourceMappingURL=listener.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/listener.d.ts.map b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/listener.d.ts.map new file mode 100644 index 00000000000..a326bd6b210 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/listener.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"listener.d.ts","sourceRoot":"","sources":["../../../src/transport/interface/listener.ts"],"names":[],"mappings":";AAAA,OAAO,YAAY,MAAM,QAAQ,CAAC;AAClC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC;;;GAGG;AACH,MAAM,WAAW,QAAS,SAAQ,YAAY;IAC5C,IAAI,IAAI,IAAI,CAAC;IAEb,KAAK,IAAI,IAAI,CAAC;IAEd,EAAE,CAAC,IAAI,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;CAC5D"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/listener.js b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/listener.js new file mode 100644 index 00000000000..196998386cb --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/listener.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGlzdGVuZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvdHJhbnNwb3J0L2ludGVyZmFjZS9saXN0ZW5lci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIn0= \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/socket.d.ts b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/socket.d.ts new file mode 100644 index 00000000000..39e6a4e4a6a --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/socket.d.ts @@ -0,0 +1,13 @@ +/** + * Represents one end of a socket connection. + * A message sent via `send` will be handled by the corresponding Socket's handler function at the other end. + * Implementations could use e.g. MessagePorts for communication between browser workers, + * or WebSockets for communication between processes. + * If `registerHandler` callback receives `undefined` that signals the other end closed. + */ +export interface Socket { + send(msg: any, transfer?: Transferable[]): Promise; + registerHandler(cb: (msg: any) => any): void; + close(): void; +} +//# sourceMappingURL=socket.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/socket.d.ts.map b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/socket.d.ts.map new file mode 100644 index 00000000000..a7714e3a539 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/socket.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"socket.d.ts","sourceRoot":"","sources":["../../../src/transport/interface/socket.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,WAAW,MAAM;IACrB,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,CAAC,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD,eAAe,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,GAAG,GAAG,IAAI,CAAC;IAC7C,KAAK,IAAI,IAAI,CAAC;CACf"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/socket.js b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/socket.js new file mode 100644 index 00000000000..5a28a6f054d --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/socket.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic29ja2V0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3RyYW5zcG9ydC9pbnRlcmZhY2Uvc29ja2V0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiIifQ== \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/transferable.d.ts b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/transferable.d.ts new file mode 100644 index 00000000000..f8ef5f290e3 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/transferable.d.ts @@ -0,0 +1,60 @@ +declare const $transferable: unique symbol; +/** + * A descriptor representing a payload with transferable components. + * These components will have ownership transfered when published on an event bus. + */ +export interface TransferDescriptor { + /** + * Marked as transferable. + */ + [$transferable]: true; + /** + * The payload with the transferable objects. + */ + send: T; + /** + * The objects to transfer. + */ + transferables: Transferable[]; +} +/** + * + */ +export declare function isTransferDescriptor(thing: any): thing is TransferDescriptor; +/** + * Mark a transferable object as such, so it will no be serialized and + * deserialized on messaging with the main thread, but to transfer + * ownership of it to the receiving thread. + * + * Only works with array buffers, message ports and few more special + * types of objects, but it's much faster than serializing and + * deserializing them. + * + * Note: + * The transferable object cannot be accessed by this thread again + * unless the receiving thread transfers it back again! + * + * @param transferable - Array buffer, message port or similar. + * @see https://developers.google.com/web/updates/2011/12/Transferable-Objects-Lightning-Fast + */ +export declare function Transfer(transferable: Transferable): TransferDescriptor; +/** + * Mark transferable objects within an arbitrary object or array as + * being a transferable object. They will then not be serialized + * and deserialized on messaging with the main thread, but ownership + * of them will be tranferred to the receiving thread. + * + * Only array buffers, message ports and few more special types of + * objects can be transferred, but it's much faster than serializing and + * deserializing them. + * + * Note: + * The transferable object cannot be accessed by this thread again + * unless the receiving thread transfers it back again! + * + * @param transferable - Array buffer, message port or similar. + * @see https://developers.google.com/web/updates/2011/12/Transferable-Objects-Lightning-Fast + */ +export declare function Transfer(payload: T, transferables: Transferable[]): TransferDescriptor; +export {}; +//# sourceMappingURL=transferable.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/transferable.d.ts.map b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/transferable.d.ts.map new file mode 100644 index 00000000000..5126c83a736 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/transferable.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"transferable.d.ts","sourceRoot":"","sources":["../../../src/transport/interface/transferable.ts"],"names":[],"mappings":"AAAA,QAAA,MAAM,aAAa,eAAgC,CAAC;AAEpD;;;GAGG;AACH,MAAM,WAAW,kBAAkB,CAAC,CAAC,GAAG,GAAG;IACzC;;OAEG;IACH,CAAC,aAAa,CAAC,EAAE,IAAI,CAAC;IACtB;;OAEG;IACH,IAAI,EAAE,CAAC,CAAC;IACR;;OAEG;IACH,aAAa,EAAE,YAAY,EAAE,CAAC;CAC/B;AAWD;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,GAAG,GAAG,KAAK,IAAI,kBAAkB,CAE5E;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,YAAY,EAAE,YAAY,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAAC;AAE/E;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,aAAa,EAAE,YAAY,EAAE,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/transferable.js b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/transferable.js new file mode 100644 index 00000000000..e815bbc8331 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/transferable.js @@ -0,0 +1,35 @@ +const $transferable = Symbol('thread.transferable'); +/** + * + */ +function isTransferable(thing) { + if (!thing || typeof thing !== 'object') + return false; + // Don't check too thoroughly, since the list of transferable things in JS might grow over time + return true; +} +/** + * + */ +export function isTransferDescriptor(thing) { + return thing && typeof thing === 'object' && thing[$transferable]; +} +/** + * Create a transfer descriptor, marking these as transferable. + * @param payload - The payload. + * @param transferables - The transferable objects. + * @returns The descriptor. + */ +export function Transfer(payload, transferables) { + if (!transferables) { + if (!isTransferable(payload)) + throw Error(); + transferables = [payload]; + } + return { + [$transferable]: true, + send: payload, + transferables, + }; +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhbnNmZXJhYmxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3RyYW5zcG9ydC9pbnRlcmZhY2UvdHJhbnNmZXJhYmxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE1BQU0sYUFBYSxHQUFHLE1BQU0sQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDO0FBcUJwRDs7R0FFRztBQUNILFNBQVMsY0FBYyxDQUFDLEtBQVU7SUFDaEMsSUFBSSxDQUFDLEtBQUssSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRO1FBQUUsT0FBTyxLQUFLLENBQUM7SUFDdEQsK0ZBQStGO0lBQy9GLE9BQU8sSUFBSSxDQUFDO0FBQ2QsQ0FBQztBQUVEOztHQUVHO0FBQ0gsTUFBTSxVQUFVLG9CQUFvQixDQUFDLEtBQVU7SUFDN0MsT0FBTyxLQUFLLElBQUksT0FBTyxLQUFLLEtBQUssUUFBUSxJQUFJLEtBQUssQ0FBQyxhQUFhLENBQUMsQ0FBQztBQUNwRSxDQUFDO0FBdUNEOzs7OztHQUtHO0FBQ0gsTUFBTSxVQUFVLFFBQVEsQ0FBSSxPQUFVLEVBQUUsYUFBOEI7SUFDcEUsSUFBSSxDQUFDLGFBQWEsRUFBRTtRQUNsQixJQUFJLENBQUMsY0FBYyxDQUFDLE9BQU8sQ0FBQztZQUFFLE1BQU0sS0FBSyxFQUFFLENBQUM7UUFDNUMsYUFBYSxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUM7S0FDM0I7SUFFRCxPQUFPO1FBQ0wsQ0FBQyxhQUFhLENBQUMsRUFBRSxJQUFJO1FBQ3JCLElBQUksRUFBRSxPQUFPO1FBQ2IsYUFBYTtLQUNkLENBQUM7QUFDSixDQUFDIn0= \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/index.d.ts b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/index.d.ts new file mode 100644 index 00000000000..a39c08a0d40 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/index.d.ts @@ -0,0 +1,3 @@ +export * from './node_connector.js'; +export * from './node_listener.js'; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/index.d.ts.map b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/index.d.ts.map new file mode 100644 index 00000000000..1ea4d29d0e8 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/transport/node/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/index.js b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/index.js new file mode 100644 index 00000000000..07a86060aae --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/index.js @@ -0,0 +1,3 @@ +export * from './node_connector.js'; +export * from './node_listener.js'; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvdHJhbnNwb3J0L25vZGUvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsY0FBYyxxQkFBcUIsQ0FBQztBQUNwQyxjQUFjLG9CQUFvQixDQUFDIn0= \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_connector.d.ts b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_connector.d.ts new file mode 100644 index 00000000000..b1d8890543c --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_connector.d.ts @@ -0,0 +1,17 @@ +/// +import { Worker } from 'worker_threads'; +import { Connector } from '../interface/connector.js'; +import { NodeConnectorSocket } from './node_connector_socket.js'; +/** + * Creates sockets backed by a Node worker. + */ +export declare class NodeConnector implements Connector { + private worker; + constructor(worker: Worker); + /** + * Creates a socket backed by a node worker. + * @returns The socket. + */ + createSocket(): Promise; +} +//# sourceMappingURL=node_connector.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_connector.d.ts.map b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_connector.d.ts.map new file mode 100644 index 00000000000..57ef4337f76 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_connector.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"node_connector.d.ts","sourceRoot":"","sources":["../../../src/transport/node/node_connector.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAEjE;;GAEG;AACH,qBAAa,aAAc,YAAW,SAAS;IACjC,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,MAAM;IAElC;;;OAGG;IACH,YAAY;CAGb"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_connector.js b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_connector.js new file mode 100644 index 00000000000..2525dc38092 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_connector.js @@ -0,0 +1,17 @@ +import { NodeConnectorSocket } from './node_connector_socket.js'; +/** + * Creates sockets backed by a Node worker. + */ +export class NodeConnector { + constructor(worker) { + this.worker = worker; + } + /** + * Creates a socket backed by a node worker. + * @returns The socket. + */ + createSocket() { + return Promise.resolve(new NodeConnectorSocket(this.worker)); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZV9jb25uZWN0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvdHJhbnNwb3J0L25vZGUvbm9kZV9jb25uZWN0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBRUEsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFFakU7O0dBRUc7QUFDSCxNQUFNLE9BQU8sYUFBYTtJQUN4QixZQUFvQixNQUFjO1FBQWQsV0FBTSxHQUFOLE1BQU0sQ0FBUTtJQUFHLENBQUM7SUFFdEM7OztPQUdHO0lBQ0gsWUFBWTtRQUNWLE9BQU8sT0FBTyxDQUFDLE9BQU8sQ0FBQyxJQUFJLG1CQUFtQixDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDO0lBQy9ELENBQUM7Q0FDRiJ9 \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_connector_socket.d.ts b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_connector_socket.d.ts new file mode 100644 index 00000000000..a87192030c2 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_connector_socket.d.ts @@ -0,0 +1,27 @@ +/// +import { Worker } from 'worker_threads'; +import { Socket } from '../interface/socket.js'; +/** + * A socket implementation using a Node worker. + */ +export declare class NodeConnectorSocket implements Socket { + private worker; + constructor(worker: Worker); + /** + * Send a message. + * @param msg - The message. + * @param transfer - Objects to transfer ownership of. + * @returns A void promise. + */ + send(msg: any, transfer?: Transferable[]): Promise; + /** + * Register a message handler. + * @param cb - The handler function. + */ + registerHandler(cb: (msg: any) => any): void; + /** + * Remove all listeners from our worker. + */ + close(): void; +} +//# sourceMappingURL=node_connector_socket.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_connector_socket.d.ts.map b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_connector_socket.d.ts.map new file mode 100644 index 00000000000..a7bbda3ff57 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_connector_socket.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"node_connector_socket.d.ts","sourceRoot":"","sources":["../../../src/transport/node/node_connector_socket.ts"],"names":[],"mappings":";AAAA,OAAO,EAAoB,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAEhD;;GAEG;AACH,qBAAa,mBAAoB,YAAW,MAAM;IACpC,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,MAAM;IAElC;;;;;OAKG;IACH,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,GAAE,YAAY,EAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAK5D;;;OAGG;IACH,eAAe,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,GAAG,GAAG,IAAI;IAI5C;;OAEG;IACH,KAAK;CAIN"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_connector_socket.js b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_connector_socket.js new file mode 100644 index 00000000000..25eb2f34e28 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_connector_socket.js @@ -0,0 +1,33 @@ +/** + * A socket implementation using a Node worker. + */ +export class NodeConnectorSocket { + constructor(worker) { + this.worker = worker; + } + /** + * Send a message. + * @param msg - The message. + * @param transfer - Objects to transfer ownership of. + * @returns A void promise. + */ + send(msg, transfer = []) { + this.worker.postMessage(msg, transfer); + return Promise.resolve(); + } + /** + * Register a message handler. + * @param cb - The handler function. + */ + registerHandler(cb) { + this.worker.on('message', cb); + } + /** + * Remove all listeners from our worker. + */ + close() { + void this.send(undefined); + this.worker.removeAllListeners(); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZV9jb25uZWN0b3Jfc29ja2V0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3RyYW5zcG9ydC9ub2RlL25vZGVfY29ubmVjdG9yX3NvY2tldC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFHQTs7R0FFRztBQUNILE1BQU0sT0FBTyxtQkFBbUI7SUFDOUIsWUFBb0IsTUFBYztRQUFkLFdBQU0sR0FBTixNQUFNLENBQVE7SUFBRyxDQUFDO0lBRXRDOzs7OztPQUtHO0lBQ0gsSUFBSSxDQUFDLEdBQVEsRUFBRSxXQUEyQixFQUFFO1FBQzFDLElBQUksQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLEdBQUcsRUFBRSxRQUE4QixDQUFDLENBQUM7UUFDN0QsT0FBTyxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUM7SUFDM0IsQ0FBQztJQUVEOzs7T0FHRztJQUNILGVBQWUsQ0FBQyxFQUFxQjtRQUNuQyxJQUFJLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxTQUFTLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDaEMsQ0FBQztJQUVEOztPQUVHO0lBQ0gsS0FBSztRQUNILEtBQUssSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUMxQixJQUFJLENBQUMsTUFBTSxDQUFDLGtCQUFrQixFQUFFLENBQUM7SUFDbkMsQ0FBQztDQUNGIn0= \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_listener.d.ts b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_listener.d.ts new file mode 100644 index 00000000000..e9bf26a20ce --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_listener.d.ts @@ -0,0 +1,18 @@ +/// +import EventEmitter from 'events'; +import { Listener } from '../interface/listener.js'; +/** + * A socket listener that works with Node. + */ +export declare class NodeListener extends EventEmitter implements Listener { + constructor(); + /** + * Open the listener. + */ + open(): void; + /** + * Close the listener. + */ + close(): void; +} +//# sourceMappingURL=node_listener.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_listener.d.ts.map b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_listener.d.ts.map new file mode 100644 index 00000000000..e15acee10b1 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_listener.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"node_listener.d.ts","sourceRoot":"","sources":["../../../src/transport/node/node_listener.ts"],"names":[],"mappings":";AACA,OAAO,YAAY,MAAM,QAAQ,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAGpD;;GAEG;AACH,qBAAa,YAAa,SAAQ,YAAa,YAAW,QAAQ;;IAKhE;;OAEG;IACH,IAAI;IAIJ;;OAEG;IACH,KAAK;CACN"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_listener.js b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_listener.js new file mode 100644 index 00000000000..318369699af --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_listener.js @@ -0,0 +1,22 @@ +import { parentPort } from 'worker_threads'; +import EventEmitter from 'events'; +import { NodeListenerSocket } from './node_listener_socket.js'; +/** + * A socket listener that works with Node. + */ +export class NodeListener extends EventEmitter { + constructor() { + super(); + } + /** + * Open the listener. + */ + open() { + this.emit('new_socket', new NodeListenerSocket(parentPort)); + } + /** + * Close the listener. + */ + close() { } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZV9saXN0ZW5lci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy90cmFuc3BvcnQvbm9kZS9ub2RlX2xpc3RlbmVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUM1QyxPQUFPLFlBQVksTUFBTSxRQUFRLENBQUM7QUFFbEMsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFFL0Q7O0dBRUc7QUFDSCxNQUFNLE9BQU8sWUFBYSxTQUFRLFlBQVk7SUFDNUM7UUFDRSxLQUFLLEVBQUUsQ0FBQztJQUNWLENBQUM7SUFFRDs7T0FFRztJQUNILElBQUk7UUFDRixJQUFJLENBQUMsSUFBSSxDQUFDLFlBQVksRUFBRSxJQUFJLGtCQUFrQixDQUFDLFVBQWlCLENBQUMsQ0FBQyxDQUFDO0lBQ3JFLENBQUM7SUFFRDs7T0FFRztJQUNILEtBQUssS0FBSSxDQUFDO0NBQ1gifQ== \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_listener_socket.d.ts b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_listener_socket.d.ts new file mode 100644 index 00000000000..ee114126deb --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_listener_socket.d.ts @@ -0,0 +1,27 @@ +/// +import { MessagePort } from 'worker_threads'; +import { Socket } from '../interface/socket.js'; +/** + * An implementation of a TransportSocket using MessagePorts. + */ +export declare class NodeListenerSocket implements Socket { + private port; + constructor(port: MessagePort); + /** + * Send a message over this port. + * @param msg - The message. + * @param transfer - Transferable objects. + * @returns A void promise. + */ + send(msg: any, transfer?: Transferable[]): Promise; + /** + * Add a handler to this port. + * @param cb - The handler function. + */ + registerHandler(cb: (msg: any) => any): void; + /** + * Close this socket. + */ + close(): void; +} +//# sourceMappingURL=node_listener_socket.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_listener_socket.d.ts.map b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_listener_socket.d.ts.map new file mode 100644 index 00000000000..31986e0cd02 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_listener_socket.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"node_listener_socket.d.ts","sourceRoot":"","sources":["../../../src/transport/node/node_listener_socket.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,WAAW,EAAoB,MAAM,gBAAgB,CAAC;AAC/D,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAEhD;;GAEG;AACH,qBAAa,kBAAmB,YAAW,MAAM;IACnC,OAAO,CAAC,IAAI;gBAAJ,IAAI,EAAE,WAAW;IAErC;;;;;OAKG;IACH,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,GAAE,YAAY,EAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAK5D;;;OAGG;IACH,eAAe,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,GAAG,GAAG,IAAI;IAI5C;;OAEG;IACH,KAAK;CAKN"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_listener_socket.js b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_listener_socket.js new file mode 100644 index 00000000000..483c51bc0ff --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_listener_socket.js @@ -0,0 +1,34 @@ +/** + * An implementation of a TransportSocket using MessagePorts. + */ +export class NodeListenerSocket { + constructor(port) { + this.port = port; + } + /** + * Send a message over this port. + * @param msg - The message. + * @param transfer - Transferable objects. + * @returns A void promise. + */ + send(msg, transfer = []) { + this.port.postMessage(msg, transfer); + return Promise.resolve(); + } + /** + * Add a handler to this port. + * @param cb - The handler function. + */ + registerHandler(cb) { + this.port.on('message', cb); + } + /** + * Close this socket. + */ + close() { + void this.send(undefined); + this.port.removeAllListeners(); + this.port.close(); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZV9saXN0ZW5lcl9zb2NrZXQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvdHJhbnNwb3J0L25vZGUvbm9kZV9saXN0ZW5lcl9zb2NrZXQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBR0E7O0dBRUc7QUFDSCxNQUFNLE9BQU8sa0JBQWtCO0lBQzdCLFlBQW9CLElBQWlCO1FBQWpCLFNBQUksR0FBSixJQUFJLENBQWE7SUFBRyxDQUFDO0lBRXpDOzs7OztPQUtHO0lBQ0gsSUFBSSxDQUFDLEdBQVEsRUFBRSxXQUEyQixFQUFFO1FBQzFDLElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLEdBQUcsRUFBRSxRQUE4QixDQUFDLENBQUM7UUFDM0QsT0FBTyxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUM7SUFDM0IsQ0FBQztJQUVEOzs7T0FHRztJQUNILGVBQWUsQ0FBQyxFQUFxQjtRQUNuQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxTQUFTLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDOUIsQ0FBQztJQUVEOztPQUVHO0lBQ0gsS0FBSztRQUNILEtBQUssSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUMxQixJQUFJLENBQUMsSUFBSSxDQUFDLGtCQUFrQixFQUFFLENBQUM7UUFDL0IsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztJQUNwQixDQUFDO0NBQ0YifQ== \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/transport_client.d.ts b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/transport_client.d.ts new file mode 100644 index 00000000000..a70ae9fea5e --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/transport_client.d.ts @@ -0,0 +1,44 @@ +/// +import EventEmitter from 'events'; +import { Connector } from './interface/connector.js'; +/** + * Augments the TransportClient class with more precise EventEmitter types. + */ +export interface TransportClient extends EventEmitter { + on(name: 'event_msg', handler: (payload: Payload) => void): this; + emit(name: 'event_msg', payload: Payload): boolean; +} +/** + * A TransportClient provides a request/response and event api to a corresponding TransportServer. + * If `broadcast` is called on TransportServer, TransportClients will emit an `event_msg`. + * The `request` method will block until a response is returned from the TransportServer's dispatch function. + * Request multiplexing is supported. + */ +export declare class TransportClient extends EventEmitter { + private transportConnect; + private msgId; + private pendingRequests; + private socket?; + constructor(transportConnect: Connector); + /** + * Create and register our socket using our Connector. + */ + open(): Promise; + /** + * Close this and stop listening for messages. + */ + close(): void; + /** + * Queue a request. + * @param payload - The request payload. + * @param transfer - Objects to transfer ownership of. + * @returns A promise of the query result. + */ + request(payload: Payload, transfer?: Transferable[]): Promise; + /** + * Handle an incoming socket message. + * @param msg - The message. + */ + private handleSocketMessage; +} +//# sourceMappingURL=transport_client.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/transport_client.d.ts.map b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/transport_client.d.ts.map new file mode 100644 index 00000000000..9d6db62d26d --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/transport_client.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"transport_client.d.ts","sourceRoot":"","sources":["../../src/transport/transport_client.ts"],"names":[],"mappings":";AACA,OAAO,YAAY,MAAM,QAAQ,CAAC;AAElC,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAiBrD;;GAEG;AACH,MAAM,WAAW,eAAe,CAAC,OAAO,CAAE,SAAQ,YAAY;IAC5D,EAAE,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI,CAAC;IACjE,IAAI,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC;CACpD;AAED;;;;;GAKG;AACH,qBAAa,eAAe,CAAC,OAAO,CAAE,SAAQ,YAAY;IAK5C,OAAO,CAAC,gBAAgB;IAJpC,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,eAAe,CAAwB;IAC/C,OAAO,CAAC,MAAM,CAAC,CAAS;gBAEJ,gBAAgB,EAAE,SAAS;IAI/C;;OAEG;IACG,IAAI;IAKV;;OAEG;IACH,KAAK;IAML;;;;;OAKG;IACH,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,YAAY,EAAE;IAanD;;;OAGG;IACH,OAAO,CAAC,mBAAmB;CAsB5B"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/transport_client.js b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/transport_client.js new file mode 100644 index 00000000000..ee8579704b4 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/transport_client.js @@ -0,0 +1,79 @@ +import { createDebugLogger } from '@aztec/log'; +import EventEmitter from 'events'; +import { isEventMessage } from './dispatch/messages.js'; +const debug = createDebugLogger('aztec:transport_client'); +/** + * A TransportClient provides a request/response and event api to a corresponding TransportServer. + * If `broadcast` is called on TransportServer, TransportClients will emit an `event_msg`. + * The `request` method will block until a response is returned from the TransportServer's dispatch function. + * Request multiplexing is supported. + */ +export class TransportClient extends EventEmitter { + constructor(transportConnect) { + super(); + this.transportConnect = transportConnect; + this.msgId = 0; + this.pendingRequests = []; + } + /** + * Create and register our socket using our Connector. + */ + async open() { + this.socket = await this.transportConnect.createSocket(); + this.socket.registerHandler(msg => this.handleSocketMessage(msg)); + } + /** + * Close this and stop listening for messages. + */ + close() { + this.socket?.close(); + this.socket = undefined; + this.removeAllListeners(); + } + /** + * Queue a request. + * @param payload - The request payload. + * @param transfer - Objects to transfer ownership of. + * @returns A promise of the query result. + */ + request(payload, transfer) { + if (!this.socket) { + throw new Error('Socket not open.'); + } + const msgId = this.msgId++; + const msg = { msgId, payload }; + debug(`->`, msg); + return new Promise((resolve, reject) => { + this.pendingRequests.push({ resolve, reject, msgId }); + this.socket.send(msg, transfer).catch(reject); + }); + } + /** + * Handle an incoming socket message. + * @param msg - The message. + */ + handleSocketMessage(msg) { + if (msg === undefined) { + // The remote socket closed. + this.close(); + return; + } + debug(`<-`, msg); + if (isEventMessage(msg)) { + this.emit('event_msg', msg.payload); + return; + } + const reqIndex = this.pendingRequests.findIndex(r => r.msgId === msg.msgId); + if (reqIndex === -1) { + return; + } + const [pending] = this.pendingRequests.splice(reqIndex, 1); + if (msg.error) { + pending.reject(new Error(msg.error)); + } + else { + pending.resolve(msg.payload); + } + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhbnNwb3J0X2NsaWVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90cmFuc3BvcnQvdHJhbnNwb3J0X2NsaWVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFDL0MsT0FBTyxZQUFZLE1BQU0sUUFBUSxDQUFDO0FBQ2xDLE9BQU8sRUFBZ0IsY0FBYyxFQUFtQixNQUFNLHdCQUF3QixDQUFDO0FBSXZGLE1BQU0sS0FBSyxHQUFHLGlCQUFpQixDQUFDLHdCQUF3QixDQUFDLENBQUM7QUFzQjFEOzs7OztHQUtHO0FBQ0gsTUFBTSxPQUFPLGVBQXlCLFNBQVEsWUFBWTtJQUt4RCxZQUFvQixnQkFBMkI7UUFDN0MsS0FBSyxFQUFFLENBQUM7UUFEVSxxQkFBZ0IsR0FBaEIsZ0JBQWdCLENBQVc7UUFKdkMsVUFBSyxHQUFHLENBQUMsQ0FBQztRQUNWLG9CQUFlLEdBQXFCLEVBQUUsQ0FBQztJQUsvQyxDQUFDO0lBRUQ7O09BRUc7SUFDSCxLQUFLLENBQUMsSUFBSTtRQUNSLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxJQUFJLENBQUMsZ0JBQWdCLENBQUMsWUFBWSxFQUFFLENBQUM7UUFDekQsSUFBSSxDQUFDLE1BQU0sQ0FBQyxlQUFlLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsbUJBQW1CLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUNwRSxDQUFDO0lBRUQ7O09BRUc7SUFDSCxLQUFLO1FBQ0gsSUFBSSxDQUFDLE1BQU0sRUFBRSxLQUFLLEVBQUUsQ0FBQztRQUNyQixJQUFJLENBQUMsTUFBTSxHQUFHLFNBQVMsQ0FBQztRQUN4QixJQUFJLENBQUMsa0JBQWtCLEVBQUUsQ0FBQztJQUM1QixDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSCxPQUFPLENBQUMsT0FBZ0IsRUFBRSxRQUF5QjtRQUNqRCxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRTtZQUNoQixNQUFNLElBQUksS0FBSyxDQUFDLGtCQUFrQixDQUFDLENBQUM7U0FDckM7UUFDRCxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDM0IsTUFBTSxHQUFHLEdBQUcsRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFFLENBQUM7UUFDL0IsS0FBSyxDQUFDLElBQUksRUFBRSxHQUFHLENBQUMsQ0FBQztRQUNqQixPQUFPLElBQUksT0FBTyxDQUFNLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxFQUFFO1lBQzFDLElBQUksQ0FBQyxlQUFlLENBQUMsSUFBSSxDQUFDLEVBQUUsT0FBTyxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUsQ0FBQyxDQUFDO1lBQ3RELElBQUksQ0FBQyxNQUFPLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxRQUFRLENBQUMsQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDakQsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQ7OztPQUdHO0lBQ0ssbUJBQW1CLENBQUMsR0FBaUU7UUFDM0YsSUFBSSxHQUFHLEtBQUssU0FBUyxFQUFFO1lBQ3JCLDRCQUE0QjtZQUM1QixJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDYixPQUFPO1NBQ1I7UUFDRCxLQUFLLENBQUMsSUFBSSxFQUFFLEdBQUcsQ0FBQyxDQUFDO1FBQ2pCLElBQUksY0FBYyxDQUFDLEdBQUcsQ0FBQyxFQUFFO1lBQ3ZCLElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUNwQyxPQUFPO1NBQ1I7UUFDRCxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsZUFBZSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxLQUFLLEtBQUssR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzVFLElBQUksUUFBUSxLQUFLLENBQUMsQ0FBQyxFQUFFO1lBQ25CLE9BQU87U0FDUjtRQUNELE1BQU0sQ0FBQyxPQUFPLENBQUMsR0FBRyxJQUFJLENBQUMsZUFBZSxDQUFDLE1BQU0sQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFDM0QsSUFBSSxHQUFHLENBQUMsS0FBSyxFQUFFO1lBQ2IsT0FBTyxDQUFDLE1BQU0sQ0FBQyxJQUFJLEtBQUssQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztTQUN0QzthQUFNO1lBQ0wsT0FBTyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUM7U0FDOUI7SUFDSCxDQUFDO0NBQ0YifQ== \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/transport_server.d.ts b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/transport_server.d.ts new file mode 100644 index 00000000000..109e9210f8b --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/transport_server.d.ts @@ -0,0 +1,44 @@ +import { Listener } from './interface/listener.js'; +/** + * Keeps track of clients, providing a broadcast, and request/response api with multiplexing. + */ +export declare class TransportServer { + private listener; + private msgHandlerFn; + private sockets; + constructor(listener: Listener, msgHandlerFn: (msg: Payload) => Promise); + /** + * Start accepting new connections. + */ + start(): void; + /** + * Stops accepting new connections. It doesn't close existing sockets. + * It's expected the clients will gracefully complete by closing their end, sending an `undefined` message. + */ + stop(): void; + /** + * Broadcast a message. + * @param msg - The message. + */ + broadcast(msg: Payload): Promise; + /** + * New socket registration. + * @param socket - The socket to register. + */ + private handleNewSocket; + /** + * Detect the 'transferables' argument to our socket from our message + * handler return type. + * @param data - The return object. + * @returns - The data and the. + */ + private getPayloadAndTransfers; + /** + * Handles a socket message from a listener. + * @param socket - The socket. + * @param requestMessage - The message to handle. + * @returns The socket response. + */ + private handleSocketMessage; +} +//# sourceMappingURL=transport_server.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/transport_server.d.ts.map b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/transport_server.d.ts.map new file mode 100644 index 00000000000..103804f9808 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/transport_server.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"transport_server.d.ts","sourceRoot":"","sources":["../../src/transport/transport_server.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAInD;;GAEG;AACH,qBAAa,eAAe,CAAC,OAAO;IAGtB,OAAO,CAAC,QAAQ;IAAY,OAAO,CAAC,YAAY;IAF5D,OAAO,CAAC,OAAO,CAAgB;gBAEX,QAAQ,EAAE,QAAQ,EAAU,YAAY,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,GAAG,CAAC;IAE5F;;OAEG;IACH,KAAK;IAKL;;;OAGG;IACH,IAAI;IAIJ;;;OAGG;IACG,SAAS,CAAC,GAAG,EAAE,OAAO;IAI5B;;;OAGG;IACH,OAAO,CAAC,eAAe;IAcvB;;;;;OAKG;IACH,OAAO,CAAC,sBAAsB;IAe9B;;;;;OAKG;YACW,mBAAmB;CAalC"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/transport_server.js b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/transport_server.js new file mode 100644 index 00000000000..b1865345fc4 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/transport_server.js @@ -0,0 +1,89 @@ +import { isTransferDescriptor } from './interface/transferable.js'; +/** + * Keeps track of clients, providing a broadcast, and request/response api with multiplexing. + */ +export class TransportServer { + constructor(listener, msgHandlerFn) { + this.listener = listener; + this.msgHandlerFn = msgHandlerFn; + this.sockets = []; + } + /** + * Start accepting new connections. + */ + start() { + this.listener.on('new_socket', client => this.handleNewSocket(client)); + this.listener.open(); + } + /** + * Stops accepting new connections. It doesn't close existing sockets. + * It's expected the clients will gracefully complete by closing their end, sending an `undefined` message. + */ + stop() { + this.listener.close(); + } + /** + * Broadcast a message. + * @param msg - The message. + */ + async broadcast(msg) { + await Promise.all(this.sockets.map(s => s.send({ payload: msg }))); + } + /** + * New socket registration. + * @param socket - The socket to register. + */ + handleNewSocket(socket) { + socket.registerHandler(async (msg) => { + if (msg === undefined) { + // Client socket has closed. Remove it from the list of sockets. Call close on it for any cleanup. + const socketIndex = this.sockets.findIndex(s => s === socket); + const [closingSocket] = this.sockets.splice(socketIndex, 1); + closingSocket.close(); + return; + } + return await this.handleSocketMessage(socket, msg); + }); + this.sockets.push(socket); + } + /** + * Detect the 'transferables' argument to our socket from our message + * handler return type. + * @param data - The return object. + * @returns - The data and the. + */ + getPayloadAndTransfers(data) { + if (isTransferDescriptor(data)) { + // We treat PayloadWithTransfers specially so that we're able to + // attach transferables while keeping a simple return-type based usage + return [data.send, data.transferables]; + } + if (data instanceof Uint8Array) { + // We may want to devise a better solution to this. We maybe given a view over a non cloneable/transferrable + // ArrayBuffer (such as a view over wasm memory). In this case we want to take a copy, and then transfer it. + const respPayload = data instanceof Uint8Array && ArrayBuffer.isView(data) ? new Uint8Array(data) : data; + const transferables = data instanceof Uint8Array ? [respPayload.buffer] : []; + return [respPayload, transferables]; + } + return [data, []]; + } + /** + * Handles a socket message from a listener. + * @param socket - The socket. + * @param requestMessage - The message to handle. + * @returns The socket response. + */ + async handleSocketMessage(socket, { msgId, payload }) { + try { + const data = await this.msgHandlerFn(payload); + const [respPayload, transferables] = this.getPayloadAndTransfers(data); + const rep = { msgId, payload: respPayload }; + await socket.send(rep, transferables); + } + catch (err) { + const rep = { msgId, error: err.stack }; + await socket.send(rep); + } + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhbnNwb3J0X3NlcnZlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90cmFuc3BvcnQvdHJhbnNwb3J0X3NlcnZlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFHQSxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUVuRTs7R0FFRztBQUNILE1BQU0sT0FBTyxlQUFlO0lBRzFCLFlBQW9CLFFBQWtCLEVBQVUsWUFBNEM7UUFBeEUsYUFBUSxHQUFSLFFBQVEsQ0FBVTtRQUFVLGlCQUFZLEdBQVosWUFBWSxDQUFnQztRQUZwRixZQUFPLEdBQWEsRUFBRSxDQUFDO0lBRWdFLENBQUM7SUFFaEc7O09BRUc7SUFDSCxLQUFLO1FBQ0gsSUFBSSxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUMsWUFBWSxFQUFFLE1BQU0sQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDO1FBQ3ZFLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDdkIsQ0FBQztJQUVEOzs7T0FHRztJQUNILElBQUk7UUFDRixJQUFJLENBQUMsUUFBUSxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQ3hCLENBQUM7SUFFRDs7O09BR0c7SUFDSCxLQUFLLENBQUMsU0FBUyxDQUFDLEdBQVk7UUFDMUIsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxFQUFFLE9BQU8sRUFBRSxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNyRSxDQUFDO0lBRUQ7OztPQUdHO0lBQ0ssZUFBZSxDQUFDLE1BQWM7UUFDcEMsTUFBTSxDQUFDLGVBQWUsQ0FBQyxLQUFLLEVBQUMsR0FBRyxFQUFDLEVBQUU7WUFDakMsSUFBSSxHQUFHLEtBQUssU0FBUyxFQUFFO2dCQUNyQixrR0FBa0c7Z0JBQ2xHLE1BQU0sV0FBVyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxLQUFLLE1BQU0sQ0FBQyxDQUFDO2dCQUM5RCxNQUFNLENBQUMsYUFBYSxDQUFDLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsV0FBVyxFQUFFLENBQUMsQ0FBQyxDQUFDO2dCQUM1RCxhQUFhLENBQUMsS0FBSyxFQUFFLENBQUM7Z0JBQ3RCLE9BQU87YUFDUjtZQUNELE9BQU8sTUFBTSxJQUFJLENBQUMsbUJBQW1CLENBQUMsTUFBTSxFQUFFLEdBQUcsQ0FBQyxDQUFDO1FBQ3JELENBQUMsQ0FBQyxDQUFDO1FBQ0gsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDNUIsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ0ssc0JBQXNCLENBQUMsSUFBUztRQUN0QyxJQUFJLG9CQUFvQixDQUFDLElBQUksQ0FBQyxFQUFFO1lBQzlCLGdFQUFnRTtZQUNoRSxzRUFBc0U7WUFDdEUsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDO1NBQ3hDO1FBQ0QsSUFBSSxJQUFJLFlBQVksVUFBVSxFQUFFO1lBQzlCLDRHQUE0RztZQUM1Ryw0R0FBNEc7WUFDNUcsTUFBTSxXQUFXLEdBQUcsSUFBSSxZQUFZLFVBQVUsSUFBSSxXQUFXLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLFVBQVUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDO1lBQ3pHLE1BQU0sYUFBYSxHQUFHLElBQUksWUFBWSxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsV0FBVyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7WUFDN0UsT0FBTyxDQUFDLFdBQVcsRUFBRSxhQUFhLENBQUMsQ0FBQztTQUNyQztRQUNELE9BQU8sQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDcEIsQ0FBQztJQUNEOzs7OztPQUtHO0lBQ0ssS0FBSyxDQUFDLG1CQUFtQixDQUFDLE1BQWMsRUFBRSxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQTJCO1FBQzNGLElBQUk7WUFDRixNQUFNLElBQUksR0FBRyxNQUFNLElBQUksQ0FBQyxZQUFZLENBQUMsT0FBTyxDQUFDLENBQUM7WUFFOUMsTUFBTSxDQUFDLFdBQVcsRUFBRSxhQUFhLENBQUMsR0FBRyxJQUFJLENBQUMsc0JBQXNCLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDdkUsTUFBTSxHQUFHLEdBQTZCLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxXQUFXLEVBQUUsQ0FBQztZQUV0RSxNQUFNLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLGFBQWEsQ0FBQyxDQUFDO1NBQ3ZDO1FBQUMsT0FBTyxHQUFRLEVBQUU7WUFDakIsTUFBTSxHQUFHLEdBQTZCLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxHQUFHLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDbEUsTUFBTSxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1NBQ3hCO0lBQ0gsQ0FBQztDQUNGIn0= \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/async_call_state.d.ts b/circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/async_call_state.d.ts new file mode 100644 index 00000000000..9c987278c76 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/async_call_state.d.ts @@ -0,0 +1,72 @@ +import { WasmModule } from './wasm_module.js'; +/** + * The state of an asynchronous WASM function. + */ +export interface AsyncFnState { + /** + * Is this a contination? + */ + continuation: boolean; + /** + * A result, if one exists. + */ + result?: any; +} +/** + * To enable asynchronous callbacks from wasm to js, we leverage asyncify. + * Https://kripken.github.io/blog/wasm/2019/07/16/asyncify.html. + * + * This class holds state and logic specific to handling async calls from wasm to js. + * A single instance of this class is instantiated as part of BarretenbergWasm. + * It allocates some memory for the asyncify stack data and initialises it. + * + * To make an async call into the wasm, just call `call` the same as in BarretenbergWasm, only it returns a promise. + * + * To make an async import that will be called from the wasm, wrap a function with the signature: + * my_func(state: AsyncFnState, ...args) + * with a call to `wrapImportFn`. + * The arguments are whatever the original call arguments were. The addition of AsyncFnState as the first argument + * allows for the detection of wether the function is continuing after the the async call has completed. + * If `state.continuation` is false, the function should start its async operation and return the promise. + * If `state.continuation` is true, the function can get the result from `state.result` perform any finalisation, + * and return an (optional) value to the wasm. + */ +export declare class AsyncCallState { + private ASYNCIFY_DATA_SIZE; + private asyncifyDataAddr; + private asyncPromise?; + private wasm; + private state?; + private callExport; + /** + * Initialize the call hooks with a WasmModule. + * @param wasm - The module. + */ + init(wasm: WasmModule): void; + /** + * Log a message. + * @param args - The message arguments. + */ + private debug; + /** + * Free the data associated with async call states. + */ + destroy(): void; + /** + * We call the wasm function, that will in turn call back into js via callImport and set this.asyncPromise and + * enable the instrumented "record stack unwinding" code path. + * Once the stack has unwound out of the wasm call, we enter into a loop of resolving the promise set in the call + * to callImport, and calling back into the wasm to rewind the stack and continue execution. + * @param name - The function name. + * @param args - The function args. + * @returns The function result. + */ + call(name: string, ...args: any): Promise; + /** + * Wrap a WASM import function. + * @param fn - The function. + * @returns A wrapped version with asyncify calls. + */ + wrapImportFn(fn: (state: AsyncFnState, ...args: any[]) => any): (...args: any[]) => any; +} +//# sourceMappingURL=async_call_state.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/async_call_state.d.ts.map b/circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/async_call_state.d.ts.map new file mode 100644 index 00000000000..ae4697ced4c --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/async_call_state.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"async_call_state.d.ts","sourceRoot":"","sources":["../../src/wasm/async_call_state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;OAEG;IACH,YAAY,EAAE,OAAO,CAAC;IACtB;;OAEG;IACH,MAAM,CAAC,EAAE,GAAG,CAAC;CACd;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,kBAAkB,CAAa;IACvC,OAAO,CAAC,gBAAgB,CAAU;IAClC,OAAO,CAAC,YAAY,CAAC,CAAe;IACpC,OAAO,CAAC,IAAI,CAAc;IAC1B,OAAO,CAAC,KAAK,CAAC,CAAe;IAC7B,OAAO,CAAC,UAAU,CAA8B;IAEhD;;;OAGG;IACI,IAAI,CAAC,IAAI,EAAE,UAAU;IAY5B;;;OAGG;IACH,OAAO,CAAC,KAAK;IAIb;;OAEG;IACI,OAAO;IAKd;;;;;;;;OAQG;IACU,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG;IA2B5C;;;;OAIG;IACI,YAAY,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,aACjD,GAAG,EAAE;CAkBzB"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/async_call_state.js b/circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/async_call_state.js new file mode 100644 index 00000000000..b24bb8432f6 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/async_call_state.js @@ -0,0 +1,111 @@ +/** + * To enable asynchronous callbacks from wasm to js, we leverage asyncify. + * Https://kripken.github.io/blog/wasm/2019/07/16/asyncify.html. + * + * This class holds state and logic specific to handling async calls from wasm to js. + * A single instance of this class is instantiated as part of BarretenbergWasm. + * It allocates some memory for the asyncify stack data and initialises it. + * + * To make an async call into the wasm, just call `call` the same as in BarretenbergWasm, only it returns a promise. + * + * To make an async import that will be called from the wasm, wrap a function with the signature: + * my_func(state: AsyncFnState, ...args) + * with a call to `wrapImportFn`. + * The arguments are whatever the original call arguments were. The addition of AsyncFnState as the first argument + * allows for the detection of wether the function is continuing after the the async call has completed. + * If `state.continuation` is false, the function should start its async operation and return the promise. + * If `state.continuation` is true, the function can get the result from `state.result` perform any finalisation, + * and return an (optional) value to the wasm. + */ +export class AsyncCallState { + constructor() { + this.ASYNCIFY_DATA_SIZE = 16 * 1024; + } + /** + * Initialize the call hooks with a WasmModule. + * @param wasm - The module. + */ + init(wasm) { + this.wasm = wasm; + this.callExport = (name, ...args) => wasm.call(name, ...args); + // Allocate memory for asyncify stack data. + this.asyncifyDataAddr = this.callExport('bbmalloc', this.ASYNCIFY_DATA_SIZE); + // TODO: is this view construction problematic like in WasmModule? + const view = new Uint32Array(wasm.getRawMemory().buffer); + // First two integers of asyncify data, are the start and end of the stack region. + view[this.asyncifyDataAddr >> 2] = this.asyncifyDataAddr + 8; + view[(this.asyncifyDataAddr + 4) >> 2] = this.asyncifyDataAddr + this.ASYNCIFY_DATA_SIZE; + } + /** + * Log a message. + * @param args - The message arguments. + */ + debug(...args) { + this.wasm.getLogger()(...args); + } + /** + * Free the data associated with async call states. + */ + destroy() { + // Free call stack data. + this.callExport('bbfree', this.asyncifyDataAddr); + } + /** + * We call the wasm function, that will in turn call back into js via callImport and set this.asyncPromise and + * enable the instrumented "record stack unwinding" code path. + * Once the stack has unwound out of the wasm call, we enter into a loop of resolving the promise set in the call + * to callImport, and calling back into the wasm to rewind the stack and continue execution. + * @param name - The function name. + * @param args - The function args. + * @returns The function result. + */ + async call(name, ...args) { + if (this.state) { + throw new Error(`Can only handle one async call at a time: ${name}(${args})`); + } + this.state = { continuation: false }; + let result = this.callExport(name, ...args); + while (this.asyncPromise) { + // Disable the instrumented "record stack unwinding" code path. + this.callExport('asyncify_stop_unwind'); + this.debug('stack unwound.'); + // Wait for the async work to complete. + this.state.result = await this.asyncPromise; + this.state.continuation = true; + this.debug('result set starting rewind.'); + // Enable "stack rewinding" code path. + this.callExport('asyncify_start_rewind', this.asyncifyDataAddr); + // Call function again to rebuild the stack, and continue where we left off. + result = this.callExport(name, ...args); + } + // Cleanup + this.state = undefined; + return result; + } + /** + * Wrap a WASM import function. + * @param fn - The function. + * @returns A wrapped version with asyncify calls. + */ + wrapImportFn(fn) { + return (...args) => { + if (!this.asyncPromise) { + // We are in the normal code path. Start the async fetch of data. + this.asyncPromise = fn(this.state, ...args); + // Enable "record stack unwinding" code path and return. + this.callExport('asyncify_start_unwind', this.asyncifyDataAddr); + } + else { + // We are in the stack rewind code path, called once the promise is resolved. + // Save the result data back to the wasm, disable stack rewind code paths, and return. + this.callExport('asyncify_stop_rewind'); + const result = fn(this.state, ...args); + // Cleanup. + this.asyncPromise = undefined; + this.state = { continuation: false }; + return result; + } + }; + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXN5bmNfY2FsbF9zdGF0ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy93YXNtL2FzeW5jX2NhbGxfc3RhdGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBZ0JBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FrQkc7QUFDSCxNQUFNLE9BQU8sY0FBYztJQUEzQjtRQUNVLHVCQUFrQixHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUM7SUFtR3pDLENBQUM7SUE1RkM7OztPQUdHO0lBQ0ksSUFBSSxDQUFDLElBQWdCO1FBQzFCLElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDO1FBQ2pCLElBQUksQ0FBQyxVQUFVLEdBQUcsQ0FBQyxJQUFZLEVBQUUsR0FBRyxJQUFXLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLEdBQUcsSUFBSSxDQUFDLENBQUM7UUFDN0UsMkNBQTJDO1FBQzNDLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLFVBQVUsRUFBRSxJQUFJLENBQUMsa0JBQWtCLENBQUMsQ0FBQztRQUM3RSxrRUFBa0U7UUFDbEUsTUFBTSxJQUFJLEdBQUcsSUFBSSxXQUFXLENBQUMsSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ3pELGtGQUFrRjtRQUNsRixJQUFJLENBQUMsSUFBSSxDQUFDLGdCQUFnQixJQUFJLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxDQUFDLENBQUM7UUFDN0QsSUFBSSxDQUFDLENBQUMsSUFBSSxDQUFDLGdCQUFnQixHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxJQUFJLENBQUMsa0JBQWtCLENBQUM7SUFDM0YsQ0FBQztJQUVEOzs7T0FHRztJQUNLLEtBQUssQ0FBQyxHQUFHLElBQVc7UUFDMUIsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFT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 \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/empty_wasi_sdk.d.ts b/circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/empty_wasi_sdk.d.ts new file mode 100644 index 00000000000..3ba72aaa184 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/empty_wasi_sdk.d.ts @@ -0,0 +1,24 @@ +/** + * Dummy implementation of a necessary part of the wasi api: + * https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md + * We don't use these functions, but the environment expects them. + * TODO find a way to update off of wasi 12. + */ +export declare const getEmptyWasiSdk: (debug?: import("@aztec/log").DebugLogger) => { + clock_time_get(): void; + environ_get(): void; + environ_sizes_get(): void; + fd_close(): void; + fd_read(): void; + fd_write(): void; + fd_seek(): void; + fd_fdstat_get(): void; + fd_fdstat_set_flags(): void; + fd_prestat_get(): number; + fd_prestat_dir_name(): number; + path_open(): void; + path_filestat_get(): void; + proc_exit(): number; + random_get(): number; +}; +//# sourceMappingURL=empty_wasi_sdk.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/empty_wasi_sdk.d.ts.map b/circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/empty_wasi_sdk.d.ts.map new file mode 100644 index 00000000000..961a206c39f --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/empty_wasi_sdk.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"empty_wasi_sdk.d.ts","sourceRoot":"","sources":["../../src/wasm/empty_wasi_sdk.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AAGH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;CAkD1B,CAAC"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/empty_wasi_sdk.js b/circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/empty_wasi_sdk.js new file mode 100644 index 00000000000..5da154ab582 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/empty_wasi_sdk.js @@ -0,0 +1,61 @@ +import { createDebugLogger } from '@aztec/log'; +/** + * Dummy implementation of a necessary part of the wasi api: + * https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md + * We don't use these functions, but the environment expects them. + * TODO find a way to update off of wasi 12. + */ +/* eslint-disable camelcase */ +/* eslint-disable jsdoc/require-jsdoc */ +export const getEmptyWasiSdk = (debug = createDebugLogger('wasm-worker:empty_wasi_sdk')) => ({ + clock_time_get() { + debug('clock_time_get'); + }, + environ_get() { + debug('environ_get'); + }, + environ_sizes_get() { + debug('environ_sizes_get'); + }, + fd_close() { + debug('fd_close'); + }, + fd_read() { + debug('fd_read'); + }, + fd_write() { + debug('fd_write'); + }, + fd_seek() { + debug('fd_seek'); + }, + fd_fdstat_get() { + debug('fd_fdstat_get'); + }, + fd_fdstat_set_flags() { + debug('fd_fdstat_set_flags'); + }, + fd_prestat_get() { + debug('fd_prestat_get'); + return 8; + }, + fd_prestat_dir_name() { + debug('fd_prestat_dir_name'); + return 28; + }, + path_open() { + debug('path_open'); + }, + path_filestat_get() { + debug('path_filestat_get'); + }, + proc_exit() { + debug('proc_exit'); + return 52; + }, + random_get() { + debug('random_get'); + return 1; + }, +}); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW1wdHlfd2FzaV9zZGsuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvd2FzbS9lbXB0eV93YXNpX3Nkay50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFFL0M7Ozs7O0dBS0c7QUFDSCw4QkFBOEI7QUFDOUIsd0NBQXdDO0FBQ3hDLE1BQU0sQ0FBQyxNQUFNLGVBQWUsR0FBRyxDQUFDLEtBQUssR0FBRyxpQkFBaUIsQ0FBQyw0QkFBNEIsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQzNGLGNBQWM7UUFDWixLQUFLLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztJQUMxQixDQUFDO0lBQ0QsV0FBVztRQUNULEtBQUssQ0FBQyxhQUFhLENBQUMsQ0FBQztJQUN2QixDQUFDO0lBQ0QsaUJBQWlCO1FBQ2YsS0FBSyxDQUFDLG1CQUFtQixDQUFDLENBQUM7SUFDN0IsQ0FBQztJQUNELFFBQVE7UUFDTixLQUFLLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDcEIsQ0FBQztJQUNELE9BQU87UUFDTCxLQUFLLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDbkIsQ0FBQztJQUNELFFBQVE7UUFDTixLQUFLLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDcEIsQ0FBQztJQUNELE9BQU87UUFDTCxLQUFLLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDbkIsQ0FBQztJQUNELGFBQWE7UUFDWCxLQUFLLENBQUMsZUFBZSxDQUFDLENBQUM7SUFDekIsQ0FBQztJQUNELG1CQUFtQjtRQUNqQixLQUFLLENBQUMscUJBQXFCLENBQUMsQ0FBQztJQUMvQixDQUFDO0lBQ0QsY0FBYztRQUNaLEtBQUssQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO1FBQ3hCLE9BQU8sQ0FBQyxDQUFDO0lBQ1gsQ0FBQztJQUNELG1CQUFtQjtRQUNqQixLQUFLLENBQUMscUJBQXFCLENBQUMsQ0FBQztRQUM3QixPQUFPLEVBQUUsQ0FBQztJQUNaLENBQUM7SUFDRCxTQUFTO1FBQ1AsS0FBSyxDQUFDLFdBQVcsQ0FBQyxDQUFDO0lBQ3JCLENBQUM7SUFDRCxpQkFBaUI7UUFDZixLQUFLLENBQUMsbUJBQW1CLENBQUMsQ0FBQztJQUM3QixDQUFDO0lBQ0QsU0FBUztRQUNQLEtBQUssQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUNuQixPQUFPLEVBQUUsQ0FBQztJQUNaLENBQUM7SUFDRCxVQUFVO1FBQ1IsS0FBSyxDQUFDLFlBQVksQ0FBQyxDQUFDO1FBQ3BCLE9BQU8sQ0FBQyxDQUFDO0lBQ1gsQ0FBQztDQUNGLENBQUMsQ0FBQyJ9 \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/index.d.ts b/circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/index.d.ts new file mode 100644 index 00000000000..1247c354830 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/index.d.ts @@ -0,0 +1,3 @@ +export { AsyncCallState, AsyncFnState } from './async_call_state.js'; +export { WasmModule } from './wasm_module.js'; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/index.d.ts.map b/circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/index.d.ts.map new file mode 100644 index 00000000000..e4a88cedea0 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/wasm/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/index.js b/circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/index.js new file mode 100644 index 00000000000..8c9ce830550 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/index.js @@ -0,0 +1,3 @@ +export { AsyncCallState } from './async_call_state.js'; +export { WasmModule } from './wasm_module.js'; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvd2FzbS9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsY0FBYyxFQUFnQixNQUFNLHVCQUF1QixDQUFDO0FBQ3JFLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQyJ9 \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/wasm_module.d.ts b/circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/wasm_module.d.ts new file mode 100644 index 00000000000..fc3ccec5276 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/wasm_module.d.ts @@ -0,0 +1,96 @@ +/// +import { DebugLogger } from '@aztec/log'; +import { Buffer } from 'buffer'; +/** + * WasmModule: + * Helper over a webassembly module. + * Assumes a few quirks. + * 1) the module expects wasi_snapshot_preview1 with the methods from getEmptyWasiSdk + * 2) of which the webassembly + * we instantiate only uses random_get (update this if more WASI sdk methods are needed). + */ +export declare class WasmModule { + private module; + private importFn; + private memory; + private heap; + private instance?; + private mutexQ; + private debug; + /** + * Create a wasm module. Should be followed by await init();. + * @param module - The module as a WebAssembly.Module or a Buffer. + * @param importFn - Imports expected by the WASM. + * @param loggerName - Optional, for debug logging. + */ + constructor(module: WebAssembly.Module | Buffer, importFn: (module: WasmModule) => any, loggerName?: string); + /** + * Initialize this wasm module. + * @param wasmImportEnv - Linked to a module called "env". Functions implementations referenced from e.g. C++. + * @param initial - 20 pages by default. 20*2**16 \> 1mb stack size plus other overheads. + * @param maximum - 8192 maximum by default. 512mb. + */ + init(initial?: number, maximum?: number): Promise; + /** + * The methods or objects exported by the WASM module. + * @returns An indexable object. + */ + exports(): any; + /** + * Get the current logger. + * @returns Logging function. + */ + getLogger(): DebugLogger; + /** + * Add a logger. + * @param logger - Function to call when logging. + */ + addLogger(logger: DebugLogger): void; + /** + * Calls into the WebAssembly. + * @param name - The method name. + * @param args - The arguments to the method. + * @returns The numeric method result. + */ + call(name: string, ...args: any): number; + /** + * Get the memory used by the WASM module. + * @returns A WebAssembly memory object. + */ + getRawMemory(): WebAssembly.Memory; + /** + * Get the memory used by the WASM module, as a byte array. + * @returns A Uint8Array view of the WASM module memory. + */ + getMemory(): Uint8Array; + /** + * The memory size in bytes. + * @returns Number of bytes. + */ + memSize(): number; + /** + * Get a slice of memory between two addresses. + * @param start - The start address. + * @param end - The end address. + * @returns A Uint8Array view of memory. + */ + getMemorySlice(start: number, end: number): Uint8Array; + /** + * Write data into the heap. + * @param arr - The data to write. + * @param offset - The address to write data at. + */ + transferToHeap(arr: Uint8Array, offset: number): void; + /** + * When calling the wasm, sometimes a caller will require exclusive access over a series of calls. + * E.g. When a result is written to address 0, one cannot have another caller writing to the same address via + * transferToHeap before the result is read via sliceMemory. + * Acquire() gets a single token from a fifo. The caller must call release() to add the token back. + */ + acquire(): Promise; + /** + * Release the mutex, letting another promise call acquire(). + */ + release(): void; +} +//# sourceMappingURL=wasm_module.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/wasm_module.d.ts.map b/circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/wasm_module.d.ts.map new file mode 100644 index 00000000000..d759363104a --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/wasm_module.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"wasm_module.d.ts","sourceRoot":"","sources":["../../src/wasm/wasm_module.ts"],"names":[],"mappings":";AAAA,OAAO,EAAqB,WAAW,EAAE,MAAM,YAAY,CAAC;AAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAKhC;;;;;;;GAOG;AACH,qBAAa,UAAU;IAcnB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,QAAQ;IAdlB,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,IAAI,CAAc;IAC1B,OAAO,CAAC,QAAQ,CAAC,CAAuB;IACxC,OAAO,CAAC,MAAM,CAA6B;IAC3C,OAAO,CAAC,KAAK,CAAc;IAE3B;;;;;OAKG;gBAEO,MAAM,EAAE,WAAW,CAAC,MAAM,GAAG,MAAM,EACnC,QAAQ,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,GAAG,EAC7C,UAAU,SAAgB;IAM5B;;;;;OAKG;IACU,IAAI,CAAC,OAAO,SAAK,EAAE,OAAO,SAAO;IAwC9C;;;OAGG;IACI,OAAO,IAAI,GAAG;IAOrB;;;OAGG;IACI,SAAS;IAIhB;;;OAGG;IACI,SAAS,CAAC,MAAM,EAAE,WAAW;IAQpC;;;;;OAKG;IACI,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,GAAG,MAAM;IAe/C;;;OAGG;IACI,YAAY,IAAI,WAAW,CAAC,MAAM;IAGzC;;;OAGG;IACI,SAAS,IAAI,UAAU;IAQ9B;;;OAGG;IACI,OAAO,IAAI,MAAM;IAIxB;;;;;OAKG;IACI,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM;IAIhD;;;;OAIG;IACI,cAAc,CAAC,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM;IAOrD;;;;;OAKG;IACU,OAAO;IAIpB;;OAEG;IACI,OAAO;CAMf"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/wasm_module.js b/circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/wasm_module.js new file mode 100644 index 00000000000..9c48f8c5b86 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/wasm_module.js @@ -0,0 +1,181 @@ +import { createDebugLogger } from '@aztec/log'; +import { MemoryFifo } from '../memory_fifo.js'; +import { getEmptyWasiSdk } from './empty_wasi_sdk.js'; +import { randomBytes } from 'crypto'; +/** + * WasmModule: + * Helper over a webassembly module. + * Assumes a few quirks. + * 1) the module expects wasi_snapshot_preview1 with the methods from getEmptyWasiSdk + * 2) of which the webassembly + * we instantiate only uses random_get (update this if more WASI sdk methods are needed). + */ +export class WasmModule { + /** + * Create a wasm module. Should be followed by await init();. + * @param module - The module as a WebAssembly.Module or a Buffer. + * @param importFn - Imports expected by the WASM. + * @param loggerName - Optional, for debug logging. + */ + constructor(module, importFn, loggerName = 'wasm-worker') { + this.module = module; + this.importFn = importFn; + this.mutexQ = new MemoryFifo(); + this.debug = createDebugLogger(loggerName); + this.mutexQ.put(true); + } + /** + * Initialize this wasm module. + * @param wasmImportEnv - Linked to a module called "env". Functions implementations referenced from e.g. C++. + * @param initial - 20 pages by default. 20*2**16 \> 1mb stack size plus other overheads. + * @param maximum - 8192 maximum by default. 512mb. + */ + async init(initial = 20, maximum = 8192) { + this.debug(`initial mem: ${initial} pages, ${(initial * 2 ** 16) / (1024 * 1024)}mb. max mem: ${maximum} pages, ${(maximum * 2 ** 16) / (1024 * 1024)}mb`); + this.memory = new WebAssembly.Memory({ initial, maximum }); + // Create a view over the memory buffer. + // We do this once here, as webkit *seems* bugged out and actually shows this as new memory, + // thus displaying double. It's only worse if we create views on demand. I haven't established yet if + // the bug is also exasperating the termination on mobile due to "excessive memory usage". It could be + // that the OS is actually getting an incorrect reading in the same way the memory profiler does... + // The view will have to be recreated if the memory is grown. See getMemory(). + this.heap = new Uint8Array(this.memory.buffer); + // We support the wasi 12 SDK, but only implement random_get + /* eslint-disable camelcase */ + const importObj = { + wasi_snapshot_preview1: { + ...getEmptyWasiSdk(this.debug), + random_get: (arr, length) => { + arr = arr >>> 0; + const heap = this.getMemory(); + const randomData = randomBytes(length); + for (let i = arr; i < arr + length; ++i) { + heap[i] = randomData[i - arr]; + } + }, + }, + env: this.importFn(this), + }; + if (this.module instanceof WebAssembly.Module) { + this.instance = await WebAssembly.instantiate(this.module, importObj); + } + else { + const { instance } = await WebAssembly.instantiate(this.module, importObj); + this.instance = instance; + } + } + /** + * The methods or objects exported by the WASM module. + * @returns An indexable object. + */ + exports() { + if (!this.instance) { + throw new Error('WasmModule: not initialized!'); + } + return this.instance.exports; + } + /** + * Get the current logger. + * @returns Logging function. + */ + getLogger() { + return this.debug; + } + /** + * Add a logger. + * @param logger - Function to call when logging. + */ + addLogger(logger) { + const oldDebug = this.debug; + this.debug = (...args) => { + logger(...args); + oldDebug(...args); + }; + } + /** + * Calls into the WebAssembly. + * @param name - The method name. + * @param args - The arguments to the method. + * @returns The numeric method result. + */ + call(name, ...args) { + if (!this.exports()[name]) { + throw new Error(`WASM function ${name} not found.`); + } + try { + // When returning values from the WASM, use >>> operator to convert + // signed representation to unsigned representation. + return this.exports()[name](...args) >>> 0; + } + catch (err) { + const message = `WASM function ${name} aborted, error: ${err}`; + this.debug(message); + this.debug(err.stack); + throw new Error(message); + } + } + /** + * Get the memory used by the WASM module. + * @returns A WebAssembly memory object. + */ + getRawMemory() { + return this.memory; + } + /** + * Get the memory used by the WASM module, as a byte array. + * @returns A Uint8Array view of the WASM module memory. + */ + getMemory() { + // If the memory is grown, our view over it will be lost. Recreate the view. + if (this.heap.length === 0) { + this.heap = new Uint8Array(this.memory.buffer); + } + return this.heap; + } + /** + * The memory size in bytes. + * @returns Number of bytes. + */ + memSize() { + return this.getMemory().length; + } + /** + * Get a slice of memory between two addresses. + * @param start - The start address. + * @param end - The end address. + * @returns A Uint8Array view of memory. + */ + getMemorySlice(start, end) { + return this.getMemory().slice(start, end); + } + /** + * Write data into the heap. + * @param arr - The data to write. + * @param offset - The address to write data at. + */ + transferToHeap(arr, offset) { + const mem = this.getMemory(); + for (let i = 0; i < arr.length; i++) { + mem[i + offset] = arr[i]; + } + } + /** + * When calling the wasm, sometimes a caller will require exclusive access over a series of calls. + * E.g. When a result is written to address 0, one cannot have another caller writing to the same address via + * transferToHeap before the result is read via sliceMemory. + * Acquire() gets a single token from a fifo. The caller must call release() to add the token back. + */ + async acquire() { + await this.mutexQ.get(); + } + /** + * Release the mutex, letting another promise call acquire(). + */ + release() { + if (this.mutexQ.length() !== 0) { + throw new Error('Release called but not acquired.'); + } + this.mutexQ.put(true); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2FzbV9tb2R1bGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvd2FzbS93YXNtX21vZHVsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsaUJBQWlCLEVBQWUsTUFBTSxZQUFZLENBQUM7QUFFNUQsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQy9DLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUN0RCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sUUFBUSxDQUFDO0FBRXJDOzs7Ozs7O0dBT0c7QUFDSCxNQUFNLE9BQU8sVUFBVTtJQU9yQjs7Ozs7T0FLRztJQUNILFlBQ1UsTUFBbUMsRUFDbkMsUUFBcUMsRUFDN0MsVUFBVSxHQUFHLGFBQWE7UUFGbEIsV0FBTSxHQUFOLE1BQU0sQ0FBNkI7UUFDbkMsYUFBUSxHQUFSLFFBQVEsQ0FBNkI7UUFYdkMsV0FBTSxHQUFHLElBQUksVUFBVSxFQUFXLENBQUM7UUFjekMsSUFBSSxDQUFDLEtBQUssR0FBRyxpQkFBaUIsQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUMzQyxJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUN4QixDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSSxLQUFLLENBQUMsSUFBSSxDQUFDLE9BQU8sR0FBRyxFQUFFLEVBQUUsT0FBTyxHQUFHLElBQUk7UUFDNUMsSUFBSSxDQUFDLEtBQUssQ0FDUixnQkFBZ0IsT0FBTyxXQUFXLENBQUMsT0FBTyxHQUFHLENBQUMsSUFBSSxFQUFFLENBQUMsR0FBRyxDQUFDLElBQUksR0FBRyxJQUFJLENBQUMsZ0JBQWdCLE9BQU8sV0FDMUYsQ0FBQyxPQUFPLEdBQUcsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxHQUFHLENBQUMsSUFBSSxHQUFHLElBQUksQ0FDcEMsSUFBSSxDQUNMLENBQUM7UUFDRixJQUFJLENBQUMsTUFBTSxHQUFH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 \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/index.d.ts b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/index.d.ts new file mode 100644 index 00000000000..5d25ae688b9 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/index.d.ts @@ -0,0 +1,3 @@ +export * from './web_worker.js'; +export * from './web_data_store.js'; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/index.d.ts.map b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/index.d.ts.map new file mode 100644 index 00000000000..c27488b261d --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/worker/browser/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/index.js b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/index.js new file mode 100644 index 00000000000..769c36e8a11 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/index.js @@ -0,0 +1,3 @@ +export * from './web_worker.js'; +export * from './web_data_store.js'; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvd29ya2VyL2Jyb3dzZXIvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsY0FBYyxpQkFBaUIsQ0FBQztBQUNoQyxjQUFjLHFCQUFxQixDQUFDIn0= \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/start_web_module.d.ts b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/start_web_module.d.ts new file mode 100644 index 00000000000..64305a49267 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/start_web_module.d.ts @@ -0,0 +1,7 @@ +import { WasmModule } from '../../wasm/wasm_module.js'; +/** + * Start the transport server corresponding to this module. + * @param module - The WasmModule to host. + */ +export declare function startWebModule(module: WasmModule): void; +//# sourceMappingURL=start_web_module.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/start_web_module.d.ts.map b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/start_web_module.d.ts.map new file mode 100644 index 00000000000..236d51eb892 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/start_web_module.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"start_web_module.d.ts","sourceRoot":"","sources":["../../../src/worker/browser/start_web_module.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAEvD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,QAehD"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/start_web_module.js b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/start_web_module.js new file mode 100644 index 00000000000..107b51c3517 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/start_web_module.js @@ -0,0 +1,22 @@ +import { TransportServer, WorkerListener } from '../../transport/index.js'; +/** + * Start the transport server corresponding to this module. + * @param module - The WasmModule to host. + */ +export function startWebModule(module) { + const dispatch = async ({ fn, args }) => { + if (fn === '__destroyWorker__') { + transportServer.stop(); + return; + } + if (!module[fn]) { + throw new Error(`dispatch error, function not found: ${fn}`); + } + return await module[fn](...args); + }; + const transportListener = new WorkerListener(self); + const transportServer = new TransportServer(transportListener, dispatch); + module.addLogger((...args) => transportServer.broadcast({ fn: 'emit', args: ['log', ...args] })); + transportServer.start(); +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RhcnRfd2ViX21vZHVsZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy93b3JrZXIvYnJvd3Nlci9zdGFydF93ZWJfbW9kdWxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBZSxlQUFlLEVBQUUsY0FBYyxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFHeEY7OztHQUdHO0FBQ0gsTUFBTSxVQUFVLGNBQWMsQ0FBQyxNQUFrQjtJQUMvQyxNQUFNLFFBQVEsR0FBRyxLQUFLLEVBQUUsRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFlLEVBQUUsRUFBRTtRQUNuRCxJQUFJLEVBQUUsS0FBSyxtQkFBbUIsRUFBRTtZQUM5QixlQUFlLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDdkIsT0FBTztTQUNSO1FBQ0QsSUFBSSxDQUFFLE1BQWMsQ0FBQyxFQUFFLENBQUMsRUFBRTtZQUN4QixNQUFNLElBQUksS0FBSyxDQUFDLHVDQUF1QyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1NBQzlEO1FBQ0QsT0FBTyxNQUFPLE1BQWMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxDQUFDO0lBQzVDLENBQUMsQ0FBQztJQUNGLE1BQU0saUJBQWlCLEdBQUcsSUFBSSxjQUFjLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDbkQsTUFBTSxlQUFlLEdBQUcsSUFBSSxlQUFlLENBQWMsaUJBQWlCLEVBQUUsUUFBUSxDQUFDLENBQUM7SUFDdEYsTUFBTSxDQUFDLFNBQVMsQ0FBQyxDQUFDLEdBQUcsSUFBVyxFQUFFLEVBQUUsQ0FBQyxlQUFlLENBQUMsU0FBUyxDQUFDLEVBQUUsRUFBRSxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUsQ0FBQyxLQUFLLEVBQUUsR0FBRyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUN4RyxlQUFlLENBQUMsS0FBSyxFQUFFLENBQUM7QUFDMUIsQ0FBQyJ9 \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/web_data_store.d.ts b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/web_data_store.d.ts new file mode 100644 index 00000000000..9b5ab4853d9 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/web_data_store.d.ts @@ -0,0 +1,23 @@ +/// +import { DataStore } from '../data_store.js'; +/** + * Cache for data used by wasm module. + * Stores in a LevelUp database. + */ +export declare class WebDataStore implements DataStore { + private db; + constructor(); + /** + * Lookup a key. + * @param key - Key to lookup. + * @returns The buffer. + */ + get(key: string): Promise; + /** + * Alter a key. + * @param key - Key to alter. + * @param value - Buffer to store. + */ + set(key: string, value: Buffer): Promise; +} +//# sourceMappingURL=web_data_store.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/web_data_store.d.ts.map b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/web_data_store.d.ts.map new file mode 100644 index 00000000000..b786d902360 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/web_data_store.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"web_data_store.d.ts","sourceRoot":"","sources":["../../../src/worker/browser/web_data_store.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAI7C;;;GAGG;AACH,qBAAa,YAAa,YAAW,SAAS;IAC5C,OAAO,CAAC,EAAE,CAAU;;IAUpB;;;;OAIG;IACG,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAInD;;;;OAIG;IACG,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGrD"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/web_data_store.js b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/web_data_store.js new file mode 100644 index 00000000000..49f7cd14172 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/web_data_store.js @@ -0,0 +1,32 @@ +import levelup from 'levelup'; +import memdown from 'memdown'; +/** + * Cache for data used by wasm module. + * Stores in a LevelUp database. + */ +export class WebDataStore { + constructor() { + // TODO: The whole point of this is to reduce memory load in the browser. + // Replace with leveljs so the data is stored in indexeddb and not in memory. + // Hack: Cast as any to work around package "broken" with node16 resolution + // See https://github.com/microsoft/TypeScript/issues/49160 + this.db = levelup(memdown()); + } + /** + * Lookup a key. + * @param key - Key to lookup. + * @returns The buffer. + */ + async get(key) { + return await this.db.get(key).catch(() => { }); + } + /** + * Alter a key. + * @param key - Key to alter. + * @param value - Buffer to store. + */ + async set(key, value) { + await this.db.put(key, value); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2ViX2RhdGFfc3RvcmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvd29ya2VyL2Jyb3dzZXIvd2ViX2RhdGFfc3RvcmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxPQUFvQixNQUFNLFNBQVMsQ0FBQztBQUMzQyxPQUFPLE9BQU8sTUFBTSxTQUFTLENBQUM7QUFFOUI7OztHQUdHO0FBQ0gsTUFBTSxPQUFPLFlBQVk7SUFHdkI7UUFDRSx5RUFBeUU7UUFDekUsNkVBQTZFO1FBQzdFLDJFQUEyRTtRQUMzRSwyREFBMkQ7UUFDM0QsSUFBSSxDQUFDLEVBQUUsR0FBRyxPQUFPLENBQUUsT0FBZSxFQUFFLENBQUMsQ0FBQztJQUN4QyxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILEtBQUssQ0FBQyxHQUFHLENBQUMsR0FBVztRQUNuQixPQUFPLE1BQU0sSUFBSSxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUMsS0FBSyxDQUFDLEdBQUcsRUFBRSxHQUFFLENBQUMsQ0FBQyxDQUFDO0lBQ2hELENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsS0FBSyxDQUFDLEdBQUcsQ0FBQyxHQUFXLEVBQUUsS0FBYTtRQUNsQyxNQUFNLElBQUksQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsQ0FBQztJQUNoQyxDQUFDO0NBQ0YifQ== \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/web_worker.d.ts b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/web_worker.d.ts new file mode 100644 index 00000000000..d53e69632d9 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/web_worker.d.ts @@ -0,0 +1,6 @@ +import { WasmWorker } from '../wasm_worker.js'; +/** + * + */ +export declare function createWebWorker(url: string, initialMem?: number, maxMem?: number): Promise; +//# sourceMappingURL=web_worker.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/web_worker.d.ts.map b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/web_worker.d.ts.map new file mode 100644 index 00000000000..a1f0b7e1529 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/web_worker.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"web_worker.d.ts","sourceRoot":"","sources":["../../../src/worker/browser/web_worker.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C;;GAEG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAY5G"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/web_worker.js b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/web_worker.js new file mode 100644 index 00000000000..75b6479bae2 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/web_worker.js @@ -0,0 +1,19 @@ +import { WasmModule } from '../../wasm/wasm_module.js'; +import { createDispatchProxy, TransportClient, WorkerConnector } from '../../transport/index.js'; +/** + * + */ +export async function createWebWorker(url, initialMem, maxMem) { + const worker = new Worker(url); + const transportConnect = new WorkerConnector(worker); + const transportClient = new TransportClient(transportConnect); + await transportClient.open(); + const remoteModule = createDispatchProxy(WasmModule, transportClient); + remoteModule.destroyWorker = async () => { + await transportClient.request({ fn: '__destroyWorker__', args: [] }); + transportClient.close(); + }; + await remoteModule.init(initialMem, maxMem); + return remoteModule; +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2ViX3dvcmtlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy93b3JrZXIvYnJvd3Nlci93ZWJfd29ya2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUN2RCxPQUFPLEVBQUUsbUJBQW1CLEVBQWUsZUFBZSxFQUFFLGVBQWUsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBRzlHOztHQUVHO0FBQ0gsTUFBTSxDQUFDLEtBQUssVUFBVSxlQUFlLENBQUMsR0FBVyxFQUFFLFVBQW1CLEVBQUUsTUFBZTtJQUNyRixNQUFNLE1BQU0sR0FBRyxJQUFJLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUMvQixNQUFNLGdCQUFnQixHQUFHLElBQUksZUFBZSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ3JELE1BQU0sZUFBZSxHQUFHLElBQUksZUFBZSxDQUFjLGdCQUFnQixDQUFDLENBQUM7SUFDM0UsTUFBTSxlQUFlLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDN0IsTUFBTSxZQUFZLEdBQUcsbUJBQW1CLENBQUMsVUFBVSxFQUFFLGVBQWUsQ0FBZSxDQUFDO0lBQ3BGLFlBQVksQ0FBQyxhQUFhLEdBQUcsS0FBSyxJQUFJLEVBQUU7UUFDdEMsTUFBTSxlQUFlLENBQUMsT0FBTyxDQUFDLEVBQUUsRUFBRSxFQUFFLG1CQUFtQixFQUFFLElBQUksRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQ3JFLGVBQWUsQ0FBQyxLQUFLLEVBQUUsQ0FBQztJQUMxQixDQUFDLENBQUM7SUFDRixNQUFNLFlBQVksQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLE1BQU0sQ0FBQyxDQUFDO0lBQzVDLE9BQU8sWUFBWSxDQUFDO0FBQ3RCLENBQUMifQ== \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/data_store.d.ts b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/data_store.d.ts new file mode 100644 index 00000000000..0c9bd408c2d --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/data_store.d.ts @@ -0,0 +1,9 @@ +/// +/** + * Simple read/write interface for wasm modules. + */ +export interface DataStore { + get(key: string): Promise; + set(key: string, value: Buffer): Promise; +} +//# sourceMappingURL=data_store.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/data_store.d.ts.map b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/data_store.d.ts.map new file mode 100644 index 00000000000..4b0f53fd9d9 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/data_store.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"data_store.d.ts","sourceRoot":"","sources":["../../src/worker/data_store.ts"],"names":[],"mappings":";AAAA;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC9C,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAChD"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/data_store.js b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/data_store.js new file mode 100644 index 00000000000..fd170823f17 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/data_store.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0YV9zdG9yZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy93b3JrZXIvZGF0YV9zdG9yZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIn0= \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/index.d.ts b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/index.d.ts new file mode 100644 index 00000000000..f25d4249a81 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/index.d.ts @@ -0,0 +1,2 @@ +export * from './worker_pool.js'; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/index.d.ts.map b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/index.d.ts.map new file mode 100644 index 00000000000..76536aa0cf1 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/worker/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/index.js b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/index.js new file mode 100644 index 00000000000..aefc445b882 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/index.js @@ -0,0 +1,2 @@ +export * from './worker_pool.js'; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvd29ya2VyL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLGNBQWMsa0JBQWtCLENBQUMifQ== \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/index.d.ts b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/index.d.ts new file mode 100644 index 00000000000..be9811545d5 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/index.d.ts @@ -0,0 +1,3 @@ +export * from './node_worker.js'; +export * from './node_data_store.js'; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/index.d.ts.map b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/index.d.ts.map new file mode 100644 index 00000000000..a406ecf876d --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/worker/node/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/index.js b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/index.js new file mode 100644 index 00000000000..cf7a0819450 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/index.js @@ -0,0 +1,3 @@ +export * from './node_worker.js'; +export * from './node_data_store.js'; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvd29ya2VyL25vZGUvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsY0FBYyxrQkFBa0IsQ0FBQztBQUNqQyxjQUFjLHNCQUFzQixDQUFDIn0= \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/node_data_store.d.ts b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/node_data_store.d.ts new file mode 100644 index 00000000000..5908d6599bb --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/node_data_store.d.ts @@ -0,0 +1,22 @@ +/// +import { DataStore } from '../data_store.js'; +/** + * Cache for data used by wasm module. + */ +export declare class NodeDataStore implements DataStore { + private db; + constructor(path?: string); + /** + * Get a value from our DB. + * @param key - The key to look up. + * @returns The value. + */ + get(key: string): Promise; + /** + * Set a value in our DB. + * @param key - The key to update. + * @param value - The value to set. + */ + set(key: string, value: Buffer): Promise; +} +//# sourceMappingURL=node_data_store.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/node_data_store.d.ts.map b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/node_data_store.d.ts.map new file mode 100644 index 00000000000..496c69d5094 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/node_data_store.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"node_data_store.d.ts","sourceRoot":"","sources":["../../../src/worker/node/node_data_store.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAK7C;;GAEG;AACH,qBAAa,aAAc,YAAW,SAAS;IAC7C,OAAO,CAAC,EAAE,CAAU;gBAGR,IAAI,CAAC,EAAE,MAAM;IAMzB;;;;OAIG;IACG,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAInD;;;;OAIG;IACG,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGrD"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/node_data_store.js b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/node_data_store.js new file mode 100644 index 00000000000..57be391030a --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/node_data_store.js @@ -0,0 +1,31 @@ +import levelup from 'levelup'; +import leveldown from 'leveldown'; +import memdown from 'memdown'; +/** + * Cache for data used by wasm module. + */ +export class NodeDataStore { + // eslint-disable-next-line + constructor(path) { + // Hack: Cast as any to work around packages "broken" with node16 resolution + // See https://github.com/microsoft/TypeScript/issues/49160 + this.db = levelup(path ? leveldown(path) : memdown()); + } + /** + * Get a value from our DB. + * @param key - The key to look up. + * @returns The value. + */ + async get(key) { + return await this.db.get(key).catch(() => { }); + } + /** + * Set a value in our DB. + * @param key - The key to update. + * @param value - The value to set. + */ + async set(key, value) { + await this.db.put(key, value); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZV9kYXRhX3N0b3JlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3dvcmtlci9ub2RlL25vZGVfZGF0YV9zdG9yZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLE9BQW9CLE1BQU0sU0FBUyxDQUFDO0FBQzNDLE9BQU8sU0FBUyxNQUFNLFdBQVcsQ0FBQztBQUNsQyxPQUFPLE9BQU8sTUFBTSxTQUFTLENBQUM7QUFFOUI7O0dBRUc7QUFDSCxNQUFNLE9BQU8sYUFBYTtJQUd4QiwyQkFBMkI7SUFDM0IsWUFBWSxJQUFhO1FBQ3ZCLDRFQUE0RTtRQUM1RSwyREFBMkQ7UUFDM0QsSUFBSSxDQUFDLEVBQUUsR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBRSxTQUFpQixDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBRSxPQUFlLEVBQUUsQ0FBQyxDQUFDO0lBQzFFLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsS0FBSyxDQUFDLEdBQUcsQ0FBQyxHQUFXO1FBQ25CLE9BQU8sTUFBTSxJQUFJLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFLEdBQUUsQ0FBQyxDQUFDLENBQUM7SUFDaEQsQ0FBQztJQUVEOzs7O09BSUc7SUFDSCxLQUFLLENBQUMsR0FBRyxDQUFDLEdBQVcsRUFBRSxLQUFhO1FBQ2xDLE1BQU0sSUFBSSxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLEtBQUssQ0FBQyxDQUFDO0lBQ2hDLENBQUM7Q0FDRiJ9 \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/node_worker.d.ts b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/node_worker.d.ts new file mode 100644 index 00000000000..5da7e01049d --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/node_worker.d.ts @@ -0,0 +1,6 @@ +import { WasmWorker } from '../wasm_worker.js'; +/** + * + */ +export declare function createNodeWorker(filepath: string, initialMem?: number, maxMem?: number): Promise; +//# sourceMappingURL=node_worker.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/node_worker.d.ts.map b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/node_worker.d.ts.map new file mode 100644 index 00000000000..26908ec619c --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/node_worker.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"node_worker.d.ts","sourceRoot":"","sources":["../../../src/worker/node/node_worker.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAYlH"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/node_worker.js b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/node_worker.js new file mode 100644 index 00000000000..155e31ba16b --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/node_worker.js @@ -0,0 +1,21 @@ +import { Worker } from 'worker_threads'; +import { createDispatchProxy, TransportClient } from '../../transport/index.js'; +import { NodeConnector } from '../../transport/index.js'; +import { WasmModule } from '../../wasm/wasm_module.js'; +/** + * + */ +export async function createNodeWorker(filepath, initialMem, maxMem) { + const worker = new Worker(filepath); + const transportConnect = new NodeConnector(worker); + const transportClient = new TransportClient(transportConnect); + await transportClient.open(); + const remoteModule = createDispatchProxy(WasmModule, transportClient); + remoteModule.destroyWorker = async () => { + await transportClient.request({ fn: '__destroyWorker__', args: [] }); + transportClient.close(); + }; + await remoteModule.init(initialMem, maxMem); + return remoteModule; +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZV93b3JrZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvd29ya2VyL25vZGUvbm9kZV93b3JrZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ3hDLE9BQU8sRUFBRSxtQkFBbUIsRUFBZSxlQUFlLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUM3RixPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDekQsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBR3ZEOztHQUVHO0FBQ0gsTUFBTSxDQUFDLEtBQUssVUFBVSxnQkFBZ0IsQ0FBQyxRQUFnQixFQUFFLFVBQW1CLEVBQUUsTUFBZTtJQUMzRixNQUFNLE1BQU0sR0FBRyxJQUFJLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUNwQyxNQUFNLGdCQUFnQixHQUFHLElBQUksYUFBYSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ25ELE1BQU0sZUFBZSxHQUFHLElBQUksZUFBZSxDQUFjLGdCQUFnQixDQUFDLENBQUM7SUFDM0UsTUFBTSxlQUFlLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDN0IsTUFBTSxZQUFZLEdBQUcsbUJBQW1CLENBQUMsVUFBVSxFQUFFLGVBQWUsQ0FBZSxDQUFDO0lBQ3BGLFlBQVksQ0FBQyxhQUFhLEdBQUcsS0FBSyxJQUFJLEVBQUU7UUFDdEMsTUFBTSxlQUFlLENBQUMsT0FBTyxDQUFDLEVBQUUsRUFBRSxFQUFFLG1CQUFtQixFQUFFLElBQUksRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQ3JFLGVBQWUsQ0FBQyxLQUFLLEVBQUUsQ0FBQztJQUMxQixDQUFDLENBQUM7SUFDRixNQUFNLFlBQVksQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLE1BQU0sQ0FBQyxDQUFDO0lBQzVDLE9BQU8sWUFBWSxDQUFDO0FBQ3RCLENBQUMifQ== \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/start_node_module.d.ts b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/start_node_module.d.ts new file mode 100644 index 00000000000..c118c248f46 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/start_node_module.d.ts @@ -0,0 +1,7 @@ +import { WasmModule } from '../../wasm/wasm_module.js'; +/** + * Start the transport server corresponding to this module. + * @param module - The WasmModule to host. + */ +export declare function startNodeModule(module: WasmModule): void; +//# sourceMappingURL=start_node_module.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/start_node_module.d.ts.map b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/start_node_module.d.ts.map new file mode 100644 index 00000000000..f006976f41e --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/start_node_module.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"start_node_module.d.ts","sourceRoot":"","sources":["../../../src/worker/node/start_node_module.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAMvD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,UAAU,QAejD"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/start_node_module.js b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/start_node_module.js new file mode 100644 index 00000000000..8d4aee385db --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/start_node_module.js @@ -0,0 +1,26 @@ +import { parentPort } from 'worker_threads'; +import { NodeListener, TransportServer } from '../../transport/index.js'; +if (!parentPort) { + throw new Error('InvalidWorker'); +} +/** + * Start the transport server corresponding to this module. + * @param module - The WasmModule to host. + */ +export function startNodeModule(module) { + const dispatch = async ({ fn, args }) => { + if (fn === '__destroyWorker__') { + transportServer.stop(); + return; + } + if (!module[fn]) { + throw new Error(`dispatch error, function not found: ${fn}`); + } + return await module[fn](...args); + }; + const transportListener = new NodeListener(); + const transportServer = new TransportServer(transportListener, dispatch); + module.addLogger((...args) => transportServer.broadcast({ fn: 'emit', args: ['log', ...args] })); + transportServer.start(); +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RhcnRfbm9kZV9tb2R1bGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvd29ya2VyL25vZGUvc3RhcnRfbm9kZV9tb2R1bGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzVDLE9BQU8sRUFBRSxZQUFZLEVBQWUsZUFBZSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFHdEYsSUFBSSxDQUFDLFVBQVUsRUFBRTtJQUNmLE1BQU0sSUFBSSxLQUFLLENBQUMsZUFBZSxDQUFDLENBQUM7Q0FDbEM7QUFFRDs7O0dBR0c7QUFDSCxNQUFNLFVBQVUsZUFBZSxDQUFDLE1BQWtCO0lBQ2hELE1BQU0sUUFBUSxHQUFHLEtBQUssRUFBRSxFQUFFLEVBQUUsRUFBRSxJQUFJLEVBQWUsRUFBRSxFQUFFO1FBQ25ELElBQUksRUFBRSxLQUFLLG1CQUFtQixFQUFFO1lBQzlCLGVBQWUsQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUN2QixPQUFPO1NBQ1I7UUFDRCxJQUFJLENBQUUsTUFBYyxDQUFDLEVBQUUsQ0FBQyxFQUFFO1lBQ3hCLE1BQU0sSUFBSSxLQUFLLENBQUMsdUNBQXVDLEVBQUUsRUFBRSxDQUFDLENBQUM7U0FDOUQ7UUFDRCxPQUFPLE1BQU8sTUFBYyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUM7SUFDNUMsQ0FBQyxDQUFDO0lBQ0YsTUFBTSxpQkFBaUIsR0FBRyxJQUFJLFlBQVksRUFBRSxDQUFDO0lBQzdDLE1BQU0sZUFBZSxHQUFHLElBQUksZUFBZSxDQUFjLGlCQUFpQixFQUFFLFFBQVEsQ0FBQyxDQUFDO0lBQ3RGLE1BQU0sQ0FBQyxTQUFTLENBQUMsQ0FBQyxHQUFHLElBQVcsRUFBRSxFQUFFLENBQUMsZUFBZSxDQUFDLFNBQVMsQ0FBQyxFQUFFLEVBQUUsRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFLENBQUMsS0FBSyxFQUFFLEdBQUcsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDeEcsZUFBZSxDQUFDLEtBQUssRUFBRSxDQUFDO0FBQzFCLENBQUMifQ== \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/wasm_worker.d.ts b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/wasm_worker.d.ts new file mode 100644 index 00000000000..5796d84ec9e --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/wasm_worker.d.ts @@ -0,0 +1,9 @@ +import { Proxify } from '../transport/index.js'; +import { WasmModule } from '../wasm/wasm_module.js'; +/** + * Represents either a WASM web worker, or node.js worker. + */ +export type WasmWorker = Proxify & { + destroyWorker(): void; +}; +//# sourceMappingURL=wasm_worker.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/wasm_worker.d.ts.map b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/wasm_worker.d.ts.map new file mode 100644 index 00000000000..111acb92bbc --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/wasm_worker.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"wasm_worker.d.ts","sourceRoot":"","sources":["../../src/worker/wasm_worker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEpD;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,GAAG;IAAE,aAAa,IAAI,IAAI,CAAA;CAAE,CAAC"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/wasm_worker.js b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/wasm_worker.js new file mode 100644 index 00000000000..a886d8ce72e --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/wasm_worker.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2FzbV93b3JrZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvd29ya2VyL3dhc21fd29ya2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiIifQ== \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/worker_pool.d.ts b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/worker_pool.d.ts new file mode 100644 index 00000000000..62f2d879877 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/worker_pool.d.ts @@ -0,0 +1,40 @@ +import { WasmWorker } from './wasm_worker.js'; +/** + * Type of a worker factory. + * Used to customize WorkerPool worker construction. + */ +export type CreateWorker = (name: string, minMem: number, maxMem: number) => WasmWorker; +/** + * Allocates a pool of WasmWorker's. + * Worker 0 is allocated MAX_PAGES memory pages. This is because worker 0 will need to hold the proving key + * (i.e. Has state), whereas the others are pure compute (they hold a little crs state). + */ +export declare class WorkerPool { + /** + * The maximum number of memory pages to be used by the webassembly. + */ + static MAX_PAGES: number; + /** + * The workers in the pool. + */ + private workers; + /** + * Create an instance and initialize the workers. + * @param createWorker - Worker factory. + * @param poolSize - Pool size. + * @returns An initialized WorkerPool. + */ + static new(createWorker: CreateWorker, poolSize: number): Promise; + /** + * Initialize the workers. + * @param createWorker - Worker factory(). + * @param poolSize - Pool size. + * @param maxMem - Max memory pages. + */ + init(createWorker: CreateWorker, poolSize: number, maxMem?: number): Promise; + /** + * Tell all workers in the pool to stop processing. + */ + destroy(): Promise; +} +//# sourceMappingURL=worker_pool.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/worker_pool.d.ts.map b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/worker_pool.d.ts.map new file mode 100644 index 00000000000..118733d8c5c --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/worker_pool.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"worker_pool.d.ts","sourceRoot":"","sources":["../../src/worker/worker_pool.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAI9C;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,UAAU,CAAC;AACxF;;;;GAIG;AACH,qBAAa,UAAU;IAYrB;;OAEG;IACH,OAAc,SAAS,SAAQ;IAC/B;;OAEG;IACH,OAAO,CAAC,OAAO,CAAoB;IAEnC;;;;;OAKG;WACU,GAAG,CAAC,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM;IAM7D;;;;;OAKG;IACU,IAAI,CAAC,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,SAAuB;IAY7F;;OAEG;IACU,OAAO;CAGrB"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/worker_pool.js b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/worker_pool.js new file mode 100644 index 00000000000..bddeb77620d --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/worker_pool.js @@ -0,0 +1,62 @@ +import { createDebugLogger } from '@aztec/log'; +const debug = createDebugLogger('bb:worker_pool'); +/** + * Allocates a pool of WasmWorker's. + * Worker 0 is allocated MAX_PAGES memory pages. This is because worker 0 will need to hold the proving key + * (i.e. Has state), whereas the others are pure compute (they hold a little crs state). + */ +export class WorkerPool { + constructor() { + /** + * The workers in the pool. + */ + this.workers = []; + } + /** + * Create an instance and initialize the workers. + * @param createWorker - Worker factory. + * @param poolSize - Pool size. + * @returns An initialized WorkerPool. + */ + static async new(createWorker, poolSize) { + const pool = new WorkerPool(); + await pool.init(createWorker, poolSize); + return pool; + } + /** + * Initialize the workers. + * @param createWorker - Worker factory(). + * @param poolSize - Pool size. + * @param maxMem - Max memory pages. + */ + async init(createWorker, poolSize, maxMem = WorkerPool.MAX_PAGES) { + debug(`creating ${poolSize} workers...`); + const start = new Date().getTime(); + this.workers = await Promise.all(Array(poolSize) + .fill(0) + .map((_, i) => createWorker(`${i}`, i === 0 ? Math.min(WorkerPool.MAX_PAGES, maxMem) : 768, maxMem))); + debug(`created workers: ${new Date().getTime() - start}ms`); + } + /** + * Tell all workers in the pool to stop processing. + */ + async destroy() { + await Promise.all(this.workers.map(w => w.destroyWorker())); + } +} +// TODO(AD): Revisit what this means in aztec 3 context +// -- +// Introduction of low mem prover work (polynomial cache) may actually increase mem usage when the backing store isn't +// enabled. We were seeing intermittent failings related to memory in production for some users when limiting to +// 6660 (416MB). It would be nice to understand why this is (the non determinism and/or the increased mem usage). +// For now, increasing mem usage to 512MB. This maybe preferable to backing out the low mem work, but +// ironically may break the chance of us using it in mobile. +// We *could* enable the low memory backing store, but this needs a little bit of work to actually +// read/write from indexeddb, performance testing, and actual further memory load testing. +// At this point it's hard to know what our memory savings would be relative to just fully reverting the LMP. +// public static MAX_PAGES = 6660; +/** + * The maximum number of memory pages to be used by the webassembly. + */ +WorkerPool.MAX_PAGES = 8192; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid29ya2VyX3Bvb2wuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvd29ya2VyL3dvcmtlcl9wb29sLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLFlBQVksQ0FBQztBQUcvQyxNQUFNLEtBQUssR0FBRyxpQkFBaUIsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO0FBT2xEOzs7O0dBSUc7QUFDSCxNQUFNLE9BQU8sVUFBVTtJQUF2QjtRQWdCRTs7V0FFRztRQUNLLFlBQU8sR0FBaUIsRUFBRSxDQUFDO0lBc0NyQyxDQUFDO0lBcENDOzs7OztPQUtHO0lBQ0gsTUFBTSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsWUFBMEIsRUFBRSxRQUFnQjtRQUMzRCxNQUFNLElBQUksR0FBRyxJQUFJLFVBQVUsRUFBRSxDQUFDO1FBQzlCLE1BQU0sSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLEVBQUUsUUFBUSxDQUFDLENBQUM7UUFDeEMsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSSxLQUFLLENBQUMsSUFBSSxDQUFDLFlBQTBCLEVBQUUsUUFBZ0IsRUFBRSxNQUFNLEdBQUcsVUFBVSxDQUFDLFNBQVM7UUFDM0YsS0FBSyxDQUFDLFlBQVksUUFBUSxhQUFhLENBQUMsQ0FBQztRQUN6QyxNQUFNLEtBQUssR0FBRyxJQUFJLElBQUksRUFBRSxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ25DLElBQUksQ0FBQyxPQUFPLEdBQUcsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUM5QixLQUFLLENBQUMsUUFBUSxDQUFDO2FBQ1osSUFBSSxDQUFDLENBQUMsQ0FBQzthQUNQLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLFlBQVksQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLFNBQVMsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQ3ZHLENBQUM7UUFFRixLQUFLLENBQUMsb0JBQW9CLElBQUksSUFBSSxFQUFFLENBQUMsT0FBTyxFQUFFLEdBQUcsS0FBSyxJQUFJLENBQUMsQ0FBQztJQUM5RCxDQUFDO0lBRUQ7O09BRUc7SUFDSSxLQUFLLENBQUMsT0FBTztRQUNsQixNQUFNLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsYUFBYSxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQzlELENBQUM7O0FBdkRELHVEQUF1RDtBQUN2RCxLQUFLO0FBQ0wsc0hBQXNIO0FBQ3RILGdIQUFnSDtBQUNoSCxpSEFBaUg7QUFDakgscUdBQXFHO0FBQ3JHLDREQUE0RDtBQUM1RCxrR0FBa0c7QUFDbEcsMEZBQTBGO0FBQzFGLDZHQUE2RztBQUM3RyxrQ0FBa0M7QUFDbEM7O0dBRUc7QUFDVyxvQkFBUyxHQUFHLElBQUksQ0FBQyJ9 \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/package.json b/circuits/ts/.yalc/@aztec/wasm-worker/package.json new file mode 100644 index 00000000000..5e83098e655 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/package.json @@ -0,0 +1,42 @@ +{ + "name": "@aztec/wasm-worker", + "version": "0.0.0", + "type": "module", + "exports": "./dest/index.js", + "typedoc": { + "entryPoint": "./src/index.ts", + "displayName": "wasm-worker", + "tsconfig": "./tsconfig.dest.json" + }, + "scripts": { + "build": "yarn clean && yarn formatting && tsc -b tsconfig.dest.json", + "build:dev": "tsc -b tsconfig.dest.json --watch", + "clean": "rm -rf ./dest .tsbuildinfo", + "fix-eslint": "run -T eslint --fix ./src", + "formatting": "run -T prettier --check ./src && run -T eslint --max-warnings 53 ./src", + "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --no-cache --passWithNoTests" + }, + "jest": { + "preset": "ts-jest/presets/default-esm", + "globals": { + "ts-jest": { + "useESM": true + } + }, + "moduleNameMapper": { + "^(\\.{1,2}/.*)\\.js$": "$1" + }, + "testRegex": "./src/.*\\.test\\.ts$", + "rootDir": "./src" + }, + "dependencies": { + "@aztec/log": "*", + "@types/leveldown": "^4.0.3", + "detect-node": "^2.1.0", + "leveldown": "^6.1.1", + "levelup": "^5.1.1", + "memdown": "^6.1.1", + "tslib": "^2.4.0" + }, + "yalcSig": "c3f323629c42198a64e1e6969247e19a" +} diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/index.ts b/circuits/ts/.yalc/@aztec/wasm-worker/src/index.ts new file mode 100644 index 00000000000..ac5d9214c36 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/src/index.ts @@ -0,0 +1,5 @@ +export { WebDataStore } from './worker/browser/index.js'; +export { NodeDataStore } from './worker/node/index.js'; + +export { WasmModule } from './wasm/index.js'; +export { AsyncCallState, AsyncFnState } from './wasm/index.js'; diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/memory_fifo.ts b/circuits/ts/.yalc/@aztec/wasm-worker/src/memory_fifo.ts new file mode 100644 index 00000000000..03dc63d93ee --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/src/memory_fifo.ts @@ -0,0 +1,104 @@ +// TODO should come from a dependency +/** + * A simple fifo queue. It can grow unbounded. It can have multiple producers and consumers. + * Putting an item onto the queue always succeeds, unless either end() or cancel() has been called in which case + * the item being pushed is simply discarded. + */ +export class MemoryFifo { + private waiting: ((item: T | null) => void)[] = []; + private items: T[] = []; + private flushing = false; + + /** + * Length of queue. + * @returns integer. + */ + public length() { + return this.items.length; + } + + /** + * Returns next item within the queue, or blocks until and item has been put into the queue. + * If given a timeout, the promise will reject if no item is received after `timeout` seconds. + * If the queue is flushing, `null` is returned. + * @param timeout - In seconds. + * @returns Promise of result. + */ + public get(timeout?: number): Promise { + if (this.items.length) { + return Promise.resolve(this.items.shift()!); + } + + if (this.items.length === 0 && this.flushing) { + return Promise.resolve(null); + } + + return new Promise((resolve, reject) => { + this.waiting.push(resolve); + + if (timeout) { + setTimeout(() => { + const index = this.waiting.findIndex(r => r === resolve); + if (index > -1) { + this.waiting.splice(index, 1); + const err = new Error('Timeout getting item from queue.'); + reject(err); + } + }, timeout * 1000); + } + }); + } + + /** + * Put an item onto back of the queue. + * @param item - The item to enqueue. + */ + public put(item: T) { + if (this.flushing) { + return; + } else if (this.waiting.length) { + this.waiting.shift()!(item); + } else { + this.items.push(item); + } + } + + /** + * Once ended, no further items are added to queue. Consumers will consume remaining items within the queue. + * The queue is not reusable after calling `end()`. + * Any consumers waiting for an item receive null. + */ + public end() { + this.flushing = true; + this.waiting.forEach(resolve => resolve(null)); + } + + /** + * Once cancelled, all items are discarded from the queue, and no further items are added to the queue. + * The queue is not reusable after calling `cancel()`. + * Any consumers waiting for an item receive null. + */ + public cancel() { + this.flushing = true; + this.items = []; + this.waiting.forEach(resolve => resolve(null)); + } + + /** + * Helper method that can be used to continously consume and process items on the queue. + * @param handler - The item handler function. + */ + public async process(handler: (item: T) => Promise) { + try { + while (true) { + const item = await this.get(); + if (item === null) { + break; + } + await handler(item); + } + } catch (err) { + console.error('Queue handler exception:', err); + } + } +} diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/test/gcd.wasm b/circuits/ts/.yalc/@aztec/wasm-worker/src/test/gcd.wasm new file mode 100644 index 0000000000000000000000000000000000000000..19a859c306c3acf6de25eef3ea26711d05e783bb GIT binary patch literal 76 zcmWN@!3lsc5Cp*8&Evo`JzRW>MWmF7f-ga^fNNdnHQ3*q0B9V_WEK%-EZ1=Y)5eud Xb@f0+uxX~39t { + this.port.postMessage(msg, transfer); + return Promise.resolve(); + } + + /** + * Add a message handler. + * @param cb - The handler. + */ + registerHandler(cb: (msg: any) => any): void { + this.port.onmessage = event => cb(event.data); + } + + /** + * Close this message port. + */ + close() { + void this.send(undefined); + this.port.onmessage = null; + this.port.close(); + } +} diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/browser/shared_worker_connector.ts b/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/browser/shared_worker_connector.ts new file mode 100644 index 00000000000..d6167961760 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/browser/shared_worker_connector.ts @@ -0,0 +1,21 @@ +import { Connector } from '../interface/connector.js'; +import { MessagePortSocket } from './message_port_socket.js'; + +/** + * Connector implementation which wraps a SharedWorker. + */ +export class SharedWorkerConnector implements Connector { + /** + * Create a SharedWorkerConnector. + * @param worker - A shared worker. + */ + constructor(private worker: SharedWorker) {} + + /** + * Create a Socket implementation with our mesage port. + * @returns The socket. + */ + createSocket() { + return Promise.resolve(new MessagePortSocket(this.worker.port)); + } +} diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/browser/shared_worker_listener.ts b/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/browser/shared_worker_listener.ts new file mode 100644 index 00000000000..cafd280e6e6 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/browser/shared_worker_listener.ts @@ -0,0 +1,52 @@ +import EventEmitter from 'events'; +import { Listener } from '../interface/listener.js'; +import { MessagePortSocket } from './message_port_socket.js'; + +/** + * See https://developer.mozilla.org/en-US/docs/Web/API/SharedWorkerGlobalScope. + */ +declare interface SharedWorkerGlobalScope { + /** + * Fired on shared workers when a new client connects. + */ + onconnect: any; +} + +/** + * Listens for connections to a shared worker. + */ +export class SharedWorkerListener extends EventEmitter implements Listener { + /** + * + * @param worker + */ + constructor(private worker: SharedWorkerGlobalScope) { + super(); + } + + /** + * + */ + open() { + this.worker.onconnect = this.handleMessageEvent; + } + + /** + * + */ + close() { + this.worker.onconnect = () => {}; + } + + /** + * + * @param event + */ + private handleMessageEvent = (event: MessageEvent) => { + const [port] = event.ports; + if (!port) { + return; + } + this.emit('new_socket', new MessagePortSocket(port)); + }; +} diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/browser/worker_connector.ts b/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/browser/worker_connector.ts new file mode 100644 index 00000000000..fbfc7efd22e --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/browser/worker_connector.ts @@ -0,0 +1,22 @@ +import { Connector } from '../interface/connector.js'; +import { MessagePortSocket } from './message_port_socket.js'; + +/** + * + */ +export class WorkerConnector implements Connector { + /** + * + * @param worker + */ + constructor(private worker: Worker) {} + + /** + * + */ + createSocket() { + const channel = new MessageChannel(); + this.worker.postMessage('', [channel.port2]); + return Promise.resolve(new MessagePortSocket(channel.port1)); + } +} diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/browser/worker_listener.ts b/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/browser/worker_listener.ts new file mode 100644 index 00000000000..201b3a68573 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/browser/worker_listener.ts @@ -0,0 +1,52 @@ +import EventEmitter from 'events'; +import { Listener } from '../interface/listener.js'; +import { MessagePortSocket } from './message_port_socket.js'; + +/** + * + */ +declare interface DedicatedWorkerGlobalScope { + /** + * + */ + onmessage: any; +} + +/** + * + */ +export class WorkerListener extends EventEmitter implements Listener { + /** + * + * @param worker + */ + constructor(private worker: DedicatedWorkerGlobalScope) { + super(); + } + + /** + * + */ + open() { + this.worker.onmessage = this.handleMessageEvent; + } + + /** + * + */ + close() { + this.worker.onmessage = () => {}; + } + + /** + * + * @param event + */ + private handleMessageEvent = (event: MessageEvent) => { + const [port] = event.ports; + if (!port) { + return; + } + this.emit('new_socket', new MessagePortSocket(port)); + }; +} diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/dispatch/create_dispatch_fn.ts b/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/dispatch/create_dispatch_fn.ts new file mode 100644 index 00000000000..6e23e25a25f --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/dispatch/create_dispatch_fn.ts @@ -0,0 +1,24 @@ +/** + * + */ +export interface DispatchMsg { + /** + * + */ + fn: string; + /** + * + */ + args: any[]; +} + +/** + * + */ +export function createDispatchFn(targetFn: () => any, debug = console.error) { + return async ({ fn, args }: DispatchMsg) => { + const target = targetFn(); + debug(`dispatching to ${target}: ${fn}`, args); + return await target[fn](...args); + }; +} diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/dispatch/create_dispatch_proxy.ts b/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/dispatch/create_dispatch_proxy.ts new file mode 100644 index 00000000000..e9538448d3d --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/dispatch/create_dispatch_proxy.ts @@ -0,0 +1,88 @@ +import { DispatchMsg } from './create_dispatch_fn.js'; +import { TransportClient } from '../transport_client.js'; +import { EventEmitter } from 'events'; +import { isTransferDescriptor, TransferDescriptor } from '../interface/transferable.js'; + +type FilterOutAttributes = { + [Key in keyof Base]: Base[Key] extends (...args: any) => any ? Base[Key] : never; +}; + +type PromisifyFunction any> = (...args: Parameters) => Promise>; + +type Promisify any }> = { + [Key in keyof Base]: ReturnType extends Promise ? Base[Key] : PromisifyFunction; +}; + +/** + * Unpack transfer types + */ +type TransferTypes = { + [Index in keyof Tuple]: Tuple[Index] | (Tuple[Index] extends Transferable ? TransferDescriptor : never); +}; + +/** + * Annoying: https://github.com/microsoft/TypeScript/issues/29919 + * There's a bug that means we can't map over the tuple or function parameter types to make them transferrable, if + * we use the Parameters builtin, and then try to map. + * So instead we inline the Parameters builtin and apply the TransferTypes to the parameters within the inline. + * Once the above is fixed we could in theory just do: + * + * type MakeFunctionTransferrable any> = ( + * ...args: TransferTypes> + * ) => ReturnType;. + */ +type MakeFunctionTransferrable any> = ( + ...args: TFunction extends (...args: infer P) => any ? TransferTypes

: never +) => ReturnType; + +type Transferrable any }> = { + [Key in keyof Base]: MakeFunctionTransferrable; +}; + +export type Proxify = Promisify>>; + +export function createDispatchProxyFromFn( + class_: { new (...args: any[]): T }, + requestFn: (fn: string) => (...args: any[]) => Promise, +): Proxify { + const proxy: any = class_.prototype instanceof EventEmitter ? new EventEmitter() : {}; + for (const fn of Object.getOwnPropertyNames(class_.prototype)) { + if (fn === 'constructor') { + continue; + } + proxy[fn] = requestFn(fn); + } + return proxy; +} + +/** + * Create a proxy object of our class T that uses transportClient + * @param class_ - Our class T. + * @param transportClient - The transport infrastructure. + * @returns A proxy over T. + */ +export function createDispatchProxy( + class_: { new (...args: any[]): T }, + transportClient: TransportClient, +): Proxify { + // Create a proxy of class_ that passes along methods over our transportClient + const proxy = createDispatchProxyFromFn(class_, (fn: string) => (...args: any[]) => { + // Pass our proxied function name and arguments over our transport client + const transfer: Transferable[] = args.reduce( + (acc, a) => (isTransferDescriptor(a) ? [...acc, ...a.transferables] : acc), + [] as Transferable[], + ); + args = args.map(a => (isTransferDescriptor(a) ? a.send : a)); + return transportClient.request({ fn, args }, transfer); + }); + if (proxy instanceof EventEmitter) { + // Handle proxied 'emit' calls if our proxy object is an EventEmitter + transportClient.on('event_msg', ({ fn, args }) => { + if (fn === 'emit') { + const [eventName, ...restArgs] = args; + proxy.emit(eventName, ...restArgs); + } + }); + } + return proxy; +} diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/dispatch/messages.ts b/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/dispatch/messages.ts new file mode 100644 index 00000000000..49704dbde84 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/dispatch/messages.ts @@ -0,0 +1,51 @@ +/** + * Represents a transport bus request. + */ +export interface RequestMessage { + /** + * The message ID. + */ + msgId: number; + /** + * The data. + */ + payload: Payload; +} + +/** + * Represents a transport bus response. + */ +export interface ResponseMessage { + /** + * The message ID. + */ + msgId: number; + /** + * The data. + */ + payload?: Payload; + /** + * The error, if any. + */ + error?: string; +} + +/** + * A message stemming from an event. + */ +export interface EventMessage { + /** + * The event data. + */ + payload: Payload; +} + +/** + * Is this an event message? + * @returns If the msgId was blank. + */ +export function isEventMessage( + msg: ResponseMessage | EventMessage, +): msg is EventMessage { + return (msg as ResponseMessage).msgId === undefined; +} diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/index.ts b/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/index.ts new file mode 100644 index 00000000000..1ea1f8c30cf --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/index.ts @@ -0,0 +1,11 @@ +export * from './dispatch/create_dispatch_fn.js'; +export * from './dispatch/create_dispatch_proxy.js'; +export * from './dispatch/messages.js'; +export * from './interface/connector.js'; +export * from './interface/listener.js'; +export * from './interface/socket.js'; +export * from './interface/transferable.js'; +export * from './transport_client.js'; +export * from './transport_server.js'; +export * from './browser/index.js'; +export * from './node/index.js'; diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/interface/connector.ts b/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/interface/connector.ts new file mode 100644 index 00000000000..9d72f6574f7 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/interface/connector.ts @@ -0,0 +1,8 @@ +import { Socket } from './socket.js'; + +/** + * Opens a socket with corresponding TransportListener. + */ +export interface Connector { + createSocket(): Promise; +} diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/interface/listener.ts b/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/interface/listener.ts new file mode 100644 index 00000000000..b6e533570a7 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/interface/listener.ts @@ -0,0 +1,14 @@ +import EventEmitter from 'events'; +import { Socket } from './socket.js'; + +/** + * Once opened, an implementation of a TransportListener will emit `new_socket` events as new clients connect. + * Possible implementations could include MessageChannels or WebSockets. + */ +export interface Listener extends EventEmitter { + open(): void; + + close(): void; + + on(name: 'new_socket', cb: (client: Socket) => void): this; +} diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/interface/socket.ts b/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/interface/socket.ts new file mode 100644 index 00000000000..6da7ca436ed --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/interface/socket.ts @@ -0,0 +1,12 @@ +/** + * Represents one end of a socket connection. + * A message sent via `send` will be handled by the corresponding Socket's handler function at the other end. + * Implementations could use e.g. MessagePorts for communication between browser workers, + * or WebSockets for communication between processes. + * If `registerHandler` callback receives `undefined` that signals the other end closed. + */ +export interface Socket { + send(msg: any, transfer?: Transferable[]): Promise; + registerHandler(cb: (msg: any) => any): void; + close(): void; +} diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/interface/transferable.ts b/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/interface/transferable.ts new file mode 100644 index 00000000000..3ce8c59b320 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/interface/transferable.ts @@ -0,0 +1,92 @@ +const $transferable = Symbol('thread.transferable'); + +/** + * A descriptor representing a payload with transferable components. + * These components will have ownership transfered when published on an event bus. + */ +export interface TransferDescriptor { + /** + * Marked as transferable. + */ + [$transferable]: true; + /** + * The payload with the transferable objects. + */ + send: T; + /** + * The objects to transfer. + */ + transferables: Transferable[]; +} + +/** + * + */ +function isTransferable(thing: any): thing is Transferable { + if (!thing || typeof thing !== 'object') return false; + // Don't check too thoroughly, since the list of transferable things in JS might grow over time + return true; +} + +/** + * + */ +export function isTransferDescriptor(thing: any): thing is TransferDescriptor { + return thing && typeof thing === 'object' && thing[$transferable]; +} + +/** + * Mark a transferable object as such, so it will no be serialized and + * deserialized on messaging with the main thread, but to transfer + * ownership of it to the receiving thread. + * + * Only works with array buffers, message ports and few more special + * types of objects, but it's much faster than serializing and + * deserializing them. + * + * Note: + * The transferable object cannot be accessed by this thread again + * unless the receiving thread transfers it back again! + * + * @param transferable - Array buffer, message port or similar. + * @see https://developers.google.com/web/updates/2011/12/Transferable-Objects-Lightning-Fast + */ +export function Transfer(transferable: Transferable): TransferDescriptor; + +/** + * Mark transferable objects within an arbitrary object or array as + * being a transferable object. They will then not be serialized + * and deserialized on messaging with the main thread, but ownership + * of them will be tranferred to the receiving thread. + * + * Only array buffers, message ports and few more special types of + * objects can be transferred, but it's much faster than serializing and + * deserializing them. + * + * Note: + * The transferable object cannot be accessed by this thread again + * unless the receiving thread transfers it back again! + * + * @param transferable - Array buffer, message port or similar. + * @see https://developers.google.com/web/updates/2011/12/Transferable-Objects-Lightning-Fast + */ +export function Transfer(payload: T, transferables: Transferable[]): TransferDescriptor; + +/** + * Create a transfer descriptor, marking these as transferable. + * @param payload - The payload. + * @param transferables - The transferable objects. + * @returns The descriptor. + */ +export function Transfer(payload: T, transferables?: Transferable[]): TransferDescriptor { + if (!transferables) { + if (!isTransferable(payload)) throw Error(); + transferables = [payload]; + } + + return { + [$transferable]: true, + send: payload, + transferables, + }; +} diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/node/index.ts b/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/node/index.ts new file mode 100644 index 00000000000..cf87befc85e --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/node/index.ts @@ -0,0 +1,2 @@ +export * from './node_connector.js'; +export * from './node_listener.js'; diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/node/node_connector.ts b/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/node/node_connector.ts new file mode 100644 index 00000000000..bf74c2a5d72 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/node/node_connector.ts @@ -0,0 +1,18 @@ +import { Worker } from 'worker_threads'; +import { Connector } from '../interface/connector.js'; +import { NodeConnectorSocket } from './node_connector_socket.js'; + +/** + * Creates sockets backed by a Node worker. + */ +export class NodeConnector implements Connector { + constructor(private worker: Worker) {} + + /** + * Creates a socket backed by a node worker. + * @returns The socket. + */ + createSocket() { + return Promise.resolve(new NodeConnectorSocket(this.worker)); + } +} diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/node/node_connector_socket.ts b/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/node/node_connector_socket.ts new file mode 100644 index 00000000000..39b1b2e04b4 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/node/node_connector_socket.ts @@ -0,0 +1,36 @@ +import { TransferListItem, Worker } from 'worker_threads'; +import { Socket } from '../interface/socket.js'; + +/** + * A socket implementation using a Node worker. + */ +export class NodeConnectorSocket implements Socket { + constructor(private worker: Worker) {} + + /** + * Send a message. + * @param msg - The message. + * @param transfer - Objects to transfer ownership of. + * @returns A void promise. + */ + send(msg: any, transfer: Transferable[] = []): Promise { + this.worker.postMessage(msg, transfer as TransferListItem[]); + return Promise.resolve(); + } + + /** + * Register a message handler. + * @param cb - The handler function. + */ + registerHandler(cb: (msg: any) => any): void { + this.worker.on('message', cb); + } + + /** + * Remove all listeners from our worker. + */ + close() { + void this.send(undefined); + this.worker.removeAllListeners(); + } +} diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/node/node_listener.ts b/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/node/node_listener.ts new file mode 100644 index 00000000000..92c753410fb --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/node/node_listener.ts @@ -0,0 +1,25 @@ +import { parentPort } from 'worker_threads'; +import EventEmitter from 'events'; +import { Listener } from '../interface/listener.js'; +import { NodeListenerSocket } from './node_listener_socket.js'; + +/** + * A socket listener that works with Node. + */ +export class NodeListener extends EventEmitter implements Listener { + constructor() { + super(); + } + + /** + * Open the listener. + */ + open() { + this.emit('new_socket', new NodeListenerSocket(parentPort as any)); + } + + /** + * Close the listener. + */ + close() {} +} diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/node/node_listener_socket.ts b/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/node/node_listener_socket.ts new file mode 100644 index 00000000000..d492d45c602 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/node/node_listener_socket.ts @@ -0,0 +1,37 @@ +import { MessagePort, TransferListItem } from 'worker_threads'; +import { Socket } from '../interface/socket.js'; + +/** + * An implementation of a TransportSocket using MessagePorts. + */ +export class NodeListenerSocket implements Socket { + constructor(private port: MessagePort) {} + + /** + * Send a message over this port. + * @param msg - The message. + * @param transfer - Transferable objects. + * @returns A void promise. + */ + send(msg: any, transfer: Transferable[] = []): Promise { + this.port.postMessage(msg, transfer as TransferListItem[]); + return Promise.resolve(); + } + + /** + * Add a handler to this port. + * @param cb - The handler function. + */ + registerHandler(cb: (msg: any) => any): void { + this.port.on('message', cb); + } + + /** + * Close this socket. + */ + close() { + void this.send(undefined); + this.port.removeAllListeners(); + this.port.close(); + } +} diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/transport_client.ts b/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/transport_client.ts new file mode 100644 index 00000000000..5577d7a5ed5 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/transport_client.ts @@ -0,0 +1,106 @@ +import { createDebugLogger } from '@aztec/log'; +import EventEmitter from 'events'; +import { EventMessage, isEventMessage, ResponseMessage } from './dispatch/messages.js'; +import { Connector } from './interface/connector.js'; +import { Socket } from './interface/socket.js'; + +const debug = createDebugLogger('aztec:transport_client'); + +/** + * A pending request. + */ +interface PendingRequest { + /** + * The message ID. + */ + msgId: number; + resolve(data: any): void; + reject(error: Error): void; +} + +/** + * Augments the TransportClient class with more precise EventEmitter types. + */ +export interface TransportClient extends EventEmitter { + on(name: 'event_msg', handler: (payload: Payload) => void): this; + emit(name: 'event_msg', payload: Payload): boolean; +} + +/** + * A TransportClient provides a request/response and event api to a corresponding TransportServer. + * If `broadcast` is called on TransportServer, TransportClients will emit an `event_msg`. + * The `request` method will block until a response is returned from the TransportServer's dispatch function. + * Request multiplexing is supported. + */ +export class TransportClient extends EventEmitter { + private msgId = 0; + private pendingRequests: PendingRequest[] = []; + private socket?: Socket; + + constructor(private transportConnect: Connector) { + super(); + } + + /** + * Create and register our socket using our Connector. + */ + async open() { + this.socket = await this.transportConnect.createSocket(); + this.socket.registerHandler(msg => this.handleSocketMessage(msg)); + } + + /** + * Close this and stop listening for messages. + */ + close() { + this.socket?.close(); + this.socket = undefined; + this.removeAllListeners(); + } + + /** + * Queue a request. + * @param payload - The request payload. + * @param transfer - Objects to transfer ownership of. + * @returns A promise of the query result. + */ + request(payload: Payload, transfer?: Transferable[]) { + if (!this.socket) { + throw new Error('Socket not open.'); + } + const msgId = this.msgId++; + const msg = { msgId, payload }; + debug(`->`, msg); + return new Promise((resolve, reject) => { + this.pendingRequests.push({ resolve, reject, msgId }); + this.socket!.send(msg, transfer).catch(reject); + }); + } + + /** + * Handle an incoming socket message. + * @param msg - The message. + */ + private handleSocketMessage(msg: ResponseMessage | EventMessage | undefined) { + if (msg === undefined) { + // The remote socket closed. + this.close(); + return; + } + debug(`<-`, msg); + if (isEventMessage(msg)) { + this.emit('event_msg', msg.payload); + return; + } + const reqIndex = this.pendingRequests.findIndex(r => r.msgId === msg.msgId); + if (reqIndex === -1) { + return; + } + const [pending] = this.pendingRequests.splice(reqIndex, 1); + if (msg.error) { + pending.reject(new Error(msg.error)); + } else { + pending.resolve(msg.payload); + } + } +} diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/transport_server.ts b/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/transport_server.ts new file mode 100644 index 00000000000..0cb5aecf7e2 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/transport_server.ts @@ -0,0 +1,96 @@ +import { RequestMessage, ResponseMessage } from './dispatch/messages.js'; +import { Listener } from './interface/listener.js'; +import { Socket } from './interface/socket.js'; +import { isTransferDescriptor } from './interface/transferable.js'; + +/** + * Keeps track of clients, providing a broadcast, and request/response api with multiplexing. + */ +export class TransportServer { + private sockets: Socket[] = []; + + constructor(private listener: Listener, private msgHandlerFn: (msg: Payload) => Promise) {} + + /** + * Start accepting new connections. + */ + start() { + this.listener.on('new_socket', client => this.handleNewSocket(client)); + this.listener.open(); + } + + /** + * Stops accepting new connections. It doesn't close existing sockets. + * It's expected the clients will gracefully complete by closing their end, sending an `undefined` message. + */ + stop() { + this.listener.close(); + } + + /** + * Broadcast a message. + * @param msg - The message. + */ + async broadcast(msg: Payload) { + await Promise.all(this.sockets.map(s => s.send({ payload: msg }))); + } + + /** + * New socket registration. + * @param socket - The socket to register. + */ + private handleNewSocket(socket: Socket) { + socket.registerHandler(async msg => { + if (msg === undefined) { + // Client socket has closed. Remove it from the list of sockets. Call close on it for any cleanup. + const socketIndex = this.sockets.findIndex(s => s === socket); + const [closingSocket] = this.sockets.splice(socketIndex, 1); + closingSocket.close(); + return; + } + return await this.handleSocketMessage(socket, msg); + }); + this.sockets.push(socket); + } + + /** + * Detect the 'transferables' argument to our socket from our message + * handler return type. + * @param data - The return object. + * @returns - The data and the. + */ + private getPayloadAndTransfers(data: any): [any, Transferable[]] { + if (isTransferDescriptor(data)) { + // We treat PayloadWithTransfers specially so that we're able to + // attach transferables while keeping a simple return-type based usage + return [data.send, data.transferables]; + } + if (data instanceof Uint8Array) { + // We may want to devise a better solution to this. We maybe given a view over a non cloneable/transferrable + // ArrayBuffer (such as a view over wasm memory). In this case we want to take a copy, and then transfer it. + const respPayload = data instanceof Uint8Array && ArrayBuffer.isView(data) ? new Uint8Array(data) : data; + const transferables = data instanceof Uint8Array ? [respPayload.buffer] : []; + return [respPayload, transferables]; + } + return [data, []]; + } + /** + * Handles a socket message from a listener. + * @param socket - The socket. + * @param requestMessage - The message to handle. + * @returns The socket response. + */ + private async handleSocketMessage(socket: Socket, { msgId, payload }: RequestMessage) { + try { + const data = await this.msgHandlerFn(payload); + + const [respPayload, transferables] = this.getPayloadAndTransfers(data); + const rep: ResponseMessage = { msgId, payload: respPayload }; + + await socket.send(rep, transferables); + } catch (err: any) { + const rep: ResponseMessage = { msgId, error: err.stack }; + await socket.send(rep); + } + } +} diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/wasm/async_call_state.ts b/circuits/ts/.yalc/@aztec/wasm-worker/src/wasm/async_call_state.ts new file mode 100644 index 00000000000..17554f4889d --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/src/wasm/async_call_state.ts @@ -0,0 +1,136 @@ +import { WasmModule } from './wasm_module.js'; + +/** + * The state of an asynchronous WASM function. + */ +export interface AsyncFnState { + /** + * Is this a contination? + */ + continuation: boolean; + /** + * A result, if one exists. + */ + result?: any; +} + +/** + * To enable asynchronous callbacks from wasm to js, we leverage asyncify. + * Https://kripken.github.io/blog/wasm/2019/07/16/asyncify.html. + * + * This class holds state and logic specific to handling async calls from wasm to js. + * A single instance of this class is instantiated as part of BarretenbergWasm. + * It allocates some memory for the asyncify stack data and initialises it. + * + * To make an async call into the wasm, just call `call` the same as in BarretenbergWasm, only it returns a promise. + * + * To make an async import that will be called from the wasm, wrap a function with the signature: + * my_func(state: AsyncFnState, ...args) + * with a call to `wrapImportFn`. + * The arguments are whatever the original call arguments were. The addition of AsyncFnState as the first argument + * allows for the detection of wether the function is continuing after the the async call has completed. + * If `state.continuation` is false, the function should start its async operation and return the promise. + * If `state.continuation` is true, the function can get the result from `state.result` perform any finalisation, + * and return an (optional) value to the wasm. + */ +export class AsyncCallState { + private ASYNCIFY_DATA_SIZE = 16 * 1024; + private asyncifyDataAddr!: number; + private asyncPromise?: Promise; + private wasm!: WasmModule; + private state?: AsyncFnState; + private callExport!: (...args: any[]) => number; + + /** + * Initialize the call hooks with a WasmModule. + * @param wasm - The module. + */ + public init(wasm: WasmModule) { + this.wasm = wasm; + this.callExport = (name: string, ...args: any[]) => wasm.call(name, ...args); + // Allocate memory for asyncify stack data. + this.asyncifyDataAddr = this.callExport('bbmalloc', this.ASYNCIFY_DATA_SIZE); + // TODO: is this view construction problematic like in WasmModule? + const view = new Uint32Array(wasm.getRawMemory().buffer); + // First two integers of asyncify data, are the start and end of the stack region. + view[this.asyncifyDataAddr >> 2] = this.asyncifyDataAddr + 8; + view[(this.asyncifyDataAddr + 4) >> 2] = this.asyncifyDataAddr + this.ASYNCIFY_DATA_SIZE; + } + + /** + * Log a message. + * @param args - The message arguments. + */ + private debug(...args: any[]) { + this.wasm.getLogger()(...args); + } + + /** + * Free the data associated with async call states. + */ + public destroy() { + // Free call stack data. + this.callExport('bbfree', this.asyncifyDataAddr); + } + + /** + * We call the wasm function, that will in turn call back into js via callImport and set this.asyncPromise and + * enable the instrumented "record stack unwinding" code path. + * Once the stack has unwound out of the wasm call, we enter into a loop of resolving the promise set in the call + * to callImport, and calling back into the wasm to rewind the stack and continue execution. + * @param name - The function name. + * @param args - The function args. + * @returns The function result. + */ + public async call(name: string, ...args: any) { + if (this.state) { + throw new Error(`Can only handle one async call at a time: ${name}(${args})`); + } + this.state = { continuation: false }; + let result = this.callExport(name, ...args); + + while (this.asyncPromise) { + // Disable the instrumented "record stack unwinding" code path. + this.callExport('asyncify_stop_unwind'); + this.debug('stack unwound.'); + // Wait for the async work to complete. + this.state.result = await this.asyncPromise; + this.state.continuation = true; + this.debug('result set starting rewind.'); + // Enable "stack rewinding" code path. + this.callExport('asyncify_start_rewind', this.asyncifyDataAddr); + // Call function again to rebuild the stack, and continue where we left off. + result = this.callExport(name, ...args); + } + + // Cleanup + this.state = undefined; + + return result; + } + + /** + * Wrap a WASM import function. + * @param fn - The function. + * @returns A wrapped version with asyncify calls. + */ + public wrapImportFn(fn: (state: AsyncFnState, ...args: any[]) => any) { + return (...args: any[]) => { + if (!this.asyncPromise) { + // We are in the normal code path. Start the async fetch of data. + this.asyncPromise = fn(this.state!, ...args); + // Enable "record stack unwinding" code path and return. + this.callExport('asyncify_start_unwind', this.asyncifyDataAddr); + } else { + // We are in the stack rewind code path, called once the promise is resolved. + // Save the result data back to the wasm, disable stack rewind code paths, and return. + this.callExport('asyncify_stop_rewind'); + const result = fn(this.state!, ...args); + // Cleanup. + this.asyncPromise = undefined; + this.state = { continuation: false }; + return result; + } + }; + } +} diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/wasm/empty_wasi_sdk.ts b/circuits/ts/.yalc/@aztec/wasm-worker/src/wasm/empty_wasi_sdk.ts new file mode 100644 index 00000000000..c9398c01a7d --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/src/wasm/empty_wasi_sdk.ts @@ -0,0 +1,61 @@ +import { createDebugLogger } from '@aztec/log'; + +/** + * Dummy implementation of a necessary part of the wasi api: + * https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md + * We don't use these functions, but the environment expects them. + * TODO find a way to update off of wasi 12. + */ +/* eslint-disable camelcase */ +/* eslint-disable jsdoc/require-jsdoc */ +export const getEmptyWasiSdk = (debug = createDebugLogger('wasm-worker:empty_wasi_sdk')) => ({ + clock_time_get() { + debug('clock_time_get'); + }, + environ_get() { + debug('environ_get'); + }, + environ_sizes_get() { + debug('environ_sizes_get'); + }, + fd_close() { + debug('fd_close'); + }, + fd_read() { + debug('fd_read'); + }, + fd_write() { + debug('fd_write'); + }, + fd_seek() { + debug('fd_seek'); + }, + fd_fdstat_get() { + debug('fd_fdstat_get'); + }, + fd_fdstat_set_flags() { + debug('fd_fdstat_set_flags'); + }, + fd_prestat_get() { + debug('fd_prestat_get'); + return 8; + }, + fd_prestat_dir_name() { + debug('fd_prestat_dir_name'); + return 28; + }, + path_open() { + debug('path_open'); + }, + path_filestat_get() { + debug('path_filestat_get'); + }, + proc_exit() { + debug('proc_exit'); + return 52; + }, + random_get() { + debug('random_get'); + return 1; + }, +}); diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/wasm/index.ts b/circuits/ts/.yalc/@aztec/wasm-worker/src/wasm/index.ts new file mode 100644 index 00000000000..2fb5a8b9afe --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/src/wasm/index.ts @@ -0,0 +1,2 @@ +export { AsyncCallState, AsyncFnState } from './async_call_state.js'; +export { WasmModule } from './wasm_module.js'; diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/wasm/wasm_module.test.ts b/circuits/ts/.yalc/@aztec/wasm-worker/src/wasm/wasm_module.test.ts new file mode 100644 index 00000000000..d376018f3b0 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/src/wasm/wasm_module.test.ts @@ -0,0 +1,27 @@ +import { WasmModule } from './wasm_module.js'; +import { fileURLToPath } from 'url'; +import { readFile } from 'fs/promises'; +import { dirname } from 'path'; + +/** + * + */ +async function fetchCode() { + const __dirname = dirname(fileURLToPath(import.meta.url)); + return await readFile(`${__dirname}/../test/gcd.wasm`); +} + +describe('barretenberg wasm', () => { + let wasm!: WasmModule; + + beforeAll(async () => { + wasm = new WasmModule(await fetchCode(), () => ({ + /*no imports*/ + })); + await wasm.init(); + }); + + it('should new malloc, transfer and slice mem', () => { + expect(wasm.call('gcd', 1, 1)).toBe(1); + }); +}); diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/wasm/wasm_module.ts b/circuits/ts/.yalc/@aztec/wasm-worker/src/wasm/wasm_module.ts new file mode 100644 index 00000000000..6e7e1b97a86 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/src/wasm/wasm_module.ts @@ -0,0 +1,203 @@ +import { createDebugLogger, DebugLogger } from '@aztec/log'; +import { Buffer } from 'buffer'; +import { MemoryFifo } from '../memory_fifo.js'; +import { getEmptyWasiSdk } from './empty_wasi_sdk.js'; +import { randomBytes } from 'crypto'; + +/** + * WasmModule: + * Helper over a webassembly module. + * Assumes a few quirks. + * 1) the module expects wasi_snapshot_preview1 with the methods from getEmptyWasiSdk + * 2) of which the webassembly + * we instantiate only uses random_get (update this if more WASI sdk methods are needed). + */ +export class WasmModule { + private memory!: WebAssembly.Memory; + private heap!: Uint8Array; + private instance?: WebAssembly.Instance; + private mutexQ = new MemoryFifo(); + private debug: DebugLogger; + + /** + * Create a wasm module. Should be followed by await init();. + * @param module - The module as a WebAssembly.Module or a Buffer. + * @param importFn - Imports expected by the WASM. + * @param loggerName - Optional, for debug logging. + */ + constructor( + private module: WebAssembly.Module | Buffer, + private importFn: (module: WasmModule) => any, + loggerName = 'wasm-worker', + ) { + this.debug = createDebugLogger(loggerName); + this.mutexQ.put(true); + } + + /** + * Initialize this wasm module. + * @param wasmImportEnv - Linked to a module called "env". Functions implementations referenced from e.g. C++. + * @param initial - 20 pages by default. 20*2**16 \> 1mb stack size plus other overheads. + * @param maximum - 8192 maximum by default. 512mb. + */ + public async init(initial = 20, maximum = 8192) { + this.debug( + `initial mem: ${initial} pages, ${(initial * 2 ** 16) / (1024 * 1024)}mb. max mem: ${maximum} pages, ${ + (maximum * 2 ** 16) / (1024 * 1024) + }mb`, + ); + this.memory = new WebAssembly.Memory({ initial, maximum }); + // Create a view over the memory buffer. + // We do this once here, as webkit *seems* bugged out and actually shows this as new memory, + // thus displaying double. It's only worse if we create views on demand. I haven't established yet if + // the bug is also exasperating the termination on mobile due to "excessive memory usage". It could be + // that the OS is actually getting an incorrect reading in the same way the memory profiler does... + // The view will have to be recreated if the memory is grown. See getMemory(). + this.heap = new Uint8Array(this.memory.buffer); + + // We support the wasi 12 SDK, but only implement random_get + /* eslint-disable camelcase */ + const importObj = { + wasi_snapshot_preview1: { + ...getEmptyWasiSdk(this.debug), + random_get: (arr: number, length: number) => { + arr = arr >>> 0; + const heap = this.getMemory(); + const randomData = randomBytes(length); + for (let i = arr; i < arr + length; ++i) { + heap[i] = randomData[i - arr]; + } + }, + }, + env: this.importFn(this), + }; + + if (this.module instanceof WebAssembly.Module) { + this.instance = await WebAssembly.instantiate(this.module, importObj); + } else { + const { instance } = await WebAssembly.instantiate(this.module, importObj); + this.instance = instance; + } + } + + /** + * The methods or objects exported by the WASM module. + * @returns An indexable object. + */ + public exports(): any { + if (!this.instance) { + throw new Error('WasmModule: not initialized!'); + } + return this.instance.exports; + } + + /** + * Get the current logger. + * @returns Logging function. + */ + public getLogger() { + return this.debug; + } + + /** + * Add a logger. + * @param logger - Function to call when logging. + */ + public addLogger(logger: DebugLogger) { + const oldDebug = this.debug; + this.debug = (...args: any[]) => { + logger(...args); + oldDebug(...args); + }; + } + + /** + * Calls into the WebAssembly. + * @param name - The method name. + * @param args - The arguments to the method. + * @returns The numeric method result. + */ + public call(name: string, ...args: any): number { + if (!this.exports()[name]) { + throw new Error(`WASM function ${name} not found.`); + } + try { + // When returning values from the WASM, use >>> operator to convert + // signed representation to unsigned representation. + return this.exports()[name](...args) >>> 0; + } catch (err: any) { + const message = `WASM function ${name} aborted, error: ${err}`; + this.debug(message); + this.debug(err.stack); + throw new Error(message); + } + } + /** + * Get the memory used by the WASM module. + * @returns A WebAssembly memory object. + */ + public getRawMemory(): WebAssembly.Memory { + return this.memory; + } + /** + * Get the memory used by the WASM module, as a byte array. + * @returns A Uint8Array view of the WASM module memory. + */ + public getMemory(): Uint8Array { + // If the memory is grown, our view over it will be lost. Recreate the view. + if (this.heap.length === 0) { + this.heap = new Uint8Array(this.memory.buffer); + } + return this.heap; + } + + /** + * The memory size in bytes. + * @returns Number of bytes. + */ + public memSize(): number { + return this.getMemory().length; + } + + /** + * Get a slice of memory between two addresses. + * @param start - The start address. + * @param end - The end address. + * @returns A Uint8Array view of memory. + */ + public getMemorySlice(start: number, end: number) { + return this.getMemory().slice(start, end); + } + + /** + * Write data into the heap. + * @param arr - The data to write. + * @param offset - The address to write data at. + */ + public transferToHeap(arr: Uint8Array, offset: number) { + const mem = this.getMemory(); + for (let i = 0; i < arr.length; i++) { + mem[i + offset] = arr[i]; + } + } + + /** + * When calling the wasm, sometimes a caller will require exclusive access over a series of calls. + * E.g. When a result is written to address 0, one cannot have another caller writing to the same address via + * transferToHeap before the result is read via sliceMemory. + * Acquire() gets a single token from a fifo. The caller must call release() to add the token back. + */ + public async acquire() { + await this.mutexQ.get(); + } + + /** + * Release the mutex, letting another promise call acquire(). + */ + public release() { + if (this.mutexQ.length() !== 0) { + throw new Error('Release called but not acquired.'); + } + this.mutexQ.put(true); + } +} diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/browser/index.ts b/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/browser/index.ts new file mode 100644 index 00000000000..ae6a02c0771 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/browser/index.ts @@ -0,0 +1,2 @@ +export * from './web_worker.js'; +export * from './web_data_store.js'; diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/browser/start_web_module.ts b/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/browser/start_web_module.ts new file mode 100644 index 00000000000..e6b05bbd365 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/browser/start_web_module.ts @@ -0,0 +1,23 @@ +import { DispatchMsg, TransportServer, WorkerListener } from '../../transport/index.js'; +import { WasmModule } from '../../wasm/wasm_module.js'; + +/** + * Start the transport server corresponding to this module. + * @param module - The WasmModule to host. + */ +export function startWebModule(module: WasmModule) { + const dispatch = async ({ fn, args }: DispatchMsg) => { + if (fn === '__destroyWorker__') { + transportServer.stop(); + return; + } + if (!(module as any)[fn]) { + throw new Error(`dispatch error, function not found: ${fn}`); + } + return await (module as any)[fn](...args); + }; + const transportListener = new WorkerListener(self); + const transportServer = new TransportServer(transportListener, dispatch); + module.addLogger((...args: any[]) => transportServer.broadcast({ fn: 'emit', args: ['log', ...args] })); + transportServer.start(); +} diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/browser/web_data_store.ts b/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/browser/web_data_store.ts new file mode 100644 index 00000000000..79f9c6a60eb --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/browser/web_data_store.ts @@ -0,0 +1,37 @@ +import { DataStore } from '../data_store.js'; +import levelup, { LevelUp } from 'levelup'; +import memdown from 'memdown'; + +/** + * Cache for data used by wasm module. + * Stores in a LevelUp database. + */ +export class WebDataStore implements DataStore { + private db: LevelUp; + + constructor() { + // TODO: The whole point of this is to reduce memory load in the browser. + // Replace with leveljs so the data is stored in indexeddb and not in memory. + // Hack: Cast as any to work around package "broken" with node16 resolution + // See https://github.com/microsoft/TypeScript/issues/49160 + this.db = levelup((memdown as any)()); + } + + /** + * Lookup a key. + * @param key - Key to lookup. + * @returns The buffer. + */ + async get(key: string): Promise { + return await this.db.get(key).catch(() => {}); + } + + /** + * Alter a key. + * @param key - Key to alter. + * @param value - Buffer to store. + */ + async set(key: string, value: Buffer): Promise { + await this.db.put(key, value); + } +} diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/browser/web_worker.ts b/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/browser/web_worker.ts new file mode 100644 index 00000000000..6299c5011f8 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/browser/web_worker.ts @@ -0,0 +1,20 @@ +import { WasmModule } from '../../wasm/wasm_module.js'; +import { createDispatchProxy, DispatchMsg, TransportClient, WorkerConnector } from '../../transport/index.js'; +import { WasmWorker } from '../wasm_worker.js'; + +/** + * + */ +export async function createWebWorker(url: string, initialMem?: number, maxMem?: number): Promise { + const worker = new Worker(url); + const transportConnect = new WorkerConnector(worker); + const transportClient = new TransportClient(transportConnect); + await transportClient.open(); + const remoteModule = createDispatchProxy(WasmModule, transportClient) as WasmWorker; + remoteModule.destroyWorker = async () => { + await transportClient.request({ fn: '__destroyWorker__', args: [] }); + transportClient.close(); + }; + await remoteModule.init(initialMem, maxMem); + return remoteModule; +} diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/data_store.ts b/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/data_store.ts new file mode 100644 index 00000000000..4390b2775ee --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/data_store.ts @@ -0,0 +1,7 @@ +/** + * Simple read/write interface for wasm modules. + */ +export interface DataStore { + get(key: string): Promise; + set(key: string, value: Buffer): Promise; +} diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/index.ts b/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/index.ts new file mode 100644 index 00000000000..52994b878ba --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/index.ts @@ -0,0 +1 @@ +export * from './worker_pool.js'; diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/node/index.ts b/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/node/index.ts new file mode 100644 index 00000000000..6ac2cfb6ba3 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/node/index.ts @@ -0,0 +1,2 @@ +export * from './node_worker.js'; +export * from './node_data_store.js'; diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/node/node_data_store.ts b/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/node/node_data_store.ts new file mode 100644 index 00000000000..d3835350c30 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/node/node_data_store.ts @@ -0,0 +1,36 @@ +import { DataStore } from '../data_store.js'; +import levelup, { LevelUp } from 'levelup'; +import leveldown from 'leveldown'; +import memdown from 'memdown'; + +/** + * Cache for data used by wasm module. + */ +export class NodeDataStore implements DataStore { + private db: LevelUp; + + // eslint-disable-next-line + constructor(path?: string) { + // Hack: Cast as any to work around packages "broken" with node16 resolution + // See https://github.com/microsoft/TypeScript/issues/49160 + this.db = levelup(path ? (leveldown as any)(path) : (memdown as any)()); + } + + /** + * Get a value from our DB. + * @param key - The key to look up. + * @returns The value. + */ + async get(key: string): Promise { + return await this.db.get(key).catch(() => {}); + } + + /** + * Set a value in our DB. + * @param key - The key to update. + * @param value - The value to set. + */ + async set(key: string, value: Buffer): Promise { + await this.db.put(key, value); + } +} diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/node/node_worker.ts b/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/node/node_worker.ts new file mode 100644 index 00000000000..a11f379196a --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/node/node_worker.ts @@ -0,0 +1,22 @@ +import { Worker } from 'worker_threads'; +import { createDispatchProxy, DispatchMsg, TransportClient } from '../../transport/index.js'; +import { NodeConnector } from '../../transport/index.js'; +import { WasmModule } from '../../wasm/wasm_module.js'; +import { WasmWorker } from '../wasm_worker.js'; + +/** + * + */ +export async function createNodeWorker(filepath: string, initialMem?: number, maxMem?: number): Promise { + const worker = new Worker(filepath); + const transportConnect = new NodeConnector(worker); + const transportClient = new TransportClient(transportConnect); + await transportClient.open(); + const remoteModule = createDispatchProxy(WasmModule, transportClient) as WasmWorker; + remoteModule.destroyWorker = async () => { + await transportClient.request({ fn: '__destroyWorker__', args: [] }); + transportClient.close(); + }; + await remoteModule.init(initialMem, maxMem); + return remoteModule; +} diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/node/start_node_module.ts b/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/node/start_node_module.ts new file mode 100644 index 00000000000..ca0c1c9fd9e --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/node/start_node_module.ts @@ -0,0 +1,28 @@ +import { parentPort } from 'worker_threads'; +import { NodeListener, DispatchMsg, TransportServer } from '../../transport/index.js'; +import { WasmModule } from '../../wasm/wasm_module.js'; + +if (!parentPort) { + throw new Error('InvalidWorker'); +} + +/** + * Start the transport server corresponding to this module. + * @param module - The WasmModule to host. + */ +export function startNodeModule(module: WasmModule) { + const dispatch = async ({ fn, args }: DispatchMsg) => { + if (fn === '__destroyWorker__') { + transportServer.stop(); + return; + } + if (!(module as any)[fn]) { + throw new Error(`dispatch error, function not found: ${fn}`); + } + return await (module as any)[fn](...args); + }; + const transportListener = new NodeListener(); + const transportServer = new TransportServer(transportListener, dispatch); + module.addLogger((...args: any[]) => transportServer.broadcast({ fn: 'emit', args: ['log', ...args] })); + transportServer.start(); +} diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/wasm_worker.ts b/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/wasm_worker.ts new file mode 100644 index 00000000000..a9dcb4a7ad2 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/wasm_worker.ts @@ -0,0 +1,7 @@ +import { Proxify } from '../transport/index.js'; +import { WasmModule } from '../wasm/wasm_module.js'; + +/** + * Represents either a WASM web worker, or node.js worker. + */ +export type WasmWorker = Proxify & { destroyWorker(): void }; diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/worker_pool.ts b/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/worker_pool.ts new file mode 100644 index 00000000000..7ac278ba571 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/worker_pool.ts @@ -0,0 +1,73 @@ +import { createDebugLogger } from '@aztec/log'; +import { WasmWorker } from './wasm_worker.js'; + +const debug = createDebugLogger('bb:worker_pool'); + +/** + * Type of a worker factory. + * Used to customize WorkerPool worker construction. + */ +export type CreateWorker = (name: string, minMem: number, maxMem: number) => WasmWorker; +/** + * Allocates a pool of WasmWorker's. + * Worker 0 is allocated MAX_PAGES memory pages. This is because worker 0 will need to hold the proving key + * (i.e. Has state), whereas the others are pure compute (they hold a little crs state). + */ +export class WorkerPool { + // TODO(AD): Revisit what this means in aztec 3 context + // -- + // Introduction of low mem prover work (polynomial cache) may actually increase mem usage when the backing store isn't + // enabled. We were seeing intermittent failings related to memory in production for some users when limiting to + // 6660 (416MB). It would be nice to understand why this is (the non determinism and/or the increased mem usage). + // For now, increasing mem usage to 512MB. This maybe preferable to backing out the low mem work, but + // ironically may break the chance of us using it in mobile. + // We *could* enable the low memory backing store, but this needs a little bit of work to actually + // read/write from indexeddb, performance testing, and actual further memory load testing. + // At this point it's hard to know what our memory savings would be relative to just fully reverting the LMP. + // public static MAX_PAGES = 6660; + /** + * The maximum number of memory pages to be used by the webassembly. + */ + public static MAX_PAGES = 8192; + /** + * The workers in the pool. + */ + private workers: WasmWorker[] = []; + + /** + * Create an instance and initialize the workers. + * @param createWorker - Worker factory. + * @param poolSize - Pool size. + * @returns An initialized WorkerPool. + */ + static async new(createWorker: CreateWorker, poolSize: number) { + const pool = new WorkerPool(); + await pool.init(createWorker, poolSize); + return pool; + } + + /** + * Initialize the workers. + * @param createWorker - Worker factory(). + * @param poolSize - Pool size. + * @param maxMem - Max memory pages. + */ + public async init(createWorker: CreateWorker, poolSize: number, maxMem = WorkerPool.MAX_PAGES) { + debug(`creating ${poolSize} workers...`); + const start = new Date().getTime(); + this.workers = await Promise.all( + Array(poolSize) + .fill(0) + .map((_, i) => createWorker(`${i}`, i === 0 ? Math.min(WorkerPool.MAX_PAGES, maxMem) : 768, maxMem)), + ); + + debug(`created workers: ${new Date().getTime() - start}ms`); + } + + /** + * Tell all workers in the pool to stop processing. + */ + public async destroy() { + await Promise.all(this.workers.map(w => w.destroyWorker())); + } +} diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/tsconfig.dest.json b/circuits/ts/.yalc/@aztec/wasm-worker/tsconfig.dest.json new file mode 100644 index 00000000000..965aaa1c433 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/tsconfig.dest.json @@ -0,0 +1,4 @@ +{ + "extends": ".", + "exclude": ["**/*.test.*", "**/fixtures/*"] +} diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/tsconfig.json b/circuits/ts/.yalc/@aztec/wasm-worker/tsconfig.json new file mode 100644 index 00000000000..f67ddec9fd6 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "..", + "compilerOptions": { + "outDir": "dest", + "rootDir": "src", + "tsBuildInfoFile": ".tsbuildinfo" + }, + "include": ["src"] +} diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/yalc.sig b/circuits/ts/.yalc/@aztec/wasm-worker/yalc.sig new file mode 100644 index 00000000000..72cf67e08e0 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm-worker/yalc.sig @@ -0,0 +1 @@ +c3f323629c42198a64e1e6969247e19a \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/.eslintrc.cjs b/circuits/ts/.yalc/@aztec/wasm/.eslintrc.cjs new file mode 100644 index 00000000000..9cf806b1500 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/.eslintrc.cjs @@ -0,0 +1,6 @@ +require('@rushstack/eslint-patch/modern-module-resolution'); + +module.exports = { + extends: ['@aztec/eslint-config'], + parserOptions: { tsconfigRootDir: __dirname }, +}; diff --git a/circuits/ts/.yalc/@aztec/wasm/.tsbuildinfo b/circuits/ts/.yalc/@aztec/wasm/.tsbuildinfo new file mode 100644 index 00000000000..eb474691c49 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/.tsbuildinfo @@ -0,0 +1 @@ +{"program":{"fileNames":["../node_modules/typescript/lib/lib.es5.d.ts","../node_modules/typescript/lib/lib.es2015.d.ts","../node_modules/typescript/lib/lib.es2016.d.ts","../node_modules/typescript/lib/lib.es2017.d.ts","../node_modules/typescript/lib/lib.es2018.d.ts","../node_modules/typescript/lib/lib.es2019.d.ts","../node_modules/typescript/lib/lib.es2020.d.ts","../node_modules/typescript/lib/lib.es2021.d.ts","../node_modules/typescript/lib/lib.es2022.d.ts","../node_modules/typescript/lib/lib.esnext.d.ts","../node_modules/typescript/lib/lib.dom.d.ts","../node_modules/typescript/lib/lib.es2015.core.d.ts","../node_modules/typescript/lib/lib.es2015.collection.d.ts","../node_modules/typescript/lib/lib.es2015.generator.d.ts","../node_modules/typescript/lib/lib.es2015.iterable.d.ts","../node_modules/typescript/lib/lib.es2015.promise.d.ts","../node_modules/typescript/lib/lib.es2015.proxy.d.ts","../node_modules/typescript/lib/lib.es2015.reflect.d.ts","../node_modules/typescript/lib/lib.es2015.symbol.d.ts","../node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../node_modules/typescript/lib/lib.es2016.array.include.d.ts","../node_modules/typescript/lib/lib.es2017.object.d.ts","../node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../node_modules/typescript/lib/lib.es2017.string.d.ts","../node_modules/typescript/lib/lib.es2017.intl.d.ts","../node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../node_modules/typescript/lib/lib.es2018.intl.d.ts","../node_modules/typescript/lib/lib.es2018.promise.d.ts","../node_modules/typescript/lib/lib.es2018.regexp.d.ts","../node_modules/typescript/lib/lib.es2019.array.d.ts","../node_modules/typescript/lib/lib.es2019.object.d.ts","../node_modules/typescript/lib/lib.es2019.string.d.ts","../node_modules/typescript/lib/lib.es2019.symbol.d.ts","../node_modules/typescript/lib/lib.es2019.intl.d.ts","../node_modules/typescript/lib/lib.es2020.bigint.d.ts","../node_modules/typescript/lib/lib.es2020.date.d.ts","../node_modules/typescript/lib/lib.es2020.promise.d.ts","../node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../node_modules/typescript/lib/lib.es2020.string.d.ts","../node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../node_modules/typescript/lib/lib.es2020.intl.d.ts","../node_modules/typescript/lib/lib.es2020.number.d.ts","../node_modules/typescript/lib/lib.es2021.promise.d.ts","../node_modules/typescript/lib/lib.es2021.string.d.ts","../node_modules/typescript/lib/lib.es2021.weakref.d.ts","../node_modules/typescript/lib/lib.es2021.intl.d.ts","../node_modules/typescript/lib/lib.es2022.array.d.ts","../node_modules/typescript/lib/lib.es2022.error.d.ts","../node_modules/typescript/lib/lib.es2022.intl.d.ts","../node_modules/typescript/lib/lib.es2022.object.d.ts","../node_modules/typescript/lib/lib.es2022.sharedmemory.d.ts","../node_modules/typescript/lib/lib.es2022.string.d.ts","../node_modules/typescript/lib/lib.esnext.intl.d.ts","../node_modules/tslib/tslib.d.ts","../log/dest/index.d.ts","../node_modules/buffer/index.d.ts","./src/memory_fifo.ts","./src/wasm/empty_wasi_sdk.ts","./src/wasm/wasm_module.ts","./src/transport/dispatch/create_dispatch_fn.ts","./src/transport/dispatch/messages.ts","./src/transport/interface/socket.ts","./src/transport/interface/connector.ts","./src/transport/transport_client.ts","./src/transport/interface/transferable.ts","./src/transport/dispatch/create_dispatch_proxy.ts","./src/transport/interface/listener.ts","./src/transport/transport_server.ts","./src/transport/browser/message_port_socket.ts","./src/transport/browser/worker_connector.ts","./src/transport/browser/worker_listener.ts","./src/transport/browser/shared_worker_connector.ts","./src/transport/browser/shared_worker_listener.ts","./src/transport/browser/index.ts","./src/transport/node/node_connector_socket.ts","./src/transport/node/node_connector.ts","./src/transport/node/node_listener_socket.ts","./src/transport/node/node_listener.ts","./src/transport/node/index.ts","./src/transport/index.ts","./src/worker/wasm_worker.ts","./src/worker/browser/web_worker.ts","./src/worker/data_store.ts","../node_modules/@types/node/assert.d.ts","../node_modules/@types/node/assert/strict.d.ts","../node_modules/@types/node/globals.d.ts","../node_modules/@types/node/async_hooks.d.ts","../node_modules/@types/node/buffer.d.ts","../node_modules/@types/node/child_process.d.ts","../node_modules/@types/node/cluster.d.ts","../node_modules/@types/node/console.d.ts","../node_modules/@types/node/constants.d.ts","../node_modules/@types/node/crypto.d.ts","../node_modules/@types/node/dgram.d.ts","../node_modules/@types/node/diagnostics_channel.d.ts","../node_modules/@types/node/dns.d.ts","../node_modules/@types/node/dns/promises.d.ts","../node_modules/@types/node/domain.d.ts","../node_modules/@types/node/dom-events.d.ts","../node_modules/@types/node/events.d.ts","../node_modules/@types/node/fs.d.ts","../node_modules/@types/node/fs/promises.d.ts","../node_modules/@types/node/http.d.ts","../node_modules/@types/node/http2.d.ts","../node_modules/@types/node/https.d.ts","../node_modules/@types/node/inspector.d.ts","../node_modules/@types/node/module.d.ts","../node_modules/@types/node/net.d.ts","../node_modules/@types/node/os.d.ts","../node_modules/@types/node/path.d.ts","../node_modules/@types/node/perf_hooks.d.ts","../node_modules/@types/node/process.d.ts","../node_modules/@types/node/punycode.d.ts","../node_modules/@types/node/querystring.d.ts","../node_modules/@types/node/readline.d.ts","../node_modules/@types/node/readline/promises.d.ts","../node_modules/@types/node/repl.d.ts","../node_modules/@types/node/stream.d.ts","../node_modules/@types/node/stream/promises.d.ts","../node_modules/@types/node/stream/consumers.d.ts","../node_modules/@types/node/stream/web.d.ts","../node_modules/@types/node/string_decoder.d.ts","../node_modules/@types/node/test.d.ts","../node_modules/@types/node/timers.d.ts","../node_modules/@types/node/timers/promises.d.ts","../node_modules/@types/node/tls.d.ts","../node_modules/@types/node/trace_events.d.ts","../node_modules/@types/node/tty.d.ts","../node_modules/@types/node/url.d.ts","../node_modules/@types/node/util.d.ts","../node_modules/@types/node/v8.d.ts","../node_modules/@types/node/vm.d.ts","../node_modules/@types/node/wasi.d.ts","../node_modules/@types/node/worker_threads.d.ts","../node_modules/@types/node/zlib.d.ts","../node_modules/@types/node/globals.global.d.ts","../node_modules/@types/node/index.d.ts","../node_modules/@types/abstract-leveldown/index.d.ts","../node_modules/@types/level-errors/index.d.ts","../node_modules/@types/levelup/index.d.ts","../node_modules/@types/memdown/index.d.ts","./src/worker/browser/web_data_store.ts","./src/worker/browser/index.ts","./src/worker/node/node_worker.ts","../node_modules/@types/leveldown/index.d.ts","./src/worker/node/node_data_store.ts","./src/worker/node/index.ts","./src/worker/worker_pool.ts","./src/worker/index.ts","./src/wasm/async_call_state.ts","./src/wasm/index.ts","./src/index.ts","./src/worker/browser/start_web_module.ts","./src/worker/node/start_node_module.ts","../node_modules/@babel/types/lib/index.d.ts","../node_modules/@types/babel__generator/index.d.ts","../node_modules/@babel/parser/typings/babel-parser.d.ts","../node_modules/@types/babel__template/index.d.ts","../node_modules/@types/babel__traverse/index.d.ts","../node_modules/@types/babel__core/index.d.ts","../node_modules/@types/bn.js/index.d.ts","../node_modules/@types/detect-node/index.d.ts","../node_modules/@types/elliptic/index.d.ts","../node_modules/@types/graceful-fs/index.d.ts","../node_modules/@types/hdkey/index.d.ts","../node_modules/@types/istanbul-lib-coverage/index.d.ts","../node_modules/@types/istanbul-lib-report/index.d.ts","../node_modules/@types/istanbul-reports/index.d.ts","../node_modules/@jest/expect-utils/build/index.d.ts","../node_modules/chalk/index.d.ts","../node_modules/@sinclair/typebox/typebox.d.ts","../node_modules/@jest/schemas/build/index.d.ts","../node_modules/jest-diff/node_modules/pretty-format/build/index.d.ts","../node_modules/jest-diff/build/index.d.ts","../node_modules/expect/node_modules/jest-matcher-utils/build/index.d.ts","../node_modules/expect/build/index.d.ts","../node_modules/@types/jest/node_modules/pretty-format/build/index.d.ts","../node_modules/@types/jest/index.d.ts","../node_modules/@types/json-schema/index.d.ts","../node_modules/@types/prettier/index.d.ts","../node_modules/@types/semver/classes/semver.d.ts","../node_modules/@types/semver/functions/parse.d.ts","../node_modules/@types/semver/functions/valid.d.ts","../node_modules/@types/semver/functions/clean.d.ts","../node_modules/@types/semver/functions/inc.d.ts","../node_modules/@types/semver/functions/diff.d.ts","../node_modules/@types/semver/functions/major.d.ts","../node_modules/@types/semver/functions/minor.d.ts","../node_modules/@types/semver/functions/patch.d.ts","../node_modules/@types/semver/functions/prerelease.d.ts","../node_modules/@types/semver/functions/compare.d.ts","../node_modules/@types/semver/functions/rcompare.d.ts","../node_modules/@types/semver/functions/compare-loose.d.ts","../node_modules/@types/semver/functions/compare-build.d.ts","../node_modules/@types/semver/functions/sort.d.ts","../node_modules/@types/semver/functions/rsort.d.ts","../node_modules/@types/semver/functions/gt.d.ts","../node_modules/@types/semver/functions/lt.d.ts","../node_modules/@types/semver/functions/eq.d.ts","../node_modules/@types/semver/functions/neq.d.ts","../node_modules/@types/semver/functions/gte.d.ts","../node_modules/@types/semver/functions/lte.d.ts","../node_modules/@types/semver/functions/cmp.d.ts","../node_modules/@types/semver/functions/coerce.d.ts","../node_modules/@types/semver/classes/comparator.d.ts","../node_modules/@types/semver/classes/range.d.ts","../node_modules/@types/semver/functions/satisfies.d.ts","../node_modules/@types/semver/ranges/max-satisfying.d.ts","../node_modules/@types/semver/ranges/min-satisfying.d.ts","../node_modules/@types/semver/ranges/to-comparators.d.ts","../node_modules/@types/semver/ranges/min-version.d.ts","../node_modules/@types/semver/ranges/valid.d.ts","../node_modules/@types/semver/ranges/outside.d.ts","../node_modules/@types/semver/ranges/gtr.d.ts","../node_modules/@types/semver/ranges/ltr.d.ts","../node_modules/@types/semver/ranges/intersects.d.ts","../node_modules/@types/semver/ranges/simplify.d.ts","../node_modules/@types/semver/ranges/subset.d.ts","../node_modules/@types/semver/internals/identifiers.d.ts","../node_modules/@types/semver/index.d.ts","../node_modules/@types/stack-utils/index.d.ts","../node_modules/@types/uuid/index.d.ts","../node_modules/@types/yargs-parser/index.d.ts","../node_modules/@types/yargs/index.d.ts"],"fileInfos":[{"version":"8730f4bf322026ff5229336391a18bcaa1f94d4f82416c8b2f3954e2ccaae2ba","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc47c4fa66b9b9890cf076304de2a9c5201e94b740cffdf09f87296d877d71f6","impliedFormat":1},{"version":"7a387c58583dfca701b6c85e0adaf43fb17d590fb16d5b2dc0a2fbd89f35c467","impliedFormat":1},{"version":"8a12173c586e95f4433e0c6dc446bc88346be73ffe9ca6eec7aa63c8f3dca7f9","impliedFormat":1},{"version":"5f4e733ced4e129482ae2186aae29fde948ab7182844c3a5a51dd346182c7b06","impliedFormat":1},{"version":"4b421cbfb3a38a27c279dec1e9112c3d1da296f77a1a85ddadf7e7a425d45d18","impliedFormat":1},{"version":"1fc5ab7a764205c68fa10d381b08417795fc73111d6dd16b5b1ed36badb743d9","impliedFormat":1},{"version":"746d62152361558ea6d6115cf0da4dd10ede041d14882ede3568bce5dc4b4f1f","impliedFormat":1},{"version":"d11a03592451da2d1065e09e61f4e2a9bf68f780f4f6623c18b57816a9679d17","impliedFormat":1},{"version":"aea179452def8a6152f98f63b191b84e7cbd69b0e248c91e61fb2e52328abe8c","impliedFormat":1},{"version":"3aafcb693fe5b5c3bd277bd4c3a617b53db474fe498fc5df067c5603b1eebde7","affectsGlobalScope":true,"impliedFormat":1},{"version":"adb996790133eb33b33aadb9c09f15c2c575e71fb57a62de8bf74dbf59ec7dfb","affectsGlobalScope":true,"impliedFormat":1},{"version":"8cc8c5a3bac513368b0157f3d8b31cfdcfe78b56d3724f30f80ed9715e404af8","affectsGlobalScope":true,"impliedFormat":1},{"version":"cdccba9a388c2ee3fd6ad4018c640a471a6c060e96f1232062223063b0a5ac6a","affectsGlobalScope":true,"impliedFormat":1},{"version":"c5c05907c02476e4bde6b7e76a79ffcd948aedd14b6a8f56e4674221b0417398","affectsGlobalScope":true,"impliedFormat":1},{"version":"5f406584aef28a331c36523df688ca3650288d14f39c5d2e555c95f0d2ff8f6f","affectsGlobalScope":true,"impliedFormat":1},{"version":"22f230e544b35349cfb3bd9110b6ef37b41c6d6c43c3314a31bd0d9652fcec72","affectsGlobalScope":true,"impliedFormat":1},{"version":"7ea0b55f6b315cf9ac2ad622b0a7813315bb6e97bf4bb3fbf8f8affbca7dc695","affectsGlobalScope":true,"impliedFormat":1},{"version":"3013574108c36fd3aaca79764002b3717da09725a36a6fc02eac386593110f93","affectsGlobalScope":true,"impliedFormat":1},{"version":"eb26de841c52236d8222f87e9e6a235332e0788af8c87a71e9e210314300410a","affectsGlobalScope":true,"impliedFormat":1},{"version":"3be5a1453daa63e031d266bf342f3943603873d890ab8b9ada95e22389389006","affectsGlobalScope":true,"impliedFormat":1},{"version":"17bb1fc99591b00515502d264fa55dc8370c45c5298f4a5c2083557dccba5a2a","affectsGlobalScope":true,"impliedFormat":1},{"version":"7ce9f0bde3307ca1f944119f6365f2d776d281a393b576a18a2f2893a2d75c98","affectsGlobalScope":true,"impliedFormat":1},{"version":"6a6b173e739a6a99629a8594bfb294cc7329bfb7b227f12e1f7c11bc163b8577","affectsGlobalScope":true,"impliedFormat":1},{"version":"81cac4cbc92c0c839c70f8ffb94eb61e2d32dc1c3cf6d95844ca099463cf37ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"b0124885ef82641903d232172577f2ceb5d3e60aed4da1153bab4221e1f6dd4e","affectsGlobalScope":true,"impliedFormat":1},{"version":"0eb85d6c590b0d577919a79e0084fa1744c1beba6fd0d4e951432fa1ede5510a","affectsGlobalScope":true,"impliedFormat":1},{"version":"da233fc1c8a377ba9e0bed690a73c290d843c2c3d23a7bd7ec5cd3d7d73ba1e0","affectsGlobalScope":true,"impliedFormat":1},{"version":"d154ea5bb7f7f9001ed9153e876b2d5b8f5c2bb9ec02b3ae0d239ec769f1f2ae","affectsGlobalScope":true,"impliedFormat":1},{"version":"bb2d3fb05a1d2ffbca947cc7cbc95d23e1d053d6595391bd325deb265a18d36c","affectsGlobalScope":true,"impliedFormat":1},{"version":"c80df75850fea5caa2afe43b9949338ce4e2de086f91713e9af1a06f973872b8","affectsGlobalScope":true,"impliedFormat":1},{"version":"9d57b2b5d15838ed094aa9ff1299eecef40b190722eb619bac4616657a05f951","affectsGlobalScope":true,"impliedFormat":1},{"version":"6c51b5dd26a2c31dbf37f00cfc32b2aa6a92e19c995aefb5b97a3a64f1ac99de","affectsGlobalScope":true,"impliedFormat":1},{"version":"6e7997ef61de3132e4d4b2250e75343f487903ddf5370e7ce33cf1b9db9a63ed","affectsGlobalScope":true,"impliedFormat":1},{"version":"2ad234885a4240522efccd77de6c7d99eecf9b4de0914adb9a35c0c22433f993","affectsGlobalScope":true,"impliedFormat":1},{"version":"5e5e095c4470c8bab227dbbc61374878ecead104c74ab9960d3adcccfee23205","affectsGlobalScope":true,"impliedFormat":1},{"version":"09aa50414b80c023553090e2f53827f007a301bc34b0495bfb2c3c08ab9ad1eb","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7f680a43f8cd12a6b6122c07c54ba40952b0c8aa140dcfcf32eb9e6cb028596","affectsGlobalScope":true,"impliedFormat":1},{"version":"3787b83e297de7c315d55d4a7c546ae28e5f6c0a361b7a1dcec1f1f50a54ef11","affectsGlobalScope":true,"impliedFormat":1},{"version":"e7e8e1d368290e9295ef18ca23f405cf40d5456fa9f20db6373a61ca45f75f40","affectsGlobalScope":true,"impliedFormat":1},{"version":"faf0221ae0465363c842ce6aa8a0cbda5d9296940a8e26c86e04cc4081eea21e","affectsGlobalScope":true,"impliedFormat":1},{"version":"06393d13ea207a1bfe08ec8d7be562549c5e2da8983f2ee074e00002629d1871","affectsGlobalScope":true,"impliedFormat":1},{"version":"2768ef564cfc0689a1b76106c421a2909bdff0acbe87da010785adab80efdd5c","affectsGlobalScope":true,"impliedFormat":1},{"version":"b248e32ca52e8f5571390a4142558ae4f203ae2f94d5bac38a3084d529ef4e58","affectsGlobalScope":true,"impliedFormat":1},{"version":"6c55633c733c8378db65ac3da7a767c3cf2cf3057f0565a9124a16a3a2019e87","affectsGlobalScope":true,"impliedFormat":1},{"version":"fb4416144c1bf0323ccbc9afb0ab289c07312214e8820ad17d709498c865a3fe","affectsGlobalScope":true,"impliedFormat":1},{"version":"5b0ca94ec819d68d33da516306c15297acec88efeb0ae9e2b39f71dbd9685ef7","affectsGlobalScope":true,"impliedFormat":1},{"version":"34c839eaaa6d78c8674ae2c37af2236dee6831b13db7b4ef4df3ec889a04d4f2","affectsGlobalScope":true,"impliedFormat":1},{"version":"34478567f8a80171f88f2f30808beb7da15eac0538ae91282dd33dce928d98ed","affectsGlobalScope":true,"impliedFormat":1},{"version":"ab7d58e6161a550ff92e5aff755dc37fe896245348332cd5f1e1203479fe0ed1","affectsGlobalScope":true,"impliedFormat":1},{"version":"6bda95ea27a59a276e46043b7065b55bd4b316c25e70e29b572958fa77565d43","affectsGlobalScope":true,"impliedFormat":1},{"version":"aedb8de1abb2ff1095c153854a6df7deae4a5709c37297f9d6e9948b6806fa66","affectsGlobalScope":true,"impliedFormat":1},{"version":"a4da0551fd39b90ca7ce5f68fb55d4dc0c1396d589b612e1902f68ee090aaada","affectsGlobalScope":true,"impliedFormat":1},{"version":"11ffe3c281f375fff9ffdde8bbec7669b4dd671905509079f866f2354a788064","affectsGlobalScope":true,"impliedFormat":1},{"version":"52d1bb7ab7a3306fd0375c8bff560feed26ed676a5b0457fa8027b563aecb9a4","affectsGlobalScope":true,"impliedFormat":1},{"version":"f1c9fe42b65437a61104e601eb298c5c859fb522b483f1bdb700eed67a16f980","impliedFormat":1},{"version":"39605640330a122a0bf7d90ecf13d9012991adb2fa4a63d04843c94394f0f96d","impliedFormat":99},{"version":"4967529644e391115ca5592184d4b63980569adf60ee685f968fd59ab1557188","impliedFormat":1},{"version":"7501fd9b2fc1fb3bc6abe499573b81db98d2954dc25df9a421973c5faaab4941","signature":"51eeac533c6eb5567faa2e43ac43d9fe25bd39581165f2f11af315bcac8efa14","impliedFormat":99},{"version":"7a73c72029575d1234a8be8d77defdac2b05e27c917543806e1697c77dbddcb4","signature":"ad9ea8a35fadce7abfe86228c0ff466dd7fe45a0aa6634b696d426d2c40e3f58","impliedFormat":99},{"version":"9f82f7dce7a1311fa6a023919337ae0cad6faefe122ca4503ae33d2e22420bc0","signature":"1ed4fa517b6642f6697e26befa2619494bca4243f77f7b8e9b1c897965d136aa","impliedFormat":99},{"version":"f7b2cc01d2477492f72e74e50997d4078a36d0c1ed9dcc18296c2741ae428de4","signature":"52ee7b65db088422f752fa8a03abd082b6e81ccd3555629a4d2996c75a3ea784","impliedFormat":99},{"version":"f841813d6e9df0f9e0180f69b4963964544886b9b59c5d75a0a4b3de45efdceb","signature":"a36a302ce150fc6aba361bf2c3f4c4f3ea6ad1a39c4a1b876df3191774974a41","impliedFormat":99},{"version":"c35f64730d5ddb935dba2b79506f5c8a851b2c40646637c7070a4033972bd73a","signature":"0700ea2ece0b6e7609f86bc93d1d4713fd3f53be3ed4d3384baddd9daff050aa","impliedFormat":99},{"version":"4017cfb925dd1318b932861fe1789154f6063bbbf4608bf47d2acc07e3887625","signature":"8b070b73bb6b42225b7c3b6625bda6664954cc3712229b18958a8943b340ae55","impliedFormat":99},{"version":"aa9efc0c0f844b992299237fc548c0d87a010e33d680ec3ef8dbfd1c7fdd4b39","signature":"5615bcac5653c419404afd7a69d3a2ea065d6d8d73d76f645dc72775da1bce2a","impliedFormat":99},{"version":"f72d2ef8589cbc9ef38bc0a1ce8e8226886673553f135c2ec7bab480a51a1b14","signature":"0949e43a56894d36a28c69ef7226bb234ea74de6bb8db9c88ccf270be3b15b52","impliedFormat":99},{"version":"12ff3a65e83059a171d45b077f870c9847c4ddffc7cb0afe9cb3d3086ec26ed9","signature":"96d6443ed4046f8418464504489b9f770f7a438b3bc7bf460fb86471d117e9a4","impliedFormat":99},{"version":"29488db8cc9b41928088c0a874a9740bee7c05b3aee6e02d8b1136aacbb3ea57","signature":"b4117081407f355734a73e4f2051edeafff14541bacaa61b2b5b74de3a6d9f91","impliedFormat":99},{"version":"cc898ec7bce7af4fb56cfc04a7bb2efd3d2b7d98ac92b74b2b4e67e7ddbf7cc2","signature":"617438c8ffeebd4b427114557e1a41f99cd439d9757e1daf742e1ce4e866e050","impliedFormat":99},{"version":"7f14dc4040d79c8027bba900d0009a387480c8fbcaef946540e7d55cb25d477d","signature":"02349a2b4e4df02eeb877449a91fa899932d9e2a7b8ef30b47cd5820af6ab06e","impliedFormat":99},{"version":"4cbe58c97ab6d95e9d3b88062a9a09fc9c4dc9173d416c2c03d3c60de633afc8","signature":"66d2b4311e142ded625c47020aba04457dc1827b2abe4a0bf5e4282b61927b41","impliedFormat":99},{"version":"4aa8cf2c03a4bef578adb195fa0048172418ddc37ef1a43521b74e659a901b3c","signature":"508df7438e5b78be306e1383ab15dbb7119fb2ca4cb13cd9cf26e0b2489afb65","impliedFormat":99},{"version":"6263b4a797ae57e4fa8f9f034db454d13b00e5f497f33d63ae48f391b3965bb2","signature":"ce5c319de9485f5bcdefb59099b3e4f23bf0f27fc8e3bbe7282f862a9f860b49","impliedFormat":99},{"version":"8ffaac172d85e0da751e89c9115923b322afd5db8b8971b7e39a5f449e0f2d72","signature":"847f3e5260297cd02349d4fdf0ade2a89e11767d04441dd7e909bd44cb7e359f","impliedFormat":99},{"version":"04f0e5540074077b5194e4e50f045b07ea1c0d4ba639f2a90c25d415be93d62a","impliedFormat":99},{"version":"05c0a6903b06e02a54a65557ce552a38890e1eae2d4924fdc63f5d8c7d48a51f","signature":"ddbb7587357abb10688237ca0e2115ff0b141bc5addf52063ba8e05c7904c183","impliedFormat":99},{"version":"8df9a1e93f38ef9e5a02ac6d69550714fa74c0aa2b2417d1e0c935270bbb2845","signature":"c23f869061db4adee9e58bfe744589b000cb97989e1c658315b86fc61aa7cb24","impliedFormat":99},{"version":"d7945a051dd621e39b53921bbf255a067fcdcdd1d2e57749dca4de8e66115251","signature":"4d806524986070b7c9f6019a46f045e083570cd6eaa6b7bb7da0d438e1ea9d9b","impliedFormat":99},{"version":"bc3158925d8f0417aea29d03f80f8bf7fc01a75f1d8c93239ee794b4b2a40fa7","signature":"0a3f05296d25399d19f2dbf65a8537022f4e8ec42258892a801664d02b66e169","impliedFormat":99},{"version":"c2a3209fd29ed0b0daa24d258b108f7b4e4ba2656a99e529ceedd4a044b2edb8","impliedFormat":99},{"version":"a0bd6bccba91b399e4e98bb50ef2064f2dd1e5566151911526368667fb27f151","impliedFormat":99},{"version":"1b38d11a73ef55b188c688ce14f14c1805409afc8052822a32fbaa5154af78fa","signature":"4e89973a43a5c0e304e3b4adacfd647525168d6128ed218841f085610b36123b","impliedFormat":99},{"version":"2fd1ade8c0b26af4e165a0ba11d3e2f0a8d5d15f001611bf63772cb15b70ebde","signature":"052cdf9abce5e9252a42c5af82cb4591f03ecb83ebbb521fb74b31e2acd0ad79","impliedFormat":99},{"version":"eb29076a307e2750601d2eaf733b7b9b17c69d0156d47a2ba14cebf1ed66b0ce","signature":"76b1d15c83a9fd9909fd81e32024727743ae506de24a1bebc60719ad93cce0db","impliedFormat":99},{"version":"7e771891adaa85b690266bc37bd6eb43bc57eecc4b54693ead36467e7369952a","impliedFormat":1},{"version":"a69c09dbea52352f479d3e7ac949fde3d17b195abe90b045d619f747b38d6d1a","impliedFormat":1},{"version":"54ba7456adb777a685250cd144115ea51379784012ba1311255b715c6bdcff2a","affectsGlobalScope":true,"impliedFormat":1},{"version":"11e2d554398d2bd460e7d06b2fa5827a297c8acfbe00b4f894a224ac0862857f","impliedFormat":1},{"version":"e193e634a99c9c1d71f1c6e4e1567a4a73584328d21ea02dd5cddbaad6693f61","affectsGlobalScope":true,"impliedFormat":1},{"version":"374ca798f244e464346f14301dc2a8b4b111af1a83b49fffef5906c338a1f922","impliedFormat":1},{"version":"5a94487653355b56018122d92392beb2e5f4a6c63ba5cef83bbe1c99775ef713","impliedFormat":1},{"version":"d5135ad93b33adcce80b18f8065087934cdc1730d63db58562edcf017e1aad9b","affectsGlobalScope":true,"impliedFormat":1},{"version":"82408ed3e959ddc60d3e9904481b5a8dc16469928257af22a3f7d1a3bc7fd8c4","impliedFormat":1},{"version":"5450889a3b688f9da80e7c96963b2cfebc6097e8e95790a23a48558b61e6aea7","impliedFormat":1},{"version":"bb9c4ffa5e6290c6980b63c815cdd1625876dadb2efaf77edbe82984be93e55e","impliedFormat":1},{"version":"489532ff54b714f0e0939947a1c560e516d3ae93d51d639ab02e907a0e950114","impliedFormat":1},{"version":"f30bb836526d930a74593f7b0f5c1c46d10856415a8f69e5e2fc3db80371e362","impliedFormat":1},{"version":"14b5aa23c5d0ae1907bc696ac7b6915d88f7d85799cc0dc2dcf98fbce2c5a67c","impliedFormat":1},{"version":"5c439dafdc09abe4d6c260a96b822fa0ba5be7203c71a63ab1f1423cd9e838ea","impliedFormat":1},{"version":"6b526a5ec4a401ca7c26cfe6a48e641d8f30af76673bad3b06a1b4504594a960","affectsGlobalScope":true,"impliedFormat":1},{"version":"816ad2e607a96de5bcac7d437f843f5afd8957f1fa5eefa6bba8e4ed7ca8fd84","affectsGlobalScope":true,"impliedFormat":1},{"version":"80473bd0dd90ca1e166514c2dfead9d5803f9c51418864ca35abbeec6e6847e1","impliedFormat":1},{"version":"1c84b46267610a34028edfd0d035509341751262bac1062857f3c8df7aff7153","impliedFormat":1},{"version":"5eec82ac21f84d83586c59a16b9b8502d34505d1393393556682fe7e7fde9ef2","impliedFormat":1},{"version":"04eb6578a588d6a46f50299b55f30e3a04ef27d0c5a46c57d8fcc211cd530faa","impliedFormat":1},{"version":"8d3c583a07e0c37e876908c2d5da575019f689df8d9fa4c081d99119d53dba22","impliedFormat":1},{"version":"2c828a5405191d006115ab34e191b8474bc6c86ffdc401d1a9864b1b6e088a58","impliedFormat":1},{"version":"e630e5528e899219ae319e83bef54bf3bcb91b01d76861ecf881e8e614b167f0","affectsGlobalScope":true,"impliedFormat":1},{"version":"bcebb922784739bdb34c18ee51095d25a92b560c78ccd2eaacd6bd00f7443d83","impliedFormat":1},{"version":"7ee6ed878c4528215c82b664fe0cfe80e8b4da6c0d4cc80869367868774db8b1","impliedFormat":1},{"version":"b0973c3cbcdc59b37bf477731d468696ecaf442593ec51bab497a613a580fe30","impliedFormat":1},{"version":"4989e92ba5b69b182d2caaea6295af52b7dc73a4f7a2e336a676722884e7139d","affectsGlobalScope":true,"impliedFormat":1},{"version":"b3624aed92dab6da8484280d3cb3e2f4130ec3f4ef3f8201c95144ae9e898bb6","affectsGlobalScope":true,"impliedFormat":1},{"version":"5153a2fd150e46ce57bb3f8db1318d33f6ad3261ed70ceeff92281c0608c74a3","impliedFormat":1},{"version":"210d54cd652ec0fec8c8916e4af59bb341065576ecda039842f9ffb2e908507c","impliedFormat":1},{"version":"36b03690b628eab08703d63f04eaa89c5df202e5f1edf3989f13ad389cd2c091","impliedFormat":1},{"version":"0effadd232a20498b11308058e334d3339cc5bf8c4c858393e38d9d4c0013dcf","impliedFormat":1},{"version":"25846d43937c672bab7e8195f3d881f93495df712ee901860effc109918938cc","impliedFormat":1},{"version":"fd93cee2621ff42dabe57b7be402783fd1aa69ece755bcba1e0290547ae60513","impliedFormat":1},{"version":"1b952304137851e45bc009785de89ada562d9376177c97e37702e39e60c2f1ff","impliedFormat":1},{"version":"69ee23dd0d215b09907ad30d23f88b7790c93329d1faf31d7835552a10cf7cbf","impliedFormat":1},{"version":"44b8b584a338b190a59f4f6929d072431950c7bd92ec2694821c11bce180c8a5","impliedFormat":1},{"version":"23b89798789dffbd437c0c423f5d02d11f9736aea73d6abf16db4f812ff36eda","impliedFormat":1},{"version":"09326ae5f7e3d49be5cd9ea00eb814770e71870a438faa2efd8bdd9b4db21320","impliedFormat":1},{"version":"3c4ba1dd9b12ffa284b565063108f2f031d150ea15b8fafbdc17f5d2a07251f3","affectsGlobalScope":true,"impliedFormat":1},{"version":"e10177274a35a9d07c825615340b2fcde2f610f53f3fb40269fd196b4288dda6","impliedFormat":1},{"version":"c4577fb855ca259bdbf3ea663ca73988ce5f84251a92b4aef80a1f4122b6f98e","impliedFormat":1},{"version":"3c13ef48634e7b5012fcf7e8fce7496352c2d779a7201389ca96a2a81ee4314d","impliedFormat":1},{"version":"5d0a25ec910fa36595f85a67ac992d7a53dd4064a1ba6aea1c9f14ab73a023f2","impliedFormat":1},{"version":"f0900cd5d00fe1263ff41201fb8073dbeb984397e4af3b8002a5c207a30bdc33","affectsGlobalScope":true,"impliedFormat":1},{"version":"ff07a9a03c65732ccc59b3c65bc584173da093bd563a6565411c01f5703bd3cb","affectsGlobalScope":true,"impliedFormat":1},{"version":"06d7c42d256f0ce6afe1b2b6cfbc97ab391f29dadb00dd0ae8e8f23f5bc916c3","impliedFormat":1},{"version":"ec4bd1b200670fb567920db572d6701ed42a9641d09c4ff6869768c8f81b404c","impliedFormat":1},{"version":"e59a892d87e72733e2a9ca21611b9beb52977be2696c7ba4b216cbbb9a48f5aa","impliedFormat":1},{"version":"da26af7362f53d122283bc69fed862b9a9fe27e01bc6a69d1d682e0e5a4df3e6","affectsGlobalScope":true,"impliedFormat":1},{"version":"8a300fa9b698845a1f9c41ecbe2c5966634582a8e2020d51abcace9b55aa959e","impliedFormat":1},{"version":"ab9b9a36e5284fd8d3bf2f7d5fcbc60052f25f27e4d20954782099282c60d23e","affectsGlobalScope":true,"impliedFormat":1},{"version":"d8d555f3d607ecaa18d55de6995ea8f206342ecc93305919eac945c7c78c78c6","impliedFormat":1},{"version":"409b21f3d0c198cc4866b941cd9303809a13230e2b9b3c1508fe61348a8b43ed","impliedFormat":1},{"version":"49afdedca00d22b171678e3cf9c47b7e0c1846fd4905a01d68f0145eb90add94","impliedFormat":1},{"version":"7a1b0fbc4287cb7513c0a10d9b53f5acc32d3ced53b2d786711901d483c4dbb4","impliedFormat":1},{"version":"8408c66a83053c21d93e73c1f6773647ccdb60fb9468f99341e389f3bfa35ad7","impliedFormat":1},{"version":"51108a0b63dc5dd793d26c1b185df7cfa1d1bf1a6e4ad9ce6f9d7ca8eb65b4ed","signature":"8a0ab25856a3fcd2c10da218932bb157fcab3ae61294c3506200f28f5d19b9c1","impliedFormat":99},{"version":"bff5e7e514980487864d34f69b6eda6f93506aff6dd9ced75f9a172ded1a71b4","impliedFormat":99},{"version":"f87022015c1924d3d60ae66c192366518af8617f7243af5af17d46a1d4d09764","signature":"9e6e67d4df1a320ac0ec7e2b58e98b332c2b4a7b2d88e1fe7463634a81f219e0","impliedFormat":99},{"version":"2c425702763ca7d738b2f0080be64d366a0818106a73c2595ed3ea51967f18c8","impliedFormat":1},{"version":"91f4e4de96699e0a21d50885d00d1dce8695f78788e3bdf40d33a299896be442","signature":"955a24e28310e9b71695b601e309957702e2da09e67f5bc5359bfae4a603e9b6","impliedFormat":99},{"version":"ac030f3c41a1797c673137478c675da6542c0676341c85f68b93fcecaaeb4778","impliedFormat":99},{"version":"afde802c7508bfa466977ea232329057a307f777c8499ee651b7abf65d65c503","signature":"de24ca8d9277f1e78c0a904ab762dca156aa55b6ae6fb2bb27c39c9193ca9b93","impliedFormat":99},{"version":"0679dbdd43d4fae7b84baf09c5299ef7fca6effba02e711fb3bcabfe4b3719ca","impliedFormat":99},{"version":"c0c2b6bb02ec7f862cb53fe5455c4333387396423b5d5e8dd2ce1a2ef294fc90","signature":"15b413ec98335b7ec0d6068d0b10ae7d4cf794b8c93cb923bed2364ff85d372c","impliedFormat":99},{"version":"1893a547b8fbe550e167f6e8c9ae7c93bda50a72121c83aac21902fd333c2274","impliedFormat":99},{"version":"d1b4b30ab8fc253dd8606c0742c2ac08d2963b98b3bbfeabc98aabb0a5775799","impliedFormat":99},{"version":"dc9806a1a14bc9f601a6e16f016ccb22b045e84d3d3ccaf49c4e05fb49b30fb7","signature":"c9b16149b0bcedd5843245a14a41729109ec43f7b9ca8dad7660d6247766c290","impliedFormat":99},{"version":"46a360e67861a830045b0a33cdb99708cb41fbe00a58def5c08716f1816701b0","signature":"e2818909ec58404f3a37a96893be135599bda8581f76ed311370fa4c4b3220a2","impliedFormat":99},{"version":"3078727fed04c123165efdb42deeac5dceaa42ac62216ca13cb809dc7e13415f","impliedFormat":1},{"version":"cc957354aa3c94c9961ebf46282cfde1e81d107fc5785a61f62c67f1dd3ac2eb","impliedFormat":1},{"version":"b4f76b34637d79cefad486127115fed843762c69512d7101b7096e1293699679","impliedFormat":1},{"version":"93de1c6dab503f053efe8d304cb522bb3a89feab8c98f307a674a4fae04773e9","impliedFormat":1},{"version":"dae3d1adc67ac3dbd1cd471889301339ec439837b5df565982345be20c8fca9a","impliedFormat":1},{"version":"b6ddf3a46ccfa4441d8be84d2e9bf3087573c48804196faedbd4a25b60631beb","impliedFormat":1},{"version":"01f7828047b5c6703d3c601473618b448f5506a88fcac852638b0715c3abf4eb","impliedFormat":1},{"version":"3896464bb7e25fceebbd9c8a0b443caaa9b68ec323f46191c36b84293c852a19","impliedFormat":1},{"version":"b8a427b9fe88504a6fb092e21adfe272d144394a2ced7f9e4adc3de7efa6e216","impliedFormat":1},{"version":"bf88ef4208a770ca39a844b182b3695df536326ea566893fdc5b8418702a331e","impliedFormat":1},{"version":"53acffbcae83dbdd20b2eeaf06a459da0f26a74e99e76fd28325b48e9e9de0d0","impliedFormat":1},{"version":"8b06ac3faeacb8484d84ddb44571d8f410697f98d7bfa86c0fda60373a9f5215","impliedFormat":1},{"version":"7eb06594824ada538b1d8b48c3925a83e7db792f47a081a62cf3e5c4e23cf0ee","impliedFormat":1},{"version":"f5638f7c2f12a9a1a57b5c41b3c1ea7db3876c003bab68e6a57afd6bcc169af0","impliedFormat":1},{"version":"6c1e688f95fcaf53b1e41c0fdadf2c1cfc96fa924eaf7f9fdb60f96deb0a4986","impliedFormat":1},{"version":"0d14fa22c41fdc7277e6f71473b20ebc07f40f00e38875142335d5b63cdfc9d2","impliedFormat":1},{"version":"db25694be959314fd1e868d72e567746db1db9e2001fae545d12d2a8c1bba1b8","impliedFormat":1},{"version":"43883cf3635bb1846cbdc6c363787b76227677388c74f7313e3f0edb380840fa","impliedFormat":1},{"version":"2d47012580f859dae201d2eef898a416bdae719dffc087dfd06aefe3de2f9c8d","impliedFormat":1},{"version":"3e70a7e67c2cb16f8cd49097360c0309fe9d1e3210ff9222e9dac1f8df9d4fb6","impliedFormat":1},{"version":"ab68d2a3e3e8767c3fba8f80de099a1cfc18c0de79e42cb02ae66e22dfe14a66","impliedFormat":1},{"version":"2cec1a31729b9b01e9294c33fc9425d336eff067282809761ad2e74425d6d2a5","impliedFormat":1},{"version":"2d47012580f859dae201d2eef898a416bdae719dffc087dfd06aefe3de2f9c8d","impliedFormat":1},{"version":"e10991edf67a29051eda3bf649ccc653ae1dc55b5363fa0f559f802b2017aa02","affectsGlobalScope":true,"impliedFormat":1},{"version":"f3e604694b624fa3f83f6684185452992088f5efb2cf136b62474aa106d6f1b6","impliedFormat":1},{"version":"bc88e4049153bc4dddb4503ed7e624eb141edfa9064b3659d6c86e900fe9e621","impliedFormat":1},{"version":"2b93035328f7778d200252681c1d86285d501ed424825a18f81e4c3028aa51d9","impliedFormat":1},{"version":"2ac9c8332c5f8510b8bdd571f8271e0f39b0577714d5e95c1e79a12b2616f069","impliedFormat":1},{"version":"42c21aa963e7b86fa00801d96e88b36803188018d5ad91db2a9101bccd40b3ff","impliedFormat":1},{"version":"d31eb848cdebb4c55b4893b335a7c0cca95ad66dee13cbb7d0893810c0a9c301","impliedFormat":1},{"version":"77c1d91a129ba60b8c405f9f539e42df834afb174fe0785f89d92a2c7c16b77a","impliedFormat":1},{"version":"7a9e0a564fee396cacf706523b5aeed96e04c6b871a8bebefad78499fbffc5bc","impliedFormat":1},{"version":"906c751ef5822ec0dadcea2f0e9db64a33fb4ee926cc9f7efa38afe5d5371b2a","impliedFormat":1},{"version":"5387c049e9702f2d2d7ece1a74836a14b47fbebe9bbeb19f94c580a37c855351","impliedFormat":1},{"version":"c68391fb9efad5d99ff332c65b1606248c4e4a9f1dd9a087204242b56c7126d6","impliedFormat":1},{"version":"e9cf02252d3a0ced987d24845dcb1f11c1be5541f17e5daa44c6de2d18138d0c","impliedFormat":1},{"version":"e8b02b879754d85f48489294f99147aeccc352c760d95a6fe2b6e49cd400b2fe","impliedFormat":1},{"version":"9f6908ab3d8a86c68b86e38578afc7095114e66b2fc36a2a96e9252aac3998e0","impliedFormat":1},{"version":"0eedb2344442b143ddcd788f87096961cd8572b64f10b4afc3356aa0460171c6","impliedFormat":1},{"version":"71405cc70f183d029cc5018375f6c35117ffdaf11846c35ebf85ee3956b1b2a6","impliedFormat":1},{"version":"c68baff4d8ba346130e9753cefe2e487a16731bf17e05fdacc81e8c9a26aae9d","impliedFormat":1},{"version":"2cd15528d8bb5d0453aa339b4b52e0696e8b07e790c153831c642c3dea5ac8af","impliedFormat":1},{"version":"479d622e66283ffa9883fbc33e441f7fc928b2277ff30aacbec7b7761b4e9579","impliedFormat":1},{"version":"ade307876dc5ca267ca308d09e737b611505e015c535863f22420a11fffc1c54","impliedFormat":1},{"version":"f8cdefa3e0dee639eccbe9794b46f90291e5fd3989fcba60d2f08fde56179fb9","impliedFormat":1},{"version":"86c5a62f99aac7053976e317dbe9acb2eaf903aaf3d2e5bb1cafe5c2df7b37a8","impliedFormat":1},{"version":"2b300954ce01a8343866f737656e13243e86e5baef51bd0631b21dcef1f6e954","impliedFormat":1},{"version":"a2d409a9ffd872d6b9d78ead00baa116bbc73cfa959fce9a2f29d3227876b2a1","impliedFormat":1},{"version":"b288936f560cd71f4a6002953290de9ff8dfbfbf37f5a9391be5c83322324898","impliedFormat":1},{"version":"61178a781ef82e0ff54f9430397e71e8f365fc1e3725e0e5346f2de7b0d50dfa","impliedFormat":1},{"version":"6a6ccb37feb3aad32d9be026a3337db195979cd5727a616fc0f557e974101a54","impliedFormat":1},{"version":"c649ea79205c029a02272ef55b7ab14ada0903db26144d2205021f24727ac7a3","impliedFormat":1},{"version":"38e2b02897c6357bbcff729ef84c736727b45cc152abe95a7567caccdfad2a1d","impliedFormat":1},{"version":"d6610ea7e0b1a7686dba062a1e5544dd7d34140f4545305b7c6afaebfb348341","impliedFormat":1},{"version":"3dee35db743bdba2c8d19aece7ac049bde6fa587e195d86547c882784e6ba34c","impliedFormat":1},{"version":"b15e55c5fa977c2f25ca0b1db52cfa2d1fd4bf0baf90a8b90d4a7678ca462ff1","impliedFormat":1},{"version":"f41d30972724714763a2698ae949fbc463afb203b5fa7c4ad7e4de0871129a17","impliedFormat":1},{"version":"843dd7b6a7c6269fd43827303f5cbe65c1fecabc30b4670a50d5a15d57daeeb9","impliedFormat":1},{"version":"f06d8b8567ee9fd799bf7f806efe93b67683ef24f4dea5b23ef12edff4434d9d","impliedFormat":1},{"version":"6017384f697ff38bc3ef6a546df5b230c3c31329db84cbfe686c83bec011e2b2","impliedFormat":1},{"version":"e1a5b30d9248549ca0c0bb1d653bafae20c64c4aa5928cc4cd3017b55c2177b0","impliedFormat":1},{"version":"a593632d5878f17295bd53e1c77f27bf4c15212822f764a2bfc1702f4b413fa0","impliedFormat":1},{"version":"a868a534ba1c2ca9060b8a13b0ffbbbf78b4be7b0ff80d8c75b02773f7192c29","impliedFormat":1},{"version":"da7545aba8f54a50fde23e2ede00158dc8112560d934cee58098dfb03aae9b9d","impliedFormat":1},{"version":"34baf65cfee92f110d6653322e2120c2d368ee64b3c7981dff08ed105c4f19b0","impliedFormat":1},{"version":"6aee496bf0ecfbf6731aa8cca32f4b6e92cdc0a444911a7d88410408a45ecc5d","impliedFormat":1},{"version":"b0d10e46cfe3f6c476b69af02eaa38e4ccc7430221ce3109ae84bb9fb8282298","impliedFormat":1},{"version":"12fe557e4c2d5ce9e11362f69a8d7c05d0588de4ae415afe8c5106da5c2772aa","impliedFormat":1},{"version":"70e9a18da08294f75bf23e46c7d69e67634c0765d355887b9b41f0d959e1426e","impliedFormat":1},{"version":"ae84439d1ae42b30ced3df38c4285f35b805be40dfc95b0647d0e59c70b11f97","impliedFormat":1}],"options":{"allowSyntheticDefaultImports":true,"composite":true,"declaration":true,"declarationMap":true,"downlevelIteration":true,"esModuleInterop":true,"importHelpers":true,"inlineSourceMap":true,"module":199,"outDir":"./dest","rootDir":"./src","strict":true,"target":7,"tsBuildInfoFile":"./.tsbuildinfo"},"fileIdsList":[[132],[132,157],[132,173],[132,157,158,159,160,161],[132,157,159],[132,139],[132,163],[103,132,139],[132,168],[132,169],[132,175,178],[132,174],[132,139,140],[102,132,139,140,141],[132,140],[86,132],[89,132],[90,95,123,132],[91,102,103,110,120,131,132],[91,92,102,110,132],[93,132],[94,95,103,111,132],[95,120,128,132],[96,98,102,110,132],[97,132],[98,99,132],[102,132],[100,102,132],[102,103,104,120,131,132],[102,103,104,117,120,123,132],[132,136],[98,105,110,120,131,132],[102,103,105,106,110,120,128,131,132],[105,107,120,128,131,132],[86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138],[102,108,132],[109,131,132],[98,102,110,120,132],[111,132],[112,132],[89,113,132],[114,130,132,136],[115,132],[116,132],[102,117,118,132],[117,119,132,134],[90,102,120,121,122,123,132],[90,120,122,132],[120,121,132],[123,132],[124,132],[102,126,127,132],[126,127,132],[95,110,120,128,132],[129,132],[110,130,132],[90,105,116,131,132],[95,132],[120,132,133],[132,134],[132,135],[90,95,102,104,113,120,131,132,134,136],[120,132,137],[132,183,222],[132,183,207,222],[132,222],[132,183],[132,183,208,222],[132,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221],[132,208,222],[132,225],[132,171,177],[132,172,176],[132,175],[56,67,82,132,145,149,151,153],[56,132],[56,72,73,74,75,132],[56,64,132],[56,65,71,132],[56,69,71,102,132],[56,62,66,67,102,132],[56,62,63,64,65,66,67,68,69,70,76,81,132],[56,64,102,132],[56,78,80,132],[56,65,77,132,136],[56,64,132,136],[56,69,79,102,132,136],[56,57,63,64,65,102,132],[56,63,64,67,69,132],[56,61,132],[56,57,132],[56,61,132,152],[56,57,59,60,90,95,132],[56,84,132,144],[56,61,82,132],[56,85,132,142,143],[56,61,82,83,132],[56,83,132,150],[56,132,146,148],[56,85,132,142,143,147],[56,61,82,83,132,136],[56,61,82,132,136],[56,57,83,132],[64],[65,71],[69,102],[62,66,67],[64,102],[65,77,136],[64,136],[65,102],[69],[61],[57],[57,90],[85],[83],[61,82]],"referencedMap":[[57,1],[159,2],[157,1],[171,1],[174,3],[173,1],[140,1],[162,4],[158,2],[160,5],[161,2],[163,6],[164,1],[165,7],[166,8],[167,6],[168,1],[169,9],[170,10],[180,11],[179,12],[181,1],[141,1],[147,13],[142,14],[143,15],[86,16],[87,16],[89,17],[90,18],[91,19],[92,20],[93,21],[94,22],[95,23],[96,24],[97,25],[98,26],[99,26],[101,27],[100,28],[102,27],[103,29],[104,30],[88,31],[138,1],[105,32],[106,33],[107,34],[139,35],[108,36],[109,37],[110,38],[111,39],[112,40],[113,41],[114,42],[115,43],[116,44],[117,45],[118,45],[119,46],[120,47],[122,48],[121,49],[123,50],[124,51],[125,1],[126,52],[127,53],[128,54],[129,55],[130,56],[131,57],[132,58],[133,59],[134,60],[135,61],[136,62],[137,63],[182,1],[207,64],[208,65],[183,66],[186,66],[205,64],[206,64],[196,64],[195,67],[193,64],[188,64],[201,64],[199,64],[203,64],[187,64],[200,64],[204,64],[189,64],[190,64],[202,64],[184,64],[191,64],[192,64],[194,64],[198,64],[209,68],[197,64],[185,64],[222,69],[221,1],[216,68],[218,70],[217,68],[210,68],[211,68],[213,68],[215,68],[219,70],[220,70],[212,70],[214,70],[223,1],[224,1],[225,1],[226,71],[58,1],[172,1],[178,72],[177,73],[176,74],[175,12],[56,1],[11,1],[13,1],[12,1],[2,1],[14,1],[15,1],[16,1],[17,1],[18,1],[19,1],[20,1],[21,1],[3,1],[4,1],[25,1],[22,1],[23,1],[24,1],[26,1],[27,1],[28,1],[5,1],[29,1],[30,1],[31,1],[32,1],[6,1],[36,1],[33,1],[34,1],[35,1],[37,1],[7,1],[38,1],[43,1],[44,1],[39,1],[40,1],[41,1],[42,1],[8,1],[48,1],[45,1],[46,1],[47,1],[49,1],[9,1],[50,1],[51,1],[52,1],[53,1],[54,1],[1,1],[10,1],[55,1],[154,75],[59,76],[76,77],[71,78],[74,79],[75,80],[72,79],[73,80],[62,76],[68,81],[63,76],[82,82],[65,78],[69,83],[64,76],[67,76],[81,84],[78,85],[77,86],[80,87],[79,86],[66,88],[70,89],[152,90],[60,91],[153,92],[61,93],[145,94],[155,95],[144,96],[84,97],[85,76],[151,98],[149,99],[148,100],[146,101],[156,102],[83,95],[150,103]],"exportedModulesMap":[[57,1],[159,2],[157,1],[171,1],[174,3],[173,1],[140,1],[162,4],[158,2],[160,5],[161,2],[163,6],[164,1],[165,7],[166,8],[167,6],[168,1],[169,9],[170,10],[180,11],[179,12],[181,1],[141,1],[147,13],[142,14],[143,15],[86,16],[87,16],[89,17],[90,18],[91,19],[92,20],[93,21],[94,22],[95,23],[96,24],[97,25],[98,26],[99,26],[101,27],[100,28],[102,27],[103,29],[104,30],[88,31],[138,1],[105,32],[106,33],[107,34],[139,35],[108,36],[109,37],[110,38],[111,39],[112,40],[113,41],[114,42],[115,43],[116,44],[117,45],[118,45],[119,46],[120,47],[122,48],[121,49],[123,50],[124,51],[125,1],[126,52],[127,53],[128,54],[129,55],[130,56],[131,57],[132,58],[133,59],[134,60],[135,61],[136,62],[137,63],[182,1],[207,64],[208,65],[183,66],[186,66],[205,64],[206,64],[196,64],[195,67],[193,64],[188,64],[201,64],[199,64],[203,64],[187,64],[200,64],[204,64],[189,64],[190,64],[202,64],[184,64],[191,64],[192,64],[194,64],[198,64],[209,68],[197,64],[185,64],[222,69],[221,1],[216,68],[218,70],[217,68],[210,68],[211,68],[213,68],[215,68],[219,70],[220,70],[212,70],[214,70],[223,1],[224,1],[225,1],[226,71],[58,1],[172,1],[178,72],[177,73],[176,74],[175,12],[56,1],[11,1],[13,1],[12,1],[2,1],[14,1],[15,1],[16,1],[17,1],[18,1],[19,1],[20,1],[21,1],[3,1],[4,1],[25,1],[22,1],[23,1],[24,1],[26,1],[27,1],[28,1],[5,1],[29,1],[30,1],[31,1],[32,1],[6,1],[36,1],[33,1],[34,1],[35,1],[37,1],[7,1],[38,1],[43,1],[44,1],[39,1],[40,1],[41,1],[42,1],[8,1],[48,1],[45,1],[46,1],[47,1],[49,1],[9,1],[50,1],[51,1],[52,1],[53,1],[54,1],[1,1],[10,1],[55,1],[154,75],[76,77],[71,104],[74,105],[75,106],[72,105],[73,106],[68,107],[82,82],[65,104],[69,108],[81,84],[78,109],[77,110],[80,106],[79,110],[66,111],[70,112],[152,113],[60,114],[153,92],[61,115],[145,94],[155,113],[144,116],[84,117],[151,98],[149,99],[148,116],[146,117],[156,113],[83,118],[150,117]],"semanticDiagnosticsPerFile":[57,159,157,171,174,173,140,162,158,160,161,163,164,165,166,167,168,169,170,180,179,181,141,147,142,143,86,87,89,90,91,92,93,94,95,96,97,98,99,101,100,102,103,104,88,138,105,106,107,139,108,109,110,111,112,113,114,115,116,117,118,119,120,122,121,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,182,207,208,183,186,205,206,196,195,193,188,201,199,203,187,200,204,189,190,202,184,191,192,194,198,209,197,185,222,221,216,218,217,210,211,213,215,219,220,212,214,223,224,225,226,58,172,178,177,176,175,56,11,13,12,2,14,15,16,17,18,19,20,21,3,4,25,22,23,24,26,27,28,5,29,30,31,32,6,36,33,34,35,37,7,38,43,44,39,40,41,42,8,48,45,46,47,49,9,50,51,52,53,54,1,10,55,154,59,76,71,74,75,72,73,62,68,63,82,65,69,64,67,81,78,77,80,79,66,70,152,60,153,61,145,155,144,84,85,151,149,148,146,156,83,150],"latestChangedDtsFile":"./dest/worker/node/start_node_module.d.ts"},"version":"4.9.5"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/Dockerfile b/circuits/ts/.yalc/@aztec/wasm/Dockerfile new file mode 100644 index 00000000000..ff060f58035 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/Dockerfile @@ -0,0 +1,14 @@ +FROM 278380418400.dkr.ecr.eu-west-2.amazonaws.com/yarn-project-base AS builder + +COPY wasm wasm +WORKDIR /usr/src/yarn-project/wasm +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 alpine:latest +COPY --from=builder /usr/src/yarn-project/wasm /usr/src/yarn-project/wasm +WORKDIR /usr/src/yarn-project/wasm +ENTRYPOINT ["yarn"] \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/README.md b/circuits/ts/.yalc/@aztec/wasm/README.md new file mode 100644 index 00000000000..b15e7756288 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/README.md @@ -0,0 +1,6 @@ +# wasm + +Functionality to: + +1. Call WebAssembly functions +2. Create asynchronous workers that host webassembly. diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/index.d.ts b/circuits/ts/.yalc/@aztec/wasm/dest/index.d.ts new file mode 100644 index 00000000000..a363b56ac21 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/index.d.ts @@ -0,0 +1,8 @@ +export { WebDataStore } from './worker/browser/index.js'; +export { NodeDataStore } from './worker/node/index.js'; +export { WasmWorker, WorkerPool } from './worker/index.js'; +export { WasmModule } from './wasm/index.js'; +export { AsyncCallState, AsyncFnState } from './wasm/index.js'; +export { DispatchMsg, WorkerListener, TransportServer, NodeListener } from './transport/index.js'; +export { Transfer, isTransferDescriptor } from './transport/interface/transferable.js'; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/index.d.ts.map b/circuits/ts/.yalc/@aztec/wasm/dest/index.d.ts.map new file mode 100644 index 00000000000..a6a4ba63857 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAClG,OAAO,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/index.js b/circuits/ts/.yalc/@aztec/wasm/dest/index.js new file mode 100644 index 00000000000..6f596b65715 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/index.js @@ -0,0 +1,8 @@ +export { WebDataStore } from './worker/browser/index.js'; +export { NodeDataStore } from './worker/node/index.js'; +export { WorkerPool } from './worker/index.js'; +export { WasmModule } from './wasm/index.js'; +export { AsyncCallState } from './wasm/index.js'; +export { WorkerListener, TransportServer, NodeListener } from './transport/index.js'; +export { Transfer, isTransferDescriptor } from './transport/interface/transferable.js'; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQ3pELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUN2RCxPQUFPLEVBQWMsVUFBVSxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDM0QsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQzdDLE9BQU8sRUFBRSxjQUFjLEVBQWdCLE1BQU0saUJBQWlCLENBQUM7QUFDL0QsT0FBTyxFQUFlLGNBQWMsRUFBRSxlQUFlLEVBQUUsWUFBWSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDbEcsT0FBTyxFQUFFLFFBQVEsRUFBRSxvQkFBb0IsRUFBRSxNQUFNLHVDQUF1QyxDQUFDIn0= \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/memory_fifo.d.ts b/circuits/ts/.yalc/@aztec/wasm/dest/memory_fifo.d.ts new file mode 100644 index 00000000000..de592d842b4 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/memory_fifo.d.ts @@ -0,0 +1,46 @@ +/** + * A simple fifo queue. It can grow unbounded. It can have multiple producers and consumers. + * Putting an item onto the queue always succeeds, unless either end() or cancel() has been called in which case + * the item being pushed is simply discarded. + */ +export declare class MemoryFifo { + private waiting; + private items; + private flushing; + /** + * Length of queue. + * @returns integer. + */ + length(): number; + /** + * Returns next item within the queue, or blocks until and item has been put into the queue. + * If given a timeout, the promise will reject if no item is received after `timeout` seconds. + * If the queue is flushing, `null` is returned. + * @param timeout - In seconds. + * @returns Promise of result. + */ + get(timeout?: number): Promise; + /** + * Put an item onto back of the queue. + * @param item - The item to enqueue. + */ + put(item: T): void; + /** + * Once ended, no further items are added to queue. Consumers will consume remaining items within the queue. + * The queue is not reusable after calling `end()`. + * Any consumers waiting for an item receive null. + */ + end(): void; + /** + * Once cancelled, all items are discarded from the queue, and no further items are added to the queue. + * The queue is not reusable after calling `cancel()`. + * Any consumers waiting for an item receive null. + */ + cancel(): void; + /** + * Helper method that can be used to continously consume and process items on the queue. + * @param handler - The item handler function. + */ + process(handler: (item: T) => Promise): Promise; +} +//# sourceMappingURL=memory_fifo.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/memory_fifo.d.ts.map b/circuits/ts/.yalc/@aztec/wasm/dest/memory_fifo.d.ts.map new file mode 100644 index 00000000000..9bb1710ce16 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/memory_fifo.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"memory_fifo.d.ts","sourceRoot":"","sources":["../src/memory_fifo.ts"],"names":[],"mappings":"AACA;;;;GAIG;AACH,qBAAa,UAAU,CAAC,CAAC;IACvB,OAAO,CAAC,OAAO,CAAoC;IACnD,OAAO,CAAC,KAAK,CAAW;IACxB,OAAO,CAAC,QAAQ,CAAS;IAEzB;;;OAGG;IACI,MAAM;IAIb;;;;;;OAMG;IACI,GAAG,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAyB/C;;;OAGG;IACI,GAAG,CAAC,IAAI,EAAE,CAAC;IAUlB;;;;OAIG;IACI,GAAG;IAKV;;;;OAIG;IACI,MAAM;IAMb;;;OAGG;IACU,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC;CAazD"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/memory_fifo.js b/circuits/ts/.yalc/@aztec/wasm/dest/memory_fifo.js new file mode 100644 index 00000000000..f742e3a773c --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/memory_fifo.js @@ -0,0 +1,101 @@ +// TODO should come from a dependency +/** + * A simple fifo queue. It can grow unbounded. It can have multiple producers and consumers. + * Putting an item onto the queue always succeeds, unless either end() or cancel() has been called in which case + * the item being pushed is simply discarded. + */ +export class MemoryFifo { + constructor() { + this.waiting = []; + this.items = []; + this.flushing = false; + } + /** + * Length of queue. + * @returns integer. + */ + length() { + return this.items.length; + } + /** + * Returns next item within the queue, or blocks until and item has been put into the queue. + * If given a timeout, the promise will reject if no item is received after `timeout` seconds. + * If the queue is flushing, `null` is returned. + * @param timeout - In seconds. + * @returns Promise of result. + */ + get(timeout) { + if (this.items.length) { + return Promise.resolve(this.items.shift()); + } + if (this.items.length === 0 && this.flushing) { + return Promise.resolve(null); + } + return new Promise((resolve, reject) => { + this.waiting.push(resolve); + if (timeout) { + setTimeout(() => { + const index = this.waiting.findIndex(r => r === resolve); + if (index > -1) { + this.waiting.splice(index, 1); + const err = new Error('Timeout getting item from queue.'); + reject(err); + } + }, timeout * 1000); + } + }); + } + /** + * Put an item onto back of the queue. + * @param item - The item to enqueue. + */ + put(item) { + if (this.flushing) { + return; + } + else if (this.waiting.length) { + this.waiting.shift()(item); + } + else { + this.items.push(item); + } + } + /** + * Once ended, no further items are added to queue. Consumers will consume remaining items within the queue. + * The queue is not reusable after calling `end()`. + * Any consumers waiting for an item receive null. + */ + end() { + this.flushing = true; + this.waiting.forEach(resolve => resolve(null)); + } + /** + * Once cancelled, all items are discarded from the queue, and no further items are added to the queue. + * The queue is not reusable after calling `cancel()`. + * Any consumers waiting for an item receive null. + */ + cancel() { + this.flushing = true; + this.items = []; + this.waiting.forEach(resolve => resolve(null)); + } + /** + * Helper method that can be used to continously consume and process items on the queue. + * @param handler - The item handler function. + */ + async process(handler) { + try { + while (true) { + const item = await this.get(); + if (item === null) { + break; + } + await handler(item); + } + } + catch (err) { + console.error('Queue handler exception:', err); + } + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVtb3J5X2ZpZm8uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvbWVtb3J5X2ZpZm8udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEscUNBQXFDO0FBQ3JDOzs7O0dBSUc7QUFDSCxNQUFNLE9BQU8sVUFBVTtJQUF2QjtRQUNVLFlBQU8sR0FBaUMsRUFBRSxDQUFDO1FBQzNDLFVBQUssR0FBUSxFQUFFLENBQUM7UUFDaEIsYUFBUSxHQUFHLEtBQUssQ0FBQztJQThGM0IsQ0FBQztJQTVGQzs7O09BR0c7SUFDSSxNQUFNO1FBQ1gsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQztJQUMzQixDQUFDO0lBRUQ7Ozs7OztPQU1HO0lBQ0ksR0FBRyxDQUFDLE9BQWdCO1FBQ3pCLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLEVBQUU7WUFDckIsT0FBTyxPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxFQUFHLENBQUMsQ0FBQztTQUM3QztRQUVELElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLEtBQUssQ0FBQyxJQUFJLElBQUksQ0FBQyxRQUFRLEVBQUU7WUFDNUMsT0FBTyxPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO1NBQzlCO1FBRUQsT0FBTyxJQUFJLE9BQU8sQ0FBVyxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsRUFBRTtZQUMvQyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUUzQixJQUFJLE9BQU8sRUFBRTtnQkFDWCxVQUFVLENBQUMsR0FBRyxFQUFFO29CQUNkLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxLQUFLLE9BQU8sQ0FBQyxDQUFDO29CQUN6RCxJQUFJLEtBQUssR0FBRyxDQUFDLENBQUMsRUFBRTt3QkFDZCxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUM7d0JBQzlCLE1BQU0sR0FBRyxHQUFHLElBQUksS0FBSyxDQUFDLGtDQUFrQyxDQUFDLENBQUM7d0JBQzFELE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQztxQkFDYjtnQkFDSCxDQUFDLEVBQUUsT0FBTyxHQUFHLElBQUksQ0FBQyxDQUFDO2FBQ3BCO1FBQ0gsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQ7OztPQUdHO0lBQ0ksR0FBRyxDQUFDLElBQU87UUFDaEIsSUFBSSxJQUFJLENBQUMsUUFBUSxFQUFFO1lBQ2pCLE9BQU87U0FDUjthQUFNLElBQUksSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLEVBQUU7WUFDOUIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztTQUM3QjthQUFNO1lBQ0wsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7U0FDdkI7SUFDSCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNJLEdBQUc7UUFDUixJQUFJLENBQUMsUUFBUSxHQUFHLElBQUksQ0FBQztRQUNyQixJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQ2pELENBQUM7SUFFRDs7OztPQUlHO0lBQ0ksTUFBTTtRQUNYLElBQUksQ0FBQyxRQUFRLEdBQUcsSUFBSSxDQUFDO1FBQ3JCLElBQUksQ0FBQyxLQUFLLEdBQUcsRUFBRSxDQUFDO1FBQ2hCLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDakQsQ0FBQztJQUVEOzs7T0FHRztJQUNJLEtBQUssQ0FBQyxPQUFPLENBQUMsT0FBbUM7UUFDdEQsSUFBSTtZQUNGLE9BQU8sSUFBSSxFQUFFO2dCQUNYLE1BQU0sSUFBSSxHQUFHLE1BQU0sSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO2dCQUM5QixJQUFJLElBQUksS0FBSyxJQUFJLEVBQUU7b0JBQ2pCLE1BQU07aUJBQ1A7Z0JBQ0QsTUFBTSxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7YUFDckI7U0FDRjtRQUFDLE9BQU8sR0FBRyxFQUFFO1lBQ1osT0FBTyxDQUFDLEtBQUssQ0FBQywwQkFBMEIsRUFBRSxHQUFHLENBQUMsQ0FBQztTQUNoRDtJQUNILENBQUM7Q0FDRiJ9 \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/index.d.ts b/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/index.d.ts new file mode 100644 index 00000000000..9432a480ed8 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/index.d.ts @@ -0,0 +1,5 @@ +export * from './worker_connector.js'; +export * from './worker_listener.js'; +export * from './shared_worker_connector.js'; +export * from './shared_worker_listener.js'; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/index.d.ts.map b/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/index.d.ts.map new file mode 100644 index 00000000000..381d5165ffc --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/transport/browser/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,6BAA6B,CAAC"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/index.js b/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/index.js new file mode 100644 index 00000000000..d0103503cb4 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/index.js @@ -0,0 +1,5 @@ +export * from './worker_connector.js'; +export * from './worker_listener.js'; +export * from './shared_worker_connector.js'; +export * from './shared_worker_listener.js'; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvdHJhbnNwb3J0L2Jyb3dzZXIvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsY0FBYyx1QkFBdUIsQ0FBQztBQUN0QyxjQUFjLHNCQUFzQixDQUFDO0FBQ3JDLGNBQWMsOEJBQThCLENBQUM7QUFDN0MsY0FBYyw2QkFBNkIsQ0FBQyJ9 \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/message_port_socket.d.ts b/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/message_port_socket.d.ts new file mode 100644 index 00000000000..65fcce26e3e --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/message_port_socket.d.ts @@ -0,0 +1,28 @@ +import { Socket } from '../interface/socket.js'; +/** + * An implementation of a TransportSocket using MessagePorts. + */ +export declare class MessagePortSocket implements Socket { + private port; + /** + * Create a MessagePortSocket. + * @param port - MessagePort object to wrap. + */ + constructor(port: MessagePort); + /** + * Send a message over our message port. + * @param msg - The message. + * @param transfer - Objects to transfer ownership of. + */ + send(msg: any, transfer?: Transferable[]): Promise; + /** + * Add a message handler. + * @param cb - The handler. + */ + registerHandler(cb: (msg: any) => any): void; + /** + * Close this message port. + */ + close(): void; +} +//# sourceMappingURL=message_port_socket.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/message_port_socket.d.ts.map b/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/message_port_socket.d.ts.map new file mode 100644 index 00000000000..077d4623f51 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/message_port_socket.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"message_port_socket.d.ts","sourceRoot":"","sources":["../../../src/transport/browser/message_port_socket.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAEhD;;GAEG;AACH,qBAAa,iBAAkB,YAAW,MAAM;IAKlC,OAAO,CAAC,IAAI;IAJxB;;;OAGG;gBACiB,IAAI,EAAE,WAAW;IAErC;;;;OAIG;IACH,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,GAAE,YAAY,EAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAK5D;;;OAGG;IACH,eAAe,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,GAAG,GAAG,IAAI;IAI5C;;OAEG;IACH,KAAK;CAKN"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/message_port_socket.js b/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/message_port_socket.js new file mode 100644 index 00000000000..03387a31f8c --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/message_port_socket.js @@ -0,0 +1,37 @@ +/** + * An implementation of a TransportSocket using MessagePorts. + */ +export class MessagePortSocket { + /** + * Create a MessagePortSocket. + * @param port - MessagePort object to wrap. + */ + constructor(port) { + this.port = port; + } + /** + * Send a message over our message port. + * @param msg - The message. + * @param transfer - Objects to transfer ownership of. + */ + send(msg, transfer = []) { + this.port.postMessage(msg, transfer); + return Promise.resolve(); + } + /** + * Add a message handler. + * @param cb - The handler. + */ + registerHandler(cb) { + this.port.onmessage = event => cb(event.data); + } + /** + * Close this message port. + */ + close() { + void this.send(undefined); + this.port.onmessage = null; + this.port.close(); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVzc2FnZV9wb3J0X3NvY2tldC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy90cmFuc3BvcnQvYnJvd3Nlci9tZXNzYWdlX3BvcnRfc29ja2V0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUVBOztHQUVHO0FBQ0gsTUFBTSxPQUFPLGlCQUFpQjtJQUM1Qjs7O09BR0c7SUFDSCxZQUFvQixJQUFpQjtRQUFqQixTQUFJLEdBQUosSUFBSSxDQUFhO0lBQUcsQ0FBQztJQUV6Qzs7OztPQUlHO0lBQ0gsSUFBSSxDQUFDLEdBQVEsRUFBRSxXQUEyQixFQUFFO1FBQzFDLElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLEdBQUcsRUFBRSxRQUFRLENBQUMsQ0FBQztRQUNyQyxPQUFPLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQztJQUMzQixDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsZUFBZSxDQUFDLEVBQXFCO1FBQ25DLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxHQUFHLEtBQUssQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUNoRCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxLQUFLO1FBQ0gsS0FBSyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQzFCLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksQ0FBQztRQUMzQixJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQ3BCLENBQUM7Q0FDRiJ9 \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_connector.d.ts b/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_connector.d.ts new file mode 100644 index 00000000000..032f9df12b3 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_connector.d.ts @@ -0,0 +1,19 @@ +import { Connector } from '../interface/connector.js'; +import { MessagePortSocket } from './message_port_socket.js'; +/** + * Connector implementation which wraps a SharedWorker. + */ +export declare class SharedWorkerConnector implements Connector { + private worker; + /** + * Create a SharedWorkerConnector. + * @param worker - A shared worker. + */ + constructor(worker: SharedWorker); + /** + * Create a Socket implementation with our mesage port. + * @returns The socket. + */ + createSocket(): Promise; +} +//# sourceMappingURL=shared_worker_connector.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_connector.d.ts.map b/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_connector.d.ts.map new file mode 100644 index 00000000000..b745dd62aed --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_connector.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"shared_worker_connector.d.ts","sourceRoot":"","sources":["../../../src/transport/browser/shared_worker_connector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D;;GAEG;AACH,qBAAa,qBAAsB,YAAW,SAAS;IAKzC,OAAO,CAAC,MAAM;IAJ1B;;;OAGG;gBACiB,MAAM,EAAE,YAAY;IAExC;;;OAGG;IACH,YAAY;CAGb"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_connector.js b/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_connector.js new file mode 100644 index 00000000000..fa8778b40a9 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_connector.js @@ -0,0 +1,21 @@ +import { MessagePortSocket } from './message_port_socket.js'; +/** + * Connector implementation which wraps a SharedWorker. + */ +export class SharedWorkerConnector { + /** + * Create a SharedWorkerConnector. + * @param worker - A shared worker. + */ + constructor(worker) { + this.worker = worker; + } + /** + * Create a Socket implementation with our mesage port. + * @returns The socket. + */ + createSocket() { + return Promise.resolve(new MessagePortSocket(this.worker.port)); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2hhcmVkX3dvcmtlcl9jb25uZWN0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvdHJhbnNwb3J0L2Jyb3dzZXIvc2hhcmVkX3dvcmtlcl9jb25uZWN0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFFN0Q7O0dBRUc7QUFDSCxNQUFNLE9BQU8scUJBQXFCO0lBQ2hDOzs7T0FHRztJQUNILFlBQW9CLE1BQW9CO1FBQXBCLFdBQU0sR0FBTixNQUFNLENBQWM7SUFBRyxDQUFDO0lBRTVDOzs7T0FHRztJQUNILFlBQVk7UUFDVixPQUFPLE9BQU8sQ0FBQyxPQUFPLENBQUMsSUFBSSxpQkFBaUIsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDbEUsQ0FBQztDQUNGIn0= \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_listener.d.ts b/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_listener.d.ts new file mode 100644 index 00000000000..e6e93d9b214 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_listener.d.ts @@ -0,0 +1,38 @@ +/// +import EventEmitter from 'events'; +import { Listener } from '../interface/listener.js'; +/** + * See https://developer.mozilla.org/en-US/docs/Web/API/SharedWorkerGlobalScope. + */ +declare interface SharedWorkerGlobalScope { + /** + * Fired on shared workers when a new client connects. + */ + onconnect: any; +} +/** + * Listens for connections to a shared worker. + */ +export declare class SharedWorkerListener extends EventEmitter implements Listener { + private worker; + /** + * + * @param worker + */ + constructor(worker: SharedWorkerGlobalScope); + /** + * + */ + open(): void; + /** + * + */ + close(): void; + /** + * + * @param event + */ + private handleMessageEvent; +} +export {}; +//# sourceMappingURL=shared_worker_listener.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_listener.d.ts.map b/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_listener.d.ts.map new file mode 100644 index 00000000000..72ac8c251e3 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_listener.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"shared_worker_listener.d.ts","sourceRoot":"","sources":["../../../src/transport/browser/shared_worker_listener.ts"],"names":[],"mappings":";AAAA,OAAO,YAAY,MAAM,QAAQ,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAGpD;;GAEG;AACH,OAAO,WAAW,uBAAuB;IACvC;;OAEG;IACH,SAAS,EAAE,GAAG,CAAC;CAChB;AAED;;GAEG;AACH,qBAAa,oBAAqB,SAAQ,YAAa,YAAW,QAAQ;IAK5D,OAAO,CAAC,MAAM;IAJ1B;;;OAGG;gBACiB,MAAM,EAAE,uBAAuB;IAInD;;OAEG;IACH,IAAI;IAIJ;;OAEG;IACH,KAAK;IAIL;;;OAGG;IACH,OAAO,CAAC,kBAAkB,CAMxB;CACH"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_listener.js b/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_listener.js new file mode 100644 index 00000000000..e0cec42374b --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_listener.js @@ -0,0 +1,39 @@ +import EventEmitter from 'events'; +import { MessagePortSocket } from './message_port_socket.js'; +/** + * Listens for connections to a shared worker. + */ +export class SharedWorkerListener extends EventEmitter { + /** + * + * @param worker + */ + constructor(worker) { + super(); + this.worker = worker; + /** + * + * @param event + */ + this.handleMessageEvent = (event) => { + const [port] = event.ports; + if (!port) { + return; + } + this.emit('new_socket', new MessagePortSocket(port)); + }; + } + /** + * + */ + open() { + this.worker.onconnect = this.handleMessageEvent; + } + /** + * + */ + close() { + this.worker.onconnect = () => { }; + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2hhcmVkX3dvcmtlcl9saXN0ZW5lci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy90cmFuc3BvcnQvYnJvd3Nlci9zaGFyZWRfd29ya2VyX2xpc3RlbmVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sWUFBWSxNQUFNLFFBQVEsQ0FBQztBQUVsQyxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQVk3RDs7R0FFRztBQUNILE1BQU0sT0FBTyxvQkFBcUIsU0FBUSxZQUFZO0lBQ3BEOzs7T0FHRztJQUNILFlBQW9CLE1BQStCO1FBQ2pELEtBQUssRUFBRSxDQUFDO1FBRFUsV0FBTSxHQUFOLE1BQU0sQ0FBeUI7UUFrQm5EOzs7V0FHRztRQUNLLHVCQUFrQixHQUFHLENBQUMsS0FBbUIsRUFBRSxFQUFFO1lBQ25ELE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxLQUFLLENBQUMsS0FBSyxDQUFDO1lBQzNCLElBQUksQ0FBQyxJQUFJLEVBQUU7Z0JBQ1QsT0FBTzthQUNSO1lBQ0QsSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLEVBQUUsSUFBSSxpQkFBaUIsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO1FBQ3ZELENBQUMsQ0FBQztJQTFCRixDQUFDO0lBRUQ7O09BRUc7SUFDSCxJQUFJO1FBQ0YsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLEdBQUcsSUFBSSxDQUFDLGtCQUFrQixDQUFDO0lBQ2xELENBQUM7SUFFRDs7T0FFRztJQUNILEtBQUs7UUFDSCxJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsR0FBRyxHQUFHLEVBQUUsR0FBRSxDQUFDLENBQUM7SUFDbkMsQ0FBQztDQWFGIn0= \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/worker_connector.d.ts b/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/worker_connector.d.ts new file mode 100644 index 00000000000..a7eba90c1ac --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/worker_connector.d.ts @@ -0,0 +1,18 @@ +import { Connector } from '../interface/connector.js'; +import { MessagePortSocket } from './message_port_socket.js'; +/** + * + */ +export declare class WorkerConnector implements Connector { + private worker; + /** + * + * @param worker + */ + constructor(worker: Worker); + /** + * + */ + createSocket(): Promise; +} +//# sourceMappingURL=worker_connector.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/worker_connector.d.ts.map b/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/worker_connector.d.ts.map new file mode 100644 index 00000000000..a0af81a8776 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/worker_connector.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"worker_connector.d.ts","sourceRoot":"","sources":["../../../src/transport/browser/worker_connector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D;;GAEG;AACH,qBAAa,eAAgB,YAAW,SAAS;IAKnC,OAAO,CAAC,MAAM;IAJ1B;;;OAGG;gBACiB,MAAM,EAAE,MAAM;IAElC;;OAEG;IACH,YAAY;CAKb"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/worker_connector.js b/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/worker_connector.js new file mode 100644 index 00000000000..4faae6403cf --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/worker_connector.js @@ -0,0 +1,22 @@ +import { MessagePortSocket } from './message_port_socket.js'; +/** + * + */ +export class WorkerConnector { + /** + * + * @param worker + */ + constructor(worker) { + this.worker = worker; + } + /** + * + */ + createSocket() { + const channel = new MessageChannel(); + this.worker.postMessage('', [channel.port2]); + return Promise.resolve(new MessagePortSocket(channel.port1)); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid29ya2VyX2Nvbm5lY3Rvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy90cmFuc3BvcnQvYnJvd3Nlci93b3JrZXJfY29ubmVjdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBRTdEOztHQUVHO0FBQ0gsTUFBTSxPQUFPLGVBQWU7SUFDMUI7OztPQUdHO0lBQ0gsWUFBb0IsTUFBYztRQUFkLFdBQU0sR0FBTixNQUFNLENBQVE7SUFBRyxDQUFDO0lBRXRDOztPQUVHO0lBQ0gsWUFBWTtRQUNWLE1BQU0sT0FBTyxHQUFHLElBQUksY0FBYyxFQUFFLENBQUM7UUFDckMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxXQUFXLENBQUMsRUFBRSxFQUFFLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7UUFDN0MsT0FBTyxPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksaUJBQWlCLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7SUFDL0QsQ0FBQztDQUNGIn0= \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/worker_listener.d.ts b/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/worker_listener.d.ts new file mode 100644 index 00000000000..135a82ed2c4 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/worker_listener.d.ts @@ -0,0 +1,38 @@ +/// +import EventEmitter from 'events'; +import { Listener } from '../interface/listener.js'; +/** + * + */ +declare interface DedicatedWorkerGlobalScope { + /** + * + */ + onmessage: any; +} +/** + * + */ +export declare class WorkerListener extends EventEmitter implements Listener { + private worker; + /** + * + * @param worker + */ + constructor(worker: DedicatedWorkerGlobalScope); + /** + * + */ + open(): void; + /** + * + */ + close(): void; + /** + * + * @param event + */ + private handleMessageEvent; +} +export {}; +//# sourceMappingURL=worker_listener.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/worker_listener.d.ts.map b/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/worker_listener.d.ts.map new file mode 100644 index 00000000000..778536fc69b --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/worker_listener.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"worker_listener.d.ts","sourceRoot":"","sources":["../../../src/transport/browser/worker_listener.ts"],"names":[],"mappings":";AAAA,OAAO,YAAY,MAAM,QAAQ,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAGpD;;GAEG;AACH,OAAO,WAAW,0BAA0B;IAC1C;;OAEG;IACH,SAAS,EAAE,GAAG,CAAC;CAChB;AAED;;GAEG;AACH,qBAAa,cAAe,SAAQ,YAAa,YAAW,QAAQ;IAKtD,OAAO,CAAC,MAAM;IAJ1B;;;OAGG;gBACiB,MAAM,EAAE,0BAA0B;IAItD;;OAEG;IACH,IAAI;IAIJ;;OAEG;IACH,KAAK;IAIL;;;OAGG;IACH,OAAO,CAAC,kBAAkB,CAMxB;CACH"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/worker_listener.js b/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/worker_listener.js new file mode 100644 index 00000000000..75430d08d97 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/worker_listener.js @@ -0,0 +1,39 @@ +import EventEmitter from 'events'; +import { MessagePortSocket } from './message_port_socket.js'; +/** + * + */ +export class WorkerListener extends EventEmitter { + /** + * + * @param worker + */ + constructor(worker) { + super(); + this.worker = worker; + /** + * + * @param event + */ + this.handleMessageEvent = (event) => { + const [port] = event.ports; + if (!port) { + return; + } + this.emit('new_socket', new MessagePortSocket(port)); + }; + } + /** + * + */ + open() { + this.worker.onmessage = this.handleMessageEvent; + } + /** + * + */ + close() { + this.worker.onmessage = () => { }; + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid29ya2VyX2xpc3RlbmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3RyYW5zcG9ydC9icm93c2VyL3dvcmtlcl9saXN0ZW5lci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLFlBQVksTUFBTSxRQUFRLENBQUM7QUFFbEMsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFZN0Q7O0dBRUc7QUFDSCxNQUFNLE9BQU8sY0FBZSxTQUFRLFlBQVk7SUFDOUM7OztPQUdHO0lBQ0gsWUFBb0IsTUFBa0M7UUFDcEQsS0FBSyxFQUFFLENBQUM7UUFEVSxXQUFNLEdBQU4sTUFBTSxDQUE0QjtRQWtCdEQ7OztXQUdHO1FBQ0ssdUJBQWtCLEdBQUcsQ0FBQyxLQUFtQixFQUFFLEVBQUU7WUFDbkQsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLEtBQUssQ0FBQyxLQUFLLENBQUM7WUFDM0IsSUFBSSxDQUFDLElBQUksRUFBRTtnQkFDVCxPQUFPO2FBQ1I7WUFDRCxJQUFJLENBQUMsSUFBSSxDQUFDLFlBQVksRUFBRSxJQUFJLGlCQUFpQixDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7UUFDdkQsQ0FBQyxDQUFDO0lBMUJGLENBQUM7SUFFRDs7T0FFRztJQUNILElBQUk7UUFDRixJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsR0FBRyxJQUFJLENBQUMsa0JBQWtCLENBQUM7SUFDbEQsQ0FBQztJQUVEOztPQUVHO0lBQ0gsS0FBSztRQUNILElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxHQUFHLEdBQUcsRUFBRSxHQUFFLENBQUMsQ0FBQztJQUNuQyxDQUFDO0NBYUYifQ== \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_fn.d.ts b/circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_fn.d.ts new file mode 100644 index 00000000000..fdb3921facf --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_fn.d.ts @@ -0,0 +1,21 @@ +/** + * + */ +export interface DispatchMsg { + /** + * + */ + fn: string; + /** + * + */ + args: any[]; +} +/** + * + */ +export declare function createDispatchFn(targetFn: () => any, debug?: { + (...data: any[]): void; + (message?: any, ...optionalParams: any[]): void; +}): ({ fn, args }: DispatchMsg) => Promise; +//# sourceMappingURL=create_dispatch_fn.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_fn.d.ts.map b/circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_fn.d.ts.map new file mode 100644 index 00000000000..a8e465a9c16 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_fn.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"create_dispatch_fn.d.ts","sourceRoot":"","sources":["../../../src/transport/dispatch/create_dispatch_fn.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;IACX;;OAEG;IACH,IAAI,EAAE,GAAG,EAAE,CAAC;CACb;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,EAAE,KAAK;;;CAAgB,kBAC7C,WAAW,kBAKxC"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_fn.js b/circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_fn.js new file mode 100644 index 00000000000..09b635703d4 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_fn.js @@ -0,0 +1,11 @@ +/** + * + */ +export function createDispatchFn(targetFn, debug = console.error) { + return async ({ fn, args }) => { + const target = targetFn(); + debug(`dispatching to ${target}: ${fn}`, args); + return await target[fn](...args); + }; +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3JlYXRlX2Rpc3BhdGNoX2ZuLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3RyYW5zcG9ydC9kaXNwYXRjaC9jcmVhdGVfZGlzcGF0Y2hfZm4udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBY0E7O0dBRUc7QUFDSCxNQUFNLFVBQVUsZ0JBQWdCLENBQUMsUUFBbUIsRUFBRSxLQUFLLEdBQUcsT0FBTyxDQUFDLEtBQUs7SUFDekUsT0FBTyxLQUFLLEVBQUUsRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFlLEVBQUUsRUFBRTtRQUN6QyxNQUFNLE1BQU0sR0FBRyxRQUFRLEVBQUUsQ0FBQztRQUMxQixLQUFLLENBQUMsa0JBQWtCLE1BQU0sS0FBSyxFQUFFLEVBQUUsRUFBRSxJQUFJLENBQUMsQ0FBQztRQUMvQyxPQUFPLE1BQU0sTUFBTSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUM7SUFDbkMsQ0FBQyxDQUFDO0FBQ0osQ0FBQyJ9 \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_proxy.d.ts b/circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_proxy.d.ts new file mode 100644 index 00000000000..27edab62dc3 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_proxy.d.ts @@ -0,0 +1,50 @@ +import { DispatchMsg } from './create_dispatch_fn.js'; +import { TransportClient } from '../transport_client.js'; +import { TransferDescriptor } from '../interface/transferable.js'; +type FilterOutAttributes = { + [Key in keyof Base]: Base[Key] extends (...args: any) => any ? Base[Key] : never; +}; +type PromisifyFunction any> = (...args: Parameters) => Promise>; +type Promisify any; +}> = { + [Key in keyof Base]: ReturnType extends Promise ? Base[Key] : PromisifyFunction; +}; +/** + * Unpack transfer types + */ +type TransferTypes = { + [Index in keyof Tuple]: Tuple[Index] | (Tuple[Index] extends Transferable ? TransferDescriptor : never); +}; +/** + * Annoying: https://github.com/microsoft/TypeScript/issues/29919 + * There's a bug that means we can't map over the tuple or function parameter types to make them transferrable, if + * we use the Parameters builtin, and then try to map. + * So instead we inline the Parameters builtin and apply the TransferTypes to the parameters within the inline. + * Once the above is fixed we could in theory just do: + * + * type MakeFunctionTransferrable any> = ( + * ...args: TransferTypes> + * ) => ReturnType;. + */ +type MakeFunctionTransferrable any> = (...args: TFunction extends (...args: infer P) => any ? TransferTypes

: never) => ReturnType; +type Transferrable any; +}> = { + [Key in keyof Base]: MakeFunctionTransferrable; +}; +export type Proxify = Promisify>>; +export declare function createDispatchProxyFromFn(class_: { + new (...args: any[]): T; +}, requestFn: (fn: string) => (...args: any[]) => Promise): Proxify; +/** + * Create a proxy object of our class T that uses transportClient + * @param class_ - Our class T. + * @param transportClient - The transport infrastructure. + * @returns A proxy over T. + */ +export declare function createDispatchProxy(class_: { + new (...args: any[]): T; +}, transportClient: TransportClient): Proxify; +export {}; +//# sourceMappingURL=create_dispatch_proxy.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_proxy.d.ts.map b/circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_proxy.d.ts.map new file mode 100644 index 00000000000..8e5e12339be --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_proxy.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"create_dispatch_proxy.d.ts","sourceRoot":"","sources":["../../../src/transport/dispatch/create_dispatch_proxy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEzD,OAAO,EAAwB,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAExF,KAAK,mBAAmB,CAAC,IAAI,IAAI;KAC9B,GAAG,IAAI,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,KAAK,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK;CACjF,CAAC;AAEF,KAAK,iBAAiB,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,KAAK,GAAG,IAAI,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AAE7G,KAAK,SAAS,CAAC,IAAI,SAAS;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,EAAE,GAAG,KAAK,GAAG,CAAA;CAAE,IAAI;KACrE,GAAG,IAAI,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,SAAS,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,iBAAiB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;CAC3G,CAAC;AAEF;;GAEG;AACH,KAAK,aAAa,CAAC,KAAK,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,CAAC,IAAI;KAChD,KAAK,IAAI,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,YAAY,GAAG,kBAAkB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC;CACtH,CAAC;AAEF;;;;;;;;;;GAUG;AACH,KAAK,yBAAyB,CAAC,SAAS,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,KAAK,GAAG,IAAI,CACxE,GAAG,IAAI,EAAE,SAAS,SAAS,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,KAAK,GAAG,GAAG,aAAa,CAAC,CAAC,CAAC,GAAG,KAAK,KAC5E,UAAU,CAAC,SAAS,CAAC,CAAC;AAE3B,KAAK,aAAa,CAAC,IAAI,SAAS;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAA;CAAE,IAAI;KAC3E,GAAG,IAAI,MAAM,IAAI,GAAG,yBAAyB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;CAC1D,CAAC;AAEF,MAAM,MAAM,OAAO,CAAC,CAAC,IAAI,SAAS,CAAC,aAAa,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAE1E,wBAAgB,yBAAyB,CAAC,CAAC,EACzC,MAAM,EAAE;IAAE,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;CAAE,EACnC,SAAS,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,GAAG,CAAC,GAC1D,OAAO,CAAC,CAAC,CAAC,CASZ;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EACnC,MAAM,EAAE;IAAE,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;CAAE,EACnC,eAAe,EAAE,eAAe,CAAC,WAAW,CAAC,GAC5C,OAAO,CAAC,CAAC,CAAC,CAqBZ"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_proxy.js b/circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_proxy.js new file mode 100644 index 00000000000..49833dfc748 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_proxy.js @@ -0,0 +1,38 @@ +import { EventEmitter } from 'events'; +import { isTransferDescriptor } from '../interface/transferable.js'; +export function createDispatchProxyFromFn(class_, requestFn) { + const proxy = class_.prototype instanceof EventEmitter ? new EventEmitter() : {}; + for (const fn of Object.getOwnPropertyNames(class_.prototype)) { + if (fn === 'constructor') { + continue; + } + proxy[fn] = requestFn(fn); + } + return proxy; +} +/** + * Create a proxy object of our class T that uses transportClient + * @param class_ - Our class T. + * @param transportClient - The transport infrastructure. + * @returns A proxy over T. + */ +export function createDispatchProxy(class_, transportClient) { + // Create a proxy of class_ that passes along methods over our transportClient + const proxy = createDispatchProxyFromFn(class_, (fn) => (...args) => { + // Pass our proxied function name and arguments over our transport client + const transfer = args.reduce((acc, a) => (isTransferDescriptor(a) ? [...acc, ...a.transferables] : acc), []); + args = args.map(a => (isTransferDescriptor(a) ? a.send : a)); + return transportClient.request({ fn, args }, transfer); + }); + if (proxy instanceof EventEmitter) { + // Handle proxied 'emit' calls if our proxy object is an EventEmitter + transportClient.on('event_msg', ({ fn, args }) => { + if (fn === 'emit') { + const [eventName, ...restArgs] = args; + proxy.emit(eventName, ...restArgs); + } + }); + } + return proxy; +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3JlYXRlX2Rpc3BhdGNoX3Byb3h5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3RyYW5zcG9ydC9kaXNwYXRjaC9jcmVhdGVfZGlzcGF0Y2hfcHJveHkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBRUEsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLFFBQVEsQ0FBQztBQUN0QyxPQUFPLEVBQUUsb0JBQW9CLEVBQXNCLE1BQU0sOEJBQThCLENBQUM7QUF3Q3hGLE1BQU0sVUFBVSx5QkFBeUIsQ0FDdkMsTUFBbUMsRUFDbkMsU0FBMkQ7SUFFM0QsTUFBTSxLQUFLLEdBQVEsTUFBTSxDQUFDLFNBQVMsWUFBWSxZQUFZLENBQUMsQ0FBQyxDQUFDLElBQUksWUFBWSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztJQUN0RixLQUFLLE1BQU0sRUFBRSxJQUFJLE1BQU0sQ0FBQyxtQkFBbUIsQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLEVBQUU7UUFDN0QsSUFBSSxFQUFFLEtBQUssYUFBYSxFQUFFO1lBQ3hCLFNBQVM7U0FDVjtRQUNELEtBQUssQ0FBQyxFQUFFLENBQUMsR0FBRyxTQUFTLENBQUMsRUFBRSxDQUFDLENBQUM7S0FDM0I7SUFDRCxPQUFPLEtBQUssQ0FBQztBQUNmLENBQUM7QUFFRDs7Ozs7R0FLRztBQUNILE1BQU0sVUFBVSxtQkFBbUIsQ0FDakMsTUFBbUMsRUFDbkMsZUFBNkM7SUFFN0MsOEVBQThFO0lBQzlFLE1BQU0sS0FBSyxHQUFHLHlCQUF5QixDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQVUsRUFBRSxFQUFFLENBQUMsQ0FBQyxHQUFHLElBQVcsRUFBRSxFQUFFO1FBQ2pGLHlFQUF5RTtRQUN6RSxNQUFNLFFBQVEsR0FBbUIsSUFBSSxDQUFDLE1BQU0sQ0FDMUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLG9CQUFvQixDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsR0FBRyxFQUFFLEdBQUcsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsRUFDMUUsRUFBb0IsQ0FDckIsQ0FBQztRQUNGLElBQUksR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUM3RCxPQUFPLGVBQWUsQ0FBQyxPQUFPLENBQUMsRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFFLEVBQUUsUUFBUSxDQUFDLENBQUM7SUFDekQsQ0FBQyxDQUFDLENBQUM7SUFDSCxJQUFJLEtBQUssWUFBWSxZQUFZLEVBQUU7UUFDakMscUVBQXFFO1FBQ3JFLGVBQWUsQ0FBQyxFQUFFLENBQUMsV0FBVyxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFFLEVBQUUsRUFBRTtZQUMvQyxJQUFJLEVBQUUsS0FBSyxNQUFNLEVBQUU7Z0JBQ2pCLE1BQU0sQ0FBQyxTQUFTLEVBQUUsR0FBRyxRQUFRLENBQUMsR0FBRyxJQUFJLENBQUM7Z0JBQ3RDLEtBQUssQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLEdBQUcsUUFBUSxDQUFDLENBQUM7YUFDcEM7UUFDSCxDQUFDLENBQUMsQ0FBQztLQUNKO0lBQ0QsT0FBTyxLQUFLLENBQUM7QUFDZixDQUFDIn0= \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/messages.d.ts b/circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/messages.d.ts new file mode 100644 index 00000000000..c8e36c087a4 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/messages.d.ts @@ -0,0 +1,45 @@ +/** + * Represents a transport bus request. + */ +export interface RequestMessage { + /** + * The message ID. + */ + msgId: number; + /** + * The data. + */ + payload: Payload; +} +/** + * Represents a transport bus response. + */ +export interface ResponseMessage { + /** + * The message ID. + */ + msgId: number; + /** + * The data. + */ + payload?: Payload; + /** + * The error, if any. + */ + error?: string; +} +/** + * A message stemming from an event. + */ +export interface EventMessage { + /** + * The event data. + */ + payload: Payload; +} +/** + * Is this an event message? + * @returns If the msgId was blank. + */ +export declare function isEventMessage(msg: ResponseMessage | EventMessage): msg is EventMessage; +//# sourceMappingURL=messages.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/messages.d.ts.map b/circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/messages.d.ts.map new file mode 100644 index 00000000000..115e820679b --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/messages.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../../src/transport/dispatch/messages.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,cAAc,CAAC,OAAO;IACrC;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe,CAAC,OAAO;IACtC;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY,CAAC,OAAO;IACnC;;OAEG;IACH,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,OAAO,EACpC,GAAG,EAAE,eAAe,CAAC,OAAO,CAAC,GAAG,YAAY,CAAC,OAAO,CAAC,GACpD,GAAG,IAAI,YAAY,CAAC,OAAO,CAAC,CAE9B"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/messages.js b/circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/messages.js new file mode 100644 index 00000000000..b5d76595237 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/messages.js @@ -0,0 +1,8 @@ +/** + * Is this an event message? + * @returns If the msgId was blank. + */ +export function isEventMessage(msg) { + return msg.msgId === undefined; +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVzc2FnZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvdHJhbnNwb3J0L2Rpc3BhdGNoL21lc3NhZ2VzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQTBDQTs7O0dBR0c7QUFDSCxNQUFNLFVBQVUsY0FBYyxDQUM1QixHQUFxRDtJQUVyRCxPQUFRLEdBQWdDLENBQUMsS0FBSyxLQUFLLFNBQVMsQ0FBQztBQUMvRCxDQUFDIn0= \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/index.d.ts b/circuits/ts/.yalc/@aztec/wasm/dest/transport/index.d.ts new file mode 100644 index 00000000000..0989a811a39 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/index.d.ts @@ -0,0 +1,12 @@ +export * from './dispatch/create_dispatch_fn.js'; +export * from './dispatch/create_dispatch_proxy.js'; +export * from './dispatch/messages.js'; +export * from './interface/connector.js'; +export * from './interface/listener.js'; +export * from './interface/socket.js'; +export * from './interface/transferable.js'; +export * from './transport_client.js'; +export * from './transport_server.js'; +export * from './browser/index.js'; +export * from './node/index.js'; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/index.d.ts.map b/circuits/ts/.yalc/@aztec/wasm/dest/transport/index.d.ts.map new file mode 100644 index 00000000000..d5bded64e1d --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/transport/index.ts"],"names":[],"mappings":"AAAA,cAAc,kCAAkC,CAAC;AACjD,cAAc,qCAAqC,CAAC;AACpD,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/index.js b/circuits/ts/.yalc/@aztec/wasm/dest/transport/index.js new file mode 100644 index 00000000000..70b1b56c44c --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/index.js @@ -0,0 +1,12 @@ +export * from './dispatch/create_dispatch_fn.js'; +export * from './dispatch/create_dispatch_proxy.js'; +export * from './dispatch/messages.js'; +export * from './interface/connector.js'; +export * from './interface/listener.js'; +export * from './interface/socket.js'; +export * from './interface/transferable.js'; +export * from './transport_client.js'; +export * from './transport_server.js'; +export * from './browser/index.js'; +export * from './node/index.js'; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdHJhbnNwb3J0L2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLGNBQWMsa0NBQWtDLENBQUM7QUFDakQsY0FBYyxxQ0FBcUMsQ0FBQztBQUNwRCxjQUFjLHdCQUF3QixDQUFDO0FBQ3ZDLGNBQWMsMEJBQTBCLENBQUM7QUFDekMsY0FBYyx5QkFBeUIsQ0FBQztBQUN4QyxjQUFjLHVCQUF1QixDQUFDO0FBQ3RDLGNBQWMsNkJBQTZCLENBQUM7QUFDNUMsY0FBYyx1QkFBdUIsQ0FBQztBQUN0QyxjQUFjLHVCQUF1QixDQUFDO0FBQ3RDLGNBQWMsb0JBQW9CLENBQUM7QUFDbkMsY0FBYyxpQkFBaUIsQ0FBQyJ9 \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/connector.d.ts b/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/connector.d.ts new file mode 100644 index 00000000000..828e9aab7b2 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/connector.d.ts @@ -0,0 +1,8 @@ +import { Socket } from './socket.js'; +/** + * Opens a socket with corresponding TransportListener. + */ +export interface Connector { + createSocket(): Promise; +} +//# sourceMappingURL=connector.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/connector.d.ts.map b/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/connector.d.ts.map new file mode 100644 index 00000000000..62006c17ceb --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/connector.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"connector.d.ts","sourceRoot":"","sources":["../../../src/transport/interface/connector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;CACjC"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/connector.js b/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/connector.js new file mode 100644 index 00000000000..7d5ac106da9 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/connector.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29ubmVjdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3RyYW5zcG9ydC9pbnRlcmZhY2UvY29ubmVjdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiIifQ== \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/listener.d.ts b/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/listener.d.ts new file mode 100644 index 00000000000..4d0baa43572 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/listener.d.ts @@ -0,0 +1,13 @@ +/// +import EventEmitter from 'events'; +import { Socket } from './socket.js'; +/** + * Once opened, an implementation of a TransportListener will emit `new_socket` events as new clients connect. + * Possible implementations could include MessageChannels or WebSockets. + */ +export interface Listener extends EventEmitter { + open(): void; + close(): void; + on(name: 'new_socket', cb: (client: Socket) => void): this; +} +//# sourceMappingURL=listener.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/listener.d.ts.map b/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/listener.d.ts.map new file mode 100644 index 00000000000..a326bd6b210 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/listener.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"listener.d.ts","sourceRoot":"","sources":["../../../src/transport/interface/listener.ts"],"names":[],"mappings":";AAAA,OAAO,YAAY,MAAM,QAAQ,CAAC;AAClC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC;;;GAGG;AACH,MAAM,WAAW,QAAS,SAAQ,YAAY;IAC5C,IAAI,IAAI,IAAI,CAAC;IAEb,KAAK,IAAI,IAAI,CAAC;IAEd,EAAE,CAAC,IAAI,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;CAC5D"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/listener.js b/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/listener.js new file mode 100644 index 00000000000..196998386cb --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/listener.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGlzdGVuZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvdHJhbnNwb3J0L2ludGVyZmFjZS9saXN0ZW5lci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIn0= \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/socket.d.ts b/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/socket.d.ts new file mode 100644 index 00000000000..39e6a4e4a6a --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/socket.d.ts @@ -0,0 +1,13 @@ +/** + * Represents one end of a socket connection. + * A message sent via `send` will be handled by the corresponding Socket's handler function at the other end. + * Implementations could use e.g. MessagePorts for communication between browser workers, + * or WebSockets for communication between processes. + * If `registerHandler` callback receives `undefined` that signals the other end closed. + */ +export interface Socket { + send(msg: any, transfer?: Transferable[]): Promise; + registerHandler(cb: (msg: any) => any): void; + close(): void; +} +//# sourceMappingURL=socket.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/socket.d.ts.map b/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/socket.d.ts.map new file mode 100644 index 00000000000..a7714e3a539 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/socket.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"socket.d.ts","sourceRoot":"","sources":["../../../src/transport/interface/socket.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,WAAW,MAAM;IACrB,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,CAAC,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD,eAAe,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,GAAG,GAAG,IAAI,CAAC;IAC7C,KAAK,IAAI,IAAI,CAAC;CACf"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/socket.js b/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/socket.js new file mode 100644 index 00000000000..5a28a6f054d --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/socket.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic29ja2V0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3RyYW5zcG9ydC9pbnRlcmZhY2Uvc29ja2V0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiIifQ== \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/transferable.d.ts b/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/transferable.d.ts new file mode 100644 index 00000000000..f8ef5f290e3 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/transferable.d.ts @@ -0,0 +1,60 @@ +declare const $transferable: unique symbol; +/** + * A descriptor representing a payload with transferable components. + * These components will have ownership transfered when published on an event bus. + */ +export interface TransferDescriptor { + /** + * Marked as transferable. + */ + [$transferable]: true; + /** + * The payload with the transferable objects. + */ + send: T; + /** + * The objects to transfer. + */ + transferables: Transferable[]; +} +/** + * + */ +export declare function isTransferDescriptor(thing: any): thing is TransferDescriptor; +/** + * Mark a transferable object as such, so it will no be serialized and + * deserialized on messaging with the main thread, but to transfer + * ownership of it to the receiving thread. + * + * Only works with array buffers, message ports and few more special + * types of objects, but it's much faster than serializing and + * deserializing them. + * + * Note: + * The transferable object cannot be accessed by this thread again + * unless the receiving thread transfers it back again! + * + * @param transferable - Array buffer, message port or similar. + * @see https://developers.google.com/web/updates/2011/12/Transferable-Objects-Lightning-Fast + */ +export declare function Transfer(transferable: Transferable): TransferDescriptor; +/** + * Mark transferable objects within an arbitrary object or array as + * being a transferable object. They will then not be serialized + * and deserialized on messaging with the main thread, but ownership + * of them will be tranferred to the receiving thread. + * + * Only array buffers, message ports and few more special types of + * objects can be transferred, but it's much faster than serializing and + * deserializing them. + * + * Note: + * The transferable object cannot be accessed by this thread again + * unless the receiving thread transfers it back again! + * + * @param transferable - Array buffer, message port or similar. + * @see https://developers.google.com/web/updates/2011/12/Transferable-Objects-Lightning-Fast + */ +export declare function Transfer(payload: T, transferables: Transferable[]): TransferDescriptor; +export {}; +//# sourceMappingURL=transferable.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/transferable.d.ts.map b/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/transferable.d.ts.map new file mode 100644 index 00000000000..5126c83a736 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/transferable.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"transferable.d.ts","sourceRoot":"","sources":["../../../src/transport/interface/transferable.ts"],"names":[],"mappings":"AAAA,QAAA,MAAM,aAAa,eAAgC,CAAC;AAEpD;;;GAGG;AACH,MAAM,WAAW,kBAAkB,CAAC,CAAC,GAAG,GAAG;IACzC;;OAEG;IACH,CAAC,aAAa,CAAC,EAAE,IAAI,CAAC;IACtB;;OAEG;IACH,IAAI,EAAE,CAAC,CAAC;IACR;;OAEG;IACH,aAAa,EAAE,YAAY,EAAE,CAAC;CAC/B;AAWD;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,GAAG,GAAG,KAAK,IAAI,kBAAkB,CAE5E;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,YAAY,EAAE,YAAY,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAAC;AAE/E;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,aAAa,EAAE,YAAY,EAAE,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/transferable.js b/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/transferable.js new file mode 100644 index 00000000000..e815bbc8331 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/transferable.js @@ -0,0 +1,35 @@ +const $transferable = Symbol('thread.transferable'); +/** + * + */ +function isTransferable(thing) { + if (!thing || typeof thing !== 'object') + return false; + // Don't check too thoroughly, since the list of transferable things in JS might grow over time + return true; +} +/** + * + */ +export function isTransferDescriptor(thing) { + return thing && typeof thing === 'object' && thing[$transferable]; +} +/** + * Create a transfer descriptor, marking these as transferable. + * @param payload - The payload. + * @param transferables - The transferable objects. + * @returns The descriptor. + */ +export function Transfer(payload, transferables) { + if (!transferables) { + if (!isTransferable(payload)) + throw Error(); + transferables = [payload]; + } + return { + [$transferable]: true, + send: payload, + transferables, + }; +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhbnNmZXJhYmxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3RyYW5zcG9ydC9pbnRlcmZhY2UvdHJhbnNmZXJhYmxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE1BQU0sYUFBYSxHQUFHLE1BQU0sQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDO0FBcUJwRDs7R0FFRztBQUNILFNBQVMsY0FBYyxDQUFDLEtBQVU7SUFDaEMsSUFBSSxDQUFDLEtBQUssSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRO1FBQUUsT0FBTyxLQUFLLENBQUM7SUFDdEQsK0ZBQStGO0lBQy9GLE9BQU8sSUFBSSxDQUFDO0FBQ2QsQ0FBQztBQUVEOztHQUVHO0FBQ0gsTUFBTSxVQUFVLG9CQUFvQixDQUFDLEtBQVU7SUFDN0MsT0FBTyxLQUFLLElBQUksT0FBTyxLQUFLLEtBQUssUUFBUSxJQUFJLEtBQUssQ0FBQyxhQUFhLENBQUMsQ0FBQztBQUNwRSxDQUFDO0FBdUNEOzs7OztHQUtHO0FBQ0gsTUFBTSxVQUFVLFFBQVEsQ0FBSSxPQUFVLEVBQUUsYUFBOEI7SUFDcEUsSUFBSSxDQUFDLGFBQWEsRUFBRTtRQUNsQixJQUFJLENBQUMsY0FBYyxDQUFDLE9BQU8sQ0FBQztZQUFFLE1BQU0sS0FBSyxFQUFFLENBQUM7UUFDNUMsYUFBYSxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUM7S0FDM0I7SUFFRCxPQUFPO1FBQ0wsQ0FBQyxhQUFhLENBQUMsRUFBRSxJQUFJO1FBQ3JCLElBQUksRUFBRSxPQUFPO1FBQ2IsYUFBYTtLQUNkLENBQUM7QUFDSixDQUFDIn0= \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/index.d.ts b/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/index.d.ts new file mode 100644 index 00000000000..a39c08a0d40 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/index.d.ts @@ -0,0 +1,3 @@ +export * from './node_connector.js'; +export * from './node_listener.js'; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/index.d.ts.map b/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/index.d.ts.map new file mode 100644 index 00000000000..1ea4d29d0e8 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/transport/node/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/index.js b/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/index.js new file mode 100644 index 00000000000..07a86060aae --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/index.js @@ -0,0 +1,3 @@ +export * from './node_connector.js'; +export * from './node_listener.js'; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvdHJhbnNwb3J0L25vZGUvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsY0FBYyxxQkFBcUIsQ0FBQztBQUNwQyxjQUFjLG9CQUFvQixDQUFDIn0= \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_connector.d.ts b/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_connector.d.ts new file mode 100644 index 00000000000..b1d8890543c --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_connector.d.ts @@ -0,0 +1,17 @@ +/// +import { Worker } from 'worker_threads'; +import { Connector } from '../interface/connector.js'; +import { NodeConnectorSocket } from './node_connector_socket.js'; +/** + * Creates sockets backed by a Node worker. + */ +export declare class NodeConnector implements Connector { + private worker; + constructor(worker: Worker); + /** + * Creates a socket backed by a node worker. + * @returns The socket. + */ + createSocket(): Promise; +} +//# sourceMappingURL=node_connector.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_connector.d.ts.map b/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_connector.d.ts.map new file mode 100644 index 00000000000..57ef4337f76 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_connector.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"node_connector.d.ts","sourceRoot":"","sources":["../../../src/transport/node/node_connector.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAEjE;;GAEG;AACH,qBAAa,aAAc,YAAW,SAAS;IACjC,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,MAAM;IAElC;;;OAGG;IACH,YAAY;CAGb"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_connector.js b/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_connector.js new file mode 100644 index 00000000000..2525dc38092 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_connector.js @@ -0,0 +1,17 @@ +import { NodeConnectorSocket } from './node_connector_socket.js'; +/** + * Creates sockets backed by a Node worker. + */ +export class NodeConnector { + constructor(worker) { + this.worker = worker; + } + /** + * Creates a socket backed by a node worker. + * @returns The socket. + */ + createSocket() { + return Promise.resolve(new NodeConnectorSocket(this.worker)); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZV9jb25uZWN0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvdHJhbnNwb3J0L25vZGUvbm9kZV9jb25uZWN0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBRUEsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFFakU7O0dBRUc7QUFDSCxNQUFNLE9BQU8sYUFBYTtJQUN4QixZQUFvQixNQUFjO1FBQWQsV0FBTSxHQUFOLE1BQU0sQ0FBUTtJQUFHLENBQUM7SUFFdEM7OztPQUdHO0lBQ0gsWUFBWTtRQUNWLE9BQU8sT0FBTyxDQUFDLE9BQU8sQ0FBQyxJQUFJLG1CQUFtQixDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDO0lBQy9ELENBQUM7Q0FDRiJ9 \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_connector_socket.d.ts b/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_connector_socket.d.ts new file mode 100644 index 00000000000..a87192030c2 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_connector_socket.d.ts @@ -0,0 +1,27 @@ +/// +import { Worker } from 'worker_threads'; +import { Socket } from '../interface/socket.js'; +/** + * A socket implementation using a Node worker. + */ +export declare class NodeConnectorSocket implements Socket { + private worker; + constructor(worker: Worker); + /** + * Send a message. + * @param msg - The message. + * @param transfer - Objects to transfer ownership of. + * @returns A void promise. + */ + send(msg: any, transfer?: Transferable[]): Promise; + /** + * Register a message handler. + * @param cb - The handler function. + */ + registerHandler(cb: (msg: any) => any): void; + /** + * Remove all listeners from our worker. + */ + close(): void; +} +//# sourceMappingURL=node_connector_socket.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_connector_socket.d.ts.map b/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_connector_socket.d.ts.map new file mode 100644 index 00000000000..a7bbda3ff57 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_connector_socket.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"node_connector_socket.d.ts","sourceRoot":"","sources":["../../../src/transport/node/node_connector_socket.ts"],"names":[],"mappings":";AAAA,OAAO,EAAoB,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAEhD;;GAEG;AACH,qBAAa,mBAAoB,YAAW,MAAM;IACpC,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,MAAM;IAElC;;;;;OAKG;IACH,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,GAAE,YAAY,EAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAK5D;;;OAGG;IACH,eAAe,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,GAAG,GAAG,IAAI;IAI5C;;OAEG;IACH,KAAK;CAIN"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_connector_socket.js b/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_connector_socket.js new file mode 100644 index 00000000000..25eb2f34e28 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_connector_socket.js @@ -0,0 +1,33 @@ +/** + * A socket implementation using a Node worker. + */ +export class NodeConnectorSocket { + constructor(worker) { + this.worker = worker; + } + /** + * Send a message. + * @param msg - The message. + * @param transfer - Objects to transfer ownership of. + * @returns A void promise. + */ + send(msg, transfer = []) { + this.worker.postMessage(msg, transfer); + return Promise.resolve(); + } + /** + * Register a message handler. + * @param cb - The handler function. + */ + registerHandler(cb) { + this.worker.on('message', cb); + } + /** + * Remove all listeners from our worker. + */ + close() { + void this.send(undefined); + this.worker.removeAllListeners(); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZV9jb25uZWN0b3Jfc29ja2V0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3RyYW5zcG9ydC9ub2RlL25vZGVfY29ubmVjdG9yX3NvY2tldC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFHQTs7R0FFRztBQUNILE1BQU0sT0FBTyxtQkFBbUI7SUFDOUIsWUFBb0IsTUFBYztRQUFkLFdBQU0sR0FBTixNQUFNLENBQVE7SUFBRyxDQUFDO0lBRXRDOzs7OztPQUtHO0lBQ0gsSUFBSSxDQUFDLEdBQVEsRUFBRSxXQUEyQixFQUFFO1FBQzFDLElBQUksQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLEdBQUcsRUFBRSxRQUE4QixDQUFDLENBQUM7UUFDN0QsT0FBTyxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUM7SUFDM0IsQ0FBQztJQUVEOzs7T0FHRztJQUNILGVBQWUsQ0FBQyxFQUFxQjtRQUNuQyxJQUFJLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxTQUFTLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDaEMsQ0FBQztJQUVEOztPQUVHO0lBQ0gsS0FBSztRQUNILEtBQUssSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUMxQixJQUFJLENBQUMsTUFBTSxDQUFDLGtCQUFrQixFQUFFLENBQUM7SUFDbkMsQ0FBQztDQUNGIn0= \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_listener.d.ts b/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_listener.d.ts new file mode 100644 index 00000000000..e9bf26a20ce --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_listener.d.ts @@ -0,0 +1,18 @@ +/// +import EventEmitter from 'events'; +import { Listener } from '../interface/listener.js'; +/** + * A socket listener that works with Node. + */ +export declare class NodeListener extends EventEmitter implements Listener { + constructor(); + /** + * Open the listener. + */ + open(): void; + /** + * Close the listener. + */ + close(): void; +} +//# sourceMappingURL=node_listener.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_listener.d.ts.map b/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_listener.d.ts.map new file mode 100644 index 00000000000..e15acee10b1 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_listener.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"node_listener.d.ts","sourceRoot":"","sources":["../../../src/transport/node/node_listener.ts"],"names":[],"mappings":";AACA,OAAO,YAAY,MAAM,QAAQ,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAGpD;;GAEG;AACH,qBAAa,YAAa,SAAQ,YAAa,YAAW,QAAQ;;IAKhE;;OAEG;IACH,IAAI;IAIJ;;OAEG;IACH,KAAK;CACN"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_listener.js b/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_listener.js new file mode 100644 index 00000000000..318369699af --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_listener.js @@ -0,0 +1,22 @@ +import { parentPort } from 'worker_threads'; +import EventEmitter from 'events'; +import { NodeListenerSocket } from './node_listener_socket.js'; +/** + * A socket listener that works with Node. + */ +export class NodeListener extends EventEmitter { + constructor() { + super(); + } + /** + * Open the listener. + */ + open() { + this.emit('new_socket', new NodeListenerSocket(parentPort)); + } + /** + * Close the listener. + */ + close() { } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZV9saXN0ZW5lci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy90cmFuc3BvcnQvbm9kZS9ub2RlX2xpc3RlbmVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUM1QyxPQUFPLFlBQVksTUFBTSxRQUFRLENBQUM7QUFFbEMsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFFL0Q7O0dBRUc7QUFDSCxNQUFNLE9BQU8sWUFBYSxTQUFRLFlBQVk7SUFDNUM7UUFDRSxLQUFLLEVBQUUsQ0FBQztJQUNWLENBQUM7SUFFRDs7T0FFRztJQUNILElBQUk7UUFDRixJQUFJLENBQUMsSUFBSSxDQUFDLFlBQVksRUFBRSxJQUFJLGtCQUFrQixDQUFDLFVBQWlCLENBQUMsQ0FBQyxDQUFDO0lBQ3JFLENBQUM7SUFFRDs7T0FFRztJQUNILEtBQUssS0FBSSxDQUFDO0NBQ1gifQ== \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_listener_socket.d.ts b/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_listener_socket.d.ts new file mode 100644 index 00000000000..ee114126deb --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_listener_socket.d.ts @@ -0,0 +1,27 @@ +/// +import { MessagePort } from 'worker_threads'; +import { Socket } from '../interface/socket.js'; +/** + * An implementation of a TransportSocket using MessagePorts. + */ +export declare class NodeListenerSocket implements Socket { + private port; + constructor(port: MessagePort); + /** + * Send a message over this port. + * @param msg - The message. + * @param transfer - Transferable objects. + * @returns A void promise. + */ + send(msg: any, transfer?: Transferable[]): Promise; + /** + * Add a handler to this port. + * @param cb - The handler function. + */ + registerHandler(cb: (msg: any) => any): void; + /** + * Close this socket. + */ + close(): void; +} +//# sourceMappingURL=node_listener_socket.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_listener_socket.d.ts.map b/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_listener_socket.d.ts.map new file mode 100644 index 00000000000..31986e0cd02 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_listener_socket.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"node_listener_socket.d.ts","sourceRoot":"","sources":["../../../src/transport/node/node_listener_socket.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,WAAW,EAAoB,MAAM,gBAAgB,CAAC;AAC/D,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAEhD;;GAEG;AACH,qBAAa,kBAAmB,YAAW,MAAM;IACnC,OAAO,CAAC,IAAI;gBAAJ,IAAI,EAAE,WAAW;IAErC;;;;;OAKG;IACH,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,GAAE,YAAY,EAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAK5D;;;OAGG;IACH,eAAe,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,GAAG,GAAG,IAAI;IAI5C;;OAEG;IACH,KAAK;CAKN"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_listener_socket.js b/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_listener_socket.js new file mode 100644 index 00000000000..483c51bc0ff --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_listener_socket.js @@ -0,0 +1,34 @@ +/** + * An implementation of a TransportSocket using MessagePorts. + */ +export class NodeListenerSocket { + constructor(port) { + this.port = port; + } + /** + * Send a message over this port. + * @param msg - The message. + * @param transfer - Transferable objects. + * @returns A void promise. + */ + send(msg, transfer = []) { + this.port.postMessage(msg, transfer); + return Promise.resolve(); + } + /** + * Add a handler to this port. + * @param cb - The handler function. + */ + registerHandler(cb) { + this.port.on('message', cb); + } + /** + * Close this socket. + */ + close() { + void this.send(undefined); + this.port.removeAllListeners(); + this.port.close(); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZV9saXN0ZW5lcl9zb2NrZXQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvdHJhbnNwb3J0L25vZGUvbm9kZV9saXN0ZW5lcl9zb2NrZXQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBR0E7O0dBRUc7QUFDSCxNQUFNLE9BQU8sa0JBQWtCO0lBQzdCLFlBQW9CLElBQWlCO1FBQWpCLFNBQUksR0FBSixJQUFJLENBQWE7SUFBRyxDQUFDO0lBRXpDOzs7OztPQUtHO0lBQ0gsSUFBSSxDQUFDLEdBQVEsRUFBRSxXQUEyQixFQUFFO1FBQzFDLElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLEdBQUcsRUFBRSxRQUE4QixDQUFDLENBQUM7UUFDM0QsT0FBTyxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUM7SUFDM0IsQ0FBQztJQUVEOzs7T0FHRztJQUNILGVBQWUsQ0FBQyxFQUFxQjtRQUNuQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxTQUFTLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDOUIsQ0FBQztJQUVEOztPQUVHO0lBQ0gsS0FBSztRQUNILEtBQUssSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUMxQixJQUFJLENBQUMsSUFBSSxDQUFDLGtCQUFrQixFQUFFLENBQUM7UUFDL0IsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztJQUNwQixDQUFDO0NBQ0YifQ== \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/transport_client.d.ts b/circuits/ts/.yalc/@aztec/wasm/dest/transport/transport_client.d.ts new file mode 100644 index 00000000000..a70ae9fea5e --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/transport_client.d.ts @@ -0,0 +1,44 @@ +/// +import EventEmitter from 'events'; +import { Connector } from './interface/connector.js'; +/** + * Augments the TransportClient class with more precise EventEmitter types. + */ +export interface TransportClient extends EventEmitter { + on(name: 'event_msg', handler: (payload: Payload) => void): this; + emit(name: 'event_msg', payload: Payload): boolean; +} +/** + * A TransportClient provides a request/response and event api to a corresponding TransportServer. + * If `broadcast` is called on TransportServer, TransportClients will emit an `event_msg`. + * The `request` method will block until a response is returned from the TransportServer's dispatch function. + * Request multiplexing is supported. + */ +export declare class TransportClient extends EventEmitter { + private transportConnect; + private msgId; + private pendingRequests; + private socket?; + constructor(transportConnect: Connector); + /** + * Create and register our socket using our Connector. + */ + open(): Promise; + /** + * Close this and stop listening for messages. + */ + close(): void; + /** + * Queue a request. + * @param payload - The request payload. + * @param transfer - Objects to transfer ownership of. + * @returns A promise of the query result. + */ + request(payload: Payload, transfer?: Transferable[]): Promise; + /** + * Handle an incoming socket message. + * @param msg - The message. + */ + private handleSocketMessage; +} +//# sourceMappingURL=transport_client.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/transport_client.d.ts.map b/circuits/ts/.yalc/@aztec/wasm/dest/transport/transport_client.d.ts.map new file mode 100644 index 00000000000..9d6db62d26d --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/transport_client.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"transport_client.d.ts","sourceRoot":"","sources":["../../src/transport/transport_client.ts"],"names":[],"mappings":";AACA,OAAO,YAAY,MAAM,QAAQ,CAAC;AAElC,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAiBrD;;GAEG;AACH,MAAM,WAAW,eAAe,CAAC,OAAO,CAAE,SAAQ,YAAY;IAC5D,EAAE,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI,CAAC;IACjE,IAAI,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC;CACpD;AAED;;;;;GAKG;AACH,qBAAa,eAAe,CAAC,OAAO,CAAE,SAAQ,YAAY;IAK5C,OAAO,CAAC,gBAAgB;IAJpC,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,eAAe,CAAwB;IAC/C,OAAO,CAAC,MAAM,CAAC,CAAS;gBAEJ,gBAAgB,EAAE,SAAS;IAI/C;;OAEG;IACG,IAAI;IAKV;;OAEG;IACH,KAAK;IAML;;;;;OAKG;IACH,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,YAAY,EAAE;IAanD;;;OAGG;IACH,OAAO,CAAC,mBAAmB;CAsB5B"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/transport_client.js b/circuits/ts/.yalc/@aztec/wasm/dest/transport/transport_client.js new file mode 100644 index 00000000000..ee8579704b4 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/transport_client.js @@ -0,0 +1,79 @@ +import { createDebugLogger } from '@aztec/log'; +import EventEmitter from 'events'; +import { isEventMessage } from './dispatch/messages.js'; +const debug = createDebugLogger('aztec:transport_client'); +/** + * A TransportClient provides a request/response and event api to a corresponding TransportServer. + * If `broadcast` is called on TransportServer, TransportClients will emit an `event_msg`. + * The `request` method will block until a response is returned from the TransportServer's dispatch function. + * Request multiplexing is supported. + */ +export class TransportClient extends EventEmitter { + constructor(transportConnect) { + super(); + this.transportConnect = transportConnect; + this.msgId = 0; + this.pendingRequests = []; + } + /** + * Create and register our socket using our Connector. + */ + async open() { + this.socket = await this.transportConnect.createSocket(); + this.socket.registerHandler(msg => this.handleSocketMessage(msg)); + } + /** + * Close this and stop listening for messages. + */ + close() { + this.socket?.close(); + this.socket = undefined; + this.removeAllListeners(); + } + /** + * Queue a request. + * @param payload - The request payload. + * @param transfer - Objects to transfer ownership of. + * @returns A promise of the query result. + */ + request(payload, transfer) { + if (!this.socket) { + throw new Error('Socket not open.'); + } + const msgId = this.msgId++; + const msg = { msgId, payload }; + debug(`->`, msg); + return new Promise((resolve, reject) => { + this.pendingRequests.push({ resolve, reject, msgId }); + this.socket.send(msg, transfer).catch(reject); + }); + } + /** + * Handle an incoming socket message. + * @param msg - The message. + */ + handleSocketMessage(msg) { + if (msg === undefined) { + // The remote socket closed. + this.close(); + return; + } + debug(`<-`, msg); + if (isEventMessage(msg)) { + this.emit('event_msg', msg.payload); + return; + } + const reqIndex = this.pendingRequests.findIndex(r => r.msgId === msg.msgId); + if (reqIndex === -1) { + return; + } + const [pending] = this.pendingRequests.splice(reqIndex, 1); + if (msg.error) { + pending.reject(new Error(msg.error)); + } + else { + pending.resolve(msg.payload); + } + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhbnNwb3J0X2NsaWVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90cmFuc3BvcnQvdHJhbnNwb3J0X2NsaWVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFDL0MsT0FBTyxZQUFZLE1BQU0sUUFBUSxDQUFDO0FBQ2xDLE9BQU8sRUFBZ0IsY0FBYyxFQUFtQixNQUFNLHdCQUF3QixDQUFDO0FBSXZGLE1BQU0sS0FBSyxHQUFHLGlCQUFpQixDQUFDLHdCQUF3QixDQUFDLENBQUM7QUFzQjFEOzs7OztHQUtHO0FBQ0gsTUFBTSxPQUFPLGVBQXlCLFNBQVEsWUFBWTtJQUt4RCxZQUFvQixnQkFBMkI7UUFDN0MsS0FBSyxFQUFFLENBQUM7UUFEVSxxQkFBZ0IsR0FBaEIsZ0JBQWdCLENBQVc7UUFKdkMsVUFBSyxHQUFHLENBQUMsQ0FBQztRQUNWLG9CQUFlLEdBQXFCLEVBQUUsQ0FBQztJQUsvQyxDQUFDO0lBRUQ7O09BRUc7SUFDSCxLQUFLLENBQUMsSUFBSTtRQUNSLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxJQUFJLENBQUMsZ0JBQWdCLENBQUMsWUFBWSxFQUFFLENBQUM7UUFDekQsSUFBSSxDQUFDLE1BQU0sQ0FBQyxlQUFlLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsbUJBQW1CLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUNwRSxDQUFDO0lBRUQ7O09BRUc7SUFDSCxLQUFLO1FBQ0gsSUFBSSxDQUFDLE1BQU0sRUFBRSxLQUFLLEVBQUUsQ0FBQztRQUNyQixJQUFJLENBQUMsTUFBTSxHQUFHLFNBQVMsQ0FBQztRQUN4QixJQUFJLENBQUMsa0JBQWtCLEVBQUUsQ0FBQztJQUM1QixDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSCxPQUFPLENBQUMsT0FBZ0IsRUFBRSxRQUF5QjtRQUNqRCxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRTtZQUNoQixNQUFNLElBQUksS0FBSyxDQUFDLGtCQUFrQixDQUFDLENBQUM7U0FDckM7UUFDRCxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDM0IsTUFBTSxHQUFHLEdBQUcsRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFFLENBQUM7UUFDL0IsS0FBSyxDQUFDLElBQUksRUFBRSxHQUFHLENBQUMsQ0FBQztRQUNqQixPQUFPLElBQUksT0FBTyxDQUFNLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxFQUFFO1lBQzFDLElBQUksQ0FBQyxlQUFlLENBQUMsSUFBSSxDQUFDLEVBQUUsT0FBTyxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUsQ0FBQyxDQUFDO1lBQ3RELElBQUksQ0FBQyxNQUFPLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxRQUFRLENBQUMsQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDakQsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQ7OztPQUdHO0lBQ0ssbUJBQW1CLENBQUMsR0FBaUU7UUFDM0YsSUFBSSxHQUFHLEtBQUssU0FBUyxFQUFFO1lBQ3JCLDRCQUE0QjtZQUM1QixJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDYixPQUFPO1NBQ1I7UUFDRCxLQUFLLENBQUMsSUFBSSxFQUFFLEdBQUcsQ0FBQyxDQUFDO1FBQ2pCLElBQUksY0FBYyxDQUFDLEdBQUcsQ0FBQyxFQUFFO1lBQ3ZCLElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUNwQyxPQUFPO1NBQ1I7UUFDRCxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsZUFBZSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxLQUFLLEtBQUssR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzVFLElBQUksUUFBUSxLQUFLLENBQUMsQ0FBQyxFQUFFO1lBQ25CLE9BQU87U0FDUjtRQUNELE1BQU0sQ0FBQyxPQUFPLENBQUMsR0FBRyxJQUFJLENBQUMsZUFBZSxDQUFDLE1BQU0sQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFDM0QsSUFBSSxHQUFHLENBQUMsS0FBSyxFQUFFO1lBQ2IsT0FBTyxDQUFDLE1BQU0sQ0FBQyxJQUFJLEtBQUssQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztTQUN0QzthQUFNO1lBQ0wsT0FBTyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUM7U0FDOUI7SUFDSCxDQUFDO0NBQ0YifQ== \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/transport_server.d.ts b/circuits/ts/.yalc/@aztec/wasm/dest/transport/transport_server.d.ts new file mode 100644 index 00000000000..109e9210f8b --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/transport_server.d.ts @@ -0,0 +1,44 @@ +import { Listener } from './interface/listener.js'; +/** + * Keeps track of clients, providing a broadcast, and request/response api with multiplexing. + */ +export declare class TransportServer { + private listener; + private msgHandlerFn; + private sockets; + constructor(listener: Listener, msgHandlerFn: (msg: Payload) => Promise); + /** + * Start accepting new connections. + */ + start(): void; + /** + * Stops accepting new connections. It doesn't close existing sockets. + * It's expected the clients will gracefully complete by closing their end, sending an `undefined` message. + */ + stop(): void; + /** + * Broadcast a message. + * @param msg - The message. + */ + broadcast(msg: Payload): Promise; + /** + * New socket registration. + * @param socket - The socket to register. + */ + private handleNewSocket; + /** + * Detect the 'transferables' argument to our socket from our message + * handler return type. + * @param data - The return object. + * @returns - The data and the. + */ + private getPayloadAndTransfers; + /** + * Handles a socket message from a listener. + * @param socket - The socket. + * @param requestMessage - The message to handle. + * @returns The socket response. + */ + private handleSocketMessage; +} +//# sourceMappingURL=transport_server.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/transport_server.d.ts.map b/circuits/ts/.yalc/@aztec/wasm/dest/transport/transport_server.d.ts.map new file mode 100644 index 00000000000..103804f9808 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/transport_server.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"transport_server.d.ts","sourceRoot":"","sources":["../../src/transport/transport_server.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAInD;;GAEG;AACH,qBAAa,eAAe,CAAC,OAAO;IAGtB,OAAO,CAAC,QAAQ;IAAY,OAAO,CAAC,YAAY;IAF5D,OAAO,CAAC,OAAO,CAAgB;gBAEX,QAAQ,EAAE,QAAQ,EAAU,YAAY,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,GAAG,CAAC;IAE5F;;OAEG;IACH,KAAK;IAKL;;;OAGG;IACH,IAAI;IAIJ;;;OAGG;IACG,SAAS,CAAC,GAAG,EAAE,OAAO;IAI5B;;;OAGG;IACH,OAAO,CAAC,eAAe;IAcvB;;;;;OAKG;IACH,OAAO,CAAC,sBAAsB;IAe9B;;;;;OAKG;YACW,mBAAmB;CAalC"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/transport_server.js b/circuits/ts/.yalc/@aztec/wasm/dest/transport/transport_server.js new file mode 100644 index 00000000000..b1865345fc4 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/transport/transport_server.js @@ -0,0 +1,89 @@ +import { isTransferDescriptor } from './interface/transferable.js'; +/** + * Keeps track of clients, providing a broadcast, and request/response api with multiplexing. + */ +export class TransportServer { + constructor(listener, msgHandlerFn) { + this.listener = listener; + this.msgHandlerFn = msgHandlerFn; + this.sockets = []; + } + /** + * Start accepting new connections. + */ + start() { + this.listener.on('new_socket', client => this.handleNewSocket(client)); + this.listener.open(); + } + /** + * Stops accepting new connections. It doesn't close existing sockets. + * It's expected the clients will gracefully complete by closing their end, sending an `undefined` message. + */ + stop() { + this.listener.close(); + } + /** + * Broadcast a message. + * @param msg - The message. + */ + async broadcast(msg) { + await Promise.all(this.sockets.map(s => s.send({ payload: msg }))); + } + /** + * New socket registration. + * @param socket - The socket to register. + */ + handleNewSocket(socket) { + socket.registerHandler(async (msg) => { + if (msg === undefined) { + // Client socket has closed. Remove it from the list of sockets. Call close on it for any cleanup. + const socketIndex = this.sockets.findIndex(s => s === socket); + const [closingSocket] = this.sockets.splice(socketIndex, 1); + closingSocket.close(); + return; + } + return await this.handleSocketMessage(socket, msg); + }); + this.sockets.push(socket); + } + /** + * Detect the 'transferables' argument to our socket from our message + * handler return type. + * @param data - The return object. + * @returns - The data and the. + */ + getPayloadAndTransfers(data) { + if (isTransferDescriptor(data)) { + // We treat PayloadWithTransfers specially so that we're able to + // attach transferables while keeping a simple return-type based usage + return [data.send, data.transferables]; + } + if (data instanceof Uint8Array) { + // We may want to devise a better solution to this. We maybe given a view over a non cloneable/transferrable + // ArrayBuffer (such as a view over wasm memory). In this case we want to take a copy, and then transfer it. + const respPayload = data instanceof Uint8Array && ArrayBuffer.isView(data) ? new Uint8Array(data) : data; + const transferables = data instanceof Uint8Array ? [respPayload.buffer] : []; + return [respPayload, transferables]; + } + return [data, []]; + } + /** + * Handles a socket message from a listener. + * @param socket - The socket. + * @param requestMessage - The message to handle. + * @returns The socket response. + */ + async handleSocketMessage(socket, { msgId, payload }) { + try { + const data = await this.msgHandlerFn(payload); + const [respPayload, transferables] = this.getPayloadAndTransfers(data); + const rep = { msgId, payload: respPayload }; + await socket.send(rep, transferables); + } + catch (err) { + const rep = { msgId, error: err.stack }; + await socket.send(rep); + } + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhbnNwb3J0X3NlcnZlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90cmFuc3BvcnQvdHJhbnNwb3J0X3NlcnZlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFHQSxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUVuRTs7R0FFRztBQUNILE1BQU0sT0FBTyxlQUFlO0lBRzFCLFlBQW9CLFFBQWtCLEVBQVUsWUFBNEM7UUFBeEUsYUFBUSxHQUFSLFFBQVEsQ0FBVTtRQUFVLGlCQUFZLEdBQVosWUFBWSxDQUFnQztRQUZwRixZQUFPLEdBQWEsRUFBRSxDQUFDO0lBRWdFLENBQUM7SUFFaEc7O09BRUc7SUFDSCxLQUFLO1FBQ0gsSUFBSSxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUMsWUFBWSxFQUFFLE1BQU0sQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDO1FBQ3ZFLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDdkIsQ0FBQztJQUVEOzs7T0FHRztJQUNILElBQUk7UUFDRixJQUFJLENBQUMsUUFBUSxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQ3hCLENBQUM7SUFFRDs7O09BR0c7SUFDSCxLQUFLLENBQUMsU0FBUyxDQUFDLEdBQVk7UUFDMUIsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxFQUFFLE9BQU8sRUFBRSxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNyRSxDQUFDO0lBRUQ7OztPQUdHO0lBQ0ssZUFBZSxDQUFDLE1BQWM7UUFDcEMsTUFBTSxDQUFDLGVBQWUsQ0FBQyxLQUFLLEVBQUMsR0FBRyxFQUFDLEVBQUU7WUFDakMsSUFBSSxHQUFHLEtBQUssU0FBUyxFQUFFO2dCQUNyQixrR0FBa0c7Z0JBQ2xHLE1BQU0sV0FBVyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxLQUFLLE1BQU0sQ0FBQyxDQUFDO2dCQUM5RCxNQUFNLENBQUMsYUFBYSxDQUFDLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsV0FBVyxFQUFFLENBQUMsQ0FBQyxDQUFDO2dCQUM1RCxhQUFhLENBQUMsS0FBSyxFQUFFLENBQUM7Z0JBQ3RCLE9BQU87YUFDUjtZQUNELE9BQU8sTUFBTSxJQUFJLENBQUMsbUJBQW1CLENBQUMsTUFBTSxFQUFFLEdBQUcsQ0FBQyxDQUFDO1FBQ3JELENBQUMsQ0FBQyxDQUFDO1FBQ0gsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDNUIsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ0ssc0JBQXNCLENBQUMsSUFBUztRQUN0QyxJQUFJLG9CQUFvQixDQUFDLElBQUksQ0FBQyxFQUFFO1lBQzlCLGdFQUFnRTtZQUNoRSxzRUFBc0U7WUFDdEUsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDO1NBQ3hDO1FBQ0QsSUFBSSxJQUFJLFlBQVksVUFBVSxFQUFFO1lBQzlCLDRHQUE0RztZQUM1Ryw0R0FBNEc7WUFDNUcsTUFBTSxXQUFXLEdBQUcsSUFBSSxZQUFZLFVBQVUsSUFBSSxXQUFXLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLFVBQVUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDO1lBQ3pHLE1BQU0sYUFBYSxHQUFHLElBQUksWUFBWSxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsV0FBVyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7WUFDN0UsT0FBTyxDQUFDLFdBQVcsRUFBRSxhQUFhLENBQUMsQ0FBQztTQUNyQztRQUNELE9BQU8sQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDcEIsQ0FBQztJQUNEOzs7OztPQUtHO0lBQ0ssS0FBSyxDQUFDLG1CQUFtQixDQUFDLE1BQWMsRUFBRSxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQTJCO1FBQzNGLElBQUk7WUFDRixNQUFNLElBQUksR0FBRyxNQUFNLElBQUksQ0FBQyxZQUFZLENBQUMsT0FBTyxDQUFDLENBQUM7WUFFOUMsTUFBTSxDQUFDLFdBQVcsRUFBRSxhQUFhLENBQUMsR0FBRyxJQUFJLENBQUMsc0JBQXNCLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDdkUsTUFBTSxHQUFHLEdBQTZCLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxXQUFXLEVBQUUsQ0FBQztZQUV0RSxNQUFNLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLGFBQWEsQ0FBQyxDQUFDO1NBQ3ZDO1FBQUMsT0FBTyxHQUFRLEVBQUU7WUFDakIsTUFBTSxHQUFHLEdBQTZCLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxHQUFHLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDbEUsTUFBTSxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1NBQ3hCO0lBQ0gsQ0FBQztDQUNGIn0= \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/wasm/async_call_state.d.ts b/circuits/ts/.yalc/@aztec/wasm/dest/wasm/async_call_state.d.ts new file mode 100644 index 00000000000..9c987278c76 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/wasm/async_call_state.d.ts @@ -0,0 +1,72 @@ +import { WasmModule } from './wasm_module.js'; +/** + * The state of an asynchronous WASM function. + */ +export interface AsyncFnState { + /** + * Is this a contination? + */ + continuation: boolean; + /** + * A result, if one exists. + */ + result?: any; +} +/** + * To enable asynchronous callbacks from wasm to js, we leverage asyncify. + * Https://kripken.github.io/blog/wasm/2019/07/16/asyncify.html. + * + * This class holds state and logic specific to handling async calls from wasm to js. + * A single instance of this class is instantiated as part of BarretenbergWasm. + * It allocates some memory for the asyncify stack data and initialises it. + * + * To make an async call into the wasm, just call `call` the same as in BarretenbergWasm, only it returns a promise. + * + * To make an async import that will be called from the wasm, wrap a function with the signature: + * my_func(state: AsyncFnState, ...args) + * with a call to `wrapImportFn`. + * The arguments are whatever the original call arguments were. The addition of AsyncFnState as the first argument + * allows for the detection of wether the function is continuing after the the async call has completed. + * If `state.continuation` is false, the function should start its async operation and return the promise. + * If `state.continuation` is true, the function can get the result from `state.result` perform any finalisation, + * and return an (optional) value to the wasm. + */ +export declare class AsyncCallState { + private ASYNCIFY_DATA_SIZE; + private asyncifyDataAddr; + private asyncPromise?; + private wasm; + private state?; + private callExport; + /** + * Initialize the call hooks with a WasmModule. + * @param wasm - The module. + */ + init(wasm: WasmModule): void; + /** + * Log a message. + * @param args - The message arguments. + */ + private debug; + /** + * Free the data associated with async call states. + */ + destroy(): void; + /** + * We call the wasm function, that will in turn call back into js via callImport and set this.asyncPromise and + * enable the instrumented "record stack unwinding" code path. + * Once the stack has unwound out of the wasm call, we enter into a loop of resolving the promise set in the call + * to callImport, and calling back into the wasm to rewind the stack and continue execution. + * @param name - The function name. + * @param args - The function args. + * @returns The function result. + */ + call(name: string, ...args: any): Promise; + /** + * Wrap a WASM import function. + * @param fn - The function. + * @returns A wrapped version with asyncify calls. + */ + wrapImportFn(fn: (state: AsyncFnState, ...args: any[]) => any): (...args: any[]) => any; +} +//# sourceMappingURL=async_call_state.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/wasm/async_call_state.d.ts.map b/circuits/ts/.yalc/@aztec/wasm/dest/wasm/async_call_state.d.ts.map new file mode 100644 index 00000000000..ae4697ced4c --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/wasm/async_call_state.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"async_call_state.d.ts","sourceRoot":"","sources":["../../src/wasm/async_call_state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;OAEG;IACH,YAAY,EAAE,OAAO,CAAC;IACtB;;OAEG;IACH,MAAM,CAAC,EAAE,GAAG,CAAC;CACd;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,kBAAkB,CAAa;IACvC,OAAO,CAAC,gBAAgB,CAAU;IAClC,OAAO,CAAC,YAAY,CAAC,CAAe;IACpC,OAAO,CAAC,IAAI,CAAc;IAC1B,OAAO,CAAC,KAAK,CAAC,CAAe;IAC7B,OAAO,CAAC,UAAU,CAA8B;IAEhD;;;OAGG;IACI,IAAI,CAAC,IAAI,EAAE,UAAU;IAY5B;;;OAGG;IACH,OAAO,CAAC,KAAK;IAIb;;OAEG;IACI,OAAO;IAKd;;;;;;;;OAQG;IACU,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG;IA2B5C;;;;OAIG;IACI,YAAY,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,aACjD,GAAG,EAAE;CAkBzB"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/wasm/async_call_state.js b/circuits/ts/.yalc/@aztec/wasm/dest/wasm/async_call_state.js new file mode 100644 index 00000000000..b24bb8432f6 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/wasm/async_call_state.js @@ -0,0 +1,111 @@ +/** + * To enable asynchronous callbacks from wasm to js, we leverage asyncify. + * Https://kripken.github.io/blog/wasm/2019/07/16/asyncify.html. + * + * This class holds state and logic specific to handling async calls from wasm to js. + * A single instance of this class is instantiated as part of BarretenbergWasm. + * It allocates some memory for the asyncify stack data and initialises it. + * + * To make an async call into the wasm, just call `call` the same as in BarretenbergWasm, only it returns a promise. + * + * To make an async import that will be called from the wasm, wrap a function with the signature: + * my_func(state: AsyncFnState, ...args) + * with a call to `wrapImportFn`. + * The arguments are whatever the original call arguments were. The addition of AsyncFnState as the first argument + * allows for the detection of wether the function is continuing after the the async call has completed. + * If `state.continuation` is false, the function should start its async operation and return the promise. + * If `state.continuation` is true, the function can get the result from `state.result` perform any finalisation, + * and return an (optional) value to the wasm. + */ +export class AsyncCallState { + constructor() { + this.ASYNCIFY_DATA_SIZE = 16 * 1024; + } + /** + * Initialize the call hooks with a WasmModule. + * @param wasm - The module. + */ + init(wasm) { + this.wasm = wasm; + this.callExport = (name, ...args) => wasm.call(name, ...args); + // Allocate memory for asyncify stack data. + this.asyncifyDataAddr = this.callExport('bbmalloc', this.ASYNCIFY_DATA_SIZE); + // TODO: is this view construction problematic like in WasmModule? + const view = new Uint32Array(wasm.getRawMemory().buffer); + // First two integers of asyncify data, are the start and end of the stack region. + view[this.asyncifyDataAddr >> 2] = this.asyncifyDataAddr + 8; + view[(this.asyncifyDataAddr + 4) >> 2] = this.asyncifyDataAddr + this.ASYNCIFY_DATA_SIZE; + } + /** + * Log a message. + * @param args - The message arguments. + */ + debug(...args) { + this.wasm.getLogger()(...args); + } + /** + * Free the data associated with async call states. + */ + destroy() { + // Free call stack data. + this.callExport('bbfree', this.asyncifyDataAddr); + } + /** + * We call the wasm function, that will in turn call back into js via callImport and set this.asyncPromise and + * enable the instrumented "record stack unwinding" code path. + * Once the stack has unwound out of the wasm call, we enter into a loop of resolving the promise set in the call + * to callImport, and calling back into the wasm to rewind the stack and continue execution. + * @param name - The function name. + * @param args - The function args. + * @returns The function result. + */ + async call(name, ...args) { + if (this.state) { + throw new Error(`Can only handle one async call at a time: ${name}(${args})`); + } + this.state = { continuation: false }; + let result = this.callExport(name, ...args); + while (this.asyncPromise) { + // Disable the instrumented "record stack unwinding" code path. + this.callExport('asyncify_stop_unwind'); + this.debug('stack unwound.'); + // Wait for the async work to complete. + this.state.result = await this.asyncPromise; + this.state.continuation = true; + this.debug('result set starting rewind.'); + // Enable "stack rewinding" code path. + this.callExport('asyncify_start_rewind', this.asyncifyDataAddr); + // Call function again to rebuild the stack, and continue where we left off. + result = this.callExport(name, ...args); + } + // Cleanup + this.state = undefined; + return result; + } + /** + * Wrap a WASM import function. + * @param fn - The function. + * @returns A wrapped version with asyncify calls. + */ + wrapImportFn(fn) { + return (...args) => { + if (!this.asyncPromise) { + // We are in the normal code path. Start the async fetch of data. + this.asyncPromise = fn(this.state, ...args); + // Enable "record stack unwinding" code path and return. + this.callExport('asyncify_start_unwind', this.asyncifyDataAddr); + } + else { + // We are in the stack rewind code path, called once the promise is resolved. + // Save the result data back to the wasm, disable stack rewind code paths, and return. + this.callExport('asyncify_stop_rewind'); + const result = fn(this.state, ...args); + // Cleanup. + this.asyncPromise = undefined; + this.state = { continuation: false }; + return result; + } + }; + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXN5bmNfY2FsbF9zdGF0ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy93YXNtL2FzeW5jX2NhbGxfc3RhdGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBZ0JBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FrQkc7QUFDSCxNQUFNLE9BQU8sY0FBYztJQUEzQjtRQUNVLHVCQUFrQixHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUM7SUFtR3pDLENBQUM7SUE1RkM7OztPQUdHO0lBQ0ksSUFBSSxDQUFDLElBQWdCO1FBQzFCLElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDO1FBQ2pCLElBQUksQ0FBQyxVQUFVLEdBQUcsQ0FBQyxJQUFZLEVBQUUsR0FBRyxJQUFXLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLEdBQUcsSUFBSSxDQUFDLENBQUM7UUFDN0UsMkNBQTJDO1FBQzNDLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLFVBQVUsRUFBRSxJQUFJLENBQUMsa0JBQWtCLENBQUMsQ0FBQztRQUM3RSxrRUFBa0U7UUFDbEUsTUFBTSxJQUFJLEdBQUcsSUFBSSxXQUFXLENBQUMsSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ3pELGtGQUFrRjtRQUNsRixJQUFJLENBQUMsSUFBSSxDQUFDLGdCQUFnQixJQUFJLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxDQUFDLENBQUM7UUFDN0QsSUFBSSxDQUFDLENBQUMsSUFBSSxDQUFDLGdCQUFnQixHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxJQUFJLENBQUMsa0JBQWtCLENBQUM7SUFDM0YsQ0FBQztJQUVEOzs7T0FHRztJQUNLLEtBQUssQ0FBQyxHQUFHLElBQVc7UUFDMUIsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFT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 \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/wasm/empty_wasi_sdk.d.ts b/circuits/ts/.yalc/@aztec/wasm/dest/wasm/empty_wasi_sdk.d.ts new file mode 100644 index 00000000000..3ba72aaa184 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/wasm/empty_wasi_sdk.d.ts @@ -0,0 +1,24 @@ +/** + * Dummy implementation of a necessary part of the wasi api: + * https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md + * We don't use these functions, but the environment expects them. + * TODO find a way to update off of wasi 12. + */ +export declare const getEmptyWasiSdk: (debug?: import("@aztec/log").DebugLogger) => { + clock_time_get(): void; + environ_get(): void; + environ_sizes_get(): void; + fd_close(): void; + fd_read(): void; + fd_write(): void; + fd_seek(): void; + fd_fdstat_get(): void; + fd_fdstat_set_flags(): void; + fd_prestat_get(): number; + fd_prestat_dir_name(): number; + path_open(): void; + path_filestat_get(): void; + proc_exit(): number; + random_get(): number; +}; +//# sourceMappingURL=empty_wasi_sdk.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/wasm/empty_wasi_sdk.d.ts.map b/circuits/ts/.yalc/@aztec/wasm/dest/wasm/empty_wasi_sdk.d.ts.map new file mode 100644 index 00000000000..961a206c39f --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/wasm/empty_wasi_sdk.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"empty_wasi_sdk.d.ts","sourceRoot":"","sources":["../../src/wasm/empty_wasi_sdk.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AAGH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;CAkD1B,CAAC"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/wasm/empty_wasi_sdk.js b/circuits/ts/.yalc/@aztec/wasm/dest/wasm/empty_wasi_sdk.js new file mode 100644 index 00000000000..e40bba9f455 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/wasm/empty_wasi_sdk.js @@ -0,0 +1,61 @@ +import { createDebugLogger } from '@aztec/log'; +/** + * Dummy implementation of a necessary part of the wasi api: + * https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md + * We don't use these functions, but the environment expects them. + * TODO find a way to update off of wasi 12. + */ +/* eslint-disable camelcase */ +/* eslint-disable jsdoc/require-jsdoc */ +export const getEmptyWasiSdk = (debug = createDebugLogger('wasm:empty_wasi_sdk')) => ({ + clock_time_get() { + debug('clock_time_get'); + }, + environ_get() { + debug('environ_get'); + }, + environ_sizes_get() { + debug('environ_sizes_get'); + }, + fd_close() { + debug('fd_close'); + }, + fd_read() { + debug('fd_read'); + }, + fd_write() { + debug('fd_write'); + }, + fd_seek() { + debug('fd_seek'); + }, + fd_fdstat_get() { + debug('fd_fdstat_get'); + }, + fd_fdstat_set_flags() { + debug('fd_fdstat_set_flags'); + }, + fd_prestat_get() { + debug('fd_prestat_get'); + return 8; + }, + fd_prestat_dir_name() { + debug('fd_prestat_dir_name'); + return 28; + }, + path_open() { + debug('path_open'); + }, + path_filestat_get() { + debug('path_filestat_get'); + }, + proc_exit() { + debug('proc_exit'); + return 52; + }, + random_get() { + debug('random_get'); + return 1; + }, +}); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW1wdHlfd2FzaV9zZGsuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvd2FzbS9lbXB0eV93YXNpX3Nkay50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFFL0M7Ozs7O0dBS0c7QUFDSCw4QkFBOEI7QUFDOUIsd0NBQXdDO0FBQ3hDLE1BQU0sQ0FBQyxNQUFNLGVBQWUsR0FBRyxDQUFDLEtBQUssR0FBRyxpQkFBaUIsQ0FBQyxxQkFBcUIsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQ3BGLGNBQWM7UUFDWixLQUFLLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztJQUMxQixDQUFDO0lBQ0QsV0FBVztRQUNULEtBQUssQ0FBQyxhQUFhLENBQUMsQ0FBQztJQUN2QixDQUFDO0lBQ0QsaUJBQWlCO1FBQ2YsS0FBSyxDQUFDLG1CQUFtQixDQUFDLENBQUM7SUFDN0IsQ0FBQztJQUNELFFBQVE7UUFDTixLQUFLLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDcEIsQ0FBQztJQUNELE9BQU87UUFDTCxLQUFLLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDbkIsQ0FBQztJQUNELFFBQVE7UUFDTixLQUFLLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDcEIsQ0FBQztJQUNELE9BQU87UUFDTCxLQUFLLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDbkIsQ0FBQztJQUNELGFBQWE7UUFDWCxLQUFLLENBQUMsZUFBZSxDQUFDLENBQUM7SUFDekIsQ0FBQztJQUNELG1CQUFtQjtRQUNqQixLQUFLLENBQUMscUJBQXFCLENBQUMsQ0FBQztJQUMvQixDQUFDO0lBQ0QsY0FBYztRQUNaLEtBQUssQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO1FBQ3hCLE9BQU8sQ0FBQyxDQUFDO0lBQ1gsQ0FBQztJQUNELG1CQUFtQjtRQUNqQixLQUFLLENBQUMscUJBQXFCLENBQUMsQ0FBQztRQUM3QixPQUFPLEVBQUUsQ0FBQztJQUNaLENBQUM7SUFDRCxTQUFTO1FBQ1AsS0FBSyxDQUFDLFdBQVcsQ0FBQyxDQUFDO0lBQ3JCLENBQUM7SUFDRCxpQkFBaUI7UUFDZixLQUFLLENBQUMsbUJBQW1CLENBQUMsQ0FBQztJQUM3QixDQUFDO0lBQ0QsU0FBUztRQUNQLEtBQUssQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUNuQixPQUFPLEVBQUUsQ0FBQztJQUNaLENBQUM7SUFDRCxVQUFVO1FBQ1IsS0FBSyxDQUFDLFlBQVksQ0FBQyxDQUFDO1FBQ3BCLE9BQU8sQ0FBQyxDQUFDO0lBQ1gsQ0FBQztDQUNGLENBQUMsQ0FBQyJ9 \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/wasm/index.d.ts b/circuits/ts/.yalc/@aztec/wasm/dest/wasm/index.d.ts new file mode 100644 index 00000000000..1247c354830 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/wasm/index.d.ts @@ -0,0 +1,3 @@ +export { AsyncCallState, AsyncFnState } from './async_call_state.js'; +export { WasmModule } from './wasm_module.js'; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/wasm/index.d.ts.map b/circuits/ts/.yalc/@aztec/wasm/dest/wasm/index.d.ts.map new file mode 100644 index 00000000000..e4a88cedea0 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/wasm/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/wasm/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/wasm/index.js b/circuits/ts/.yalc/@aztec/wasm/dest/wasm/index.js new file mode 100644 index 00000000000..8c9ce830550 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/wasm/index.js @@ -0,0 +1,3 @@ +export { AsyncCallState } from './async_call_state.js'; +export { WasmModule } from './wasm_module.js'; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvd2FzbS9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsY0FBYyxFQUFnQixNQUFNLHVCQUF1QixDQUFDO0FBQ3JFLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQyJ9 \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/wasm/wasm_module.d.ts b/circuits/ts/.yalc/@aztec/wasm/dest/wasm/wasm_module.d.ts new file mode 100644 index 00000000000..a9634b4a9c0 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/wasm/wasm_module.d.ts @@ -0,0 +1,107 @@ +/// +import { DebugLogger } from '@aztec/log'; +import { Buffer } from 'buffer'; +/** + * WasmModule: + * Helper over a webassembly module. + * Assumes a few quirks. + * 1) the module expects wasi_snapshot_preview1 with the methods from getEmptyWasiSdk + * 2) of which the webassembly + * we instantiate only uses random_get (update this if more WASI sdk methods are needed). + */ +export declare class WasmModule { + private module; + private importFn; + private memory; + private heap; + private instance?; + private mutexQ; + private debug; + /** + * Create a wasm module. Should be followed by await init();. + * @param module - The module as a WebAssembly.Module or a Buffer. + * @param importFn - Imports expected by the WASM. + * @param loggerName - Optional, for debug logging. + */ + constructor(module: WebAssembly.Module | Buffer, importFn: (module: WasmModule) => any, loggerName?: string); + /** + * Return the wasm source. + * @returns The source. + */ + getModule(): WebAssembly.Module | Buffer; + /** + * Initialize this wasm module. + * @param wasmImportEnv - Linked to a module called "env". Functions implementations referenced from e.g. C++. + * @param initial - 20 pages by default. 20*2**16 \> 1mb stack size plus other overheads. + * @param maximum - 8192 maximum by default. 512mb. + */ + init(initial?: number, maximum?: number): Promise; + /** + * The methods or objects exported by the WASM module. + * @returns An indexable object. + */ + exports(): any; + /** + * Get the current logger. + * @returns Logging function. + */ + getLogger(): DebugLogger; + /** + * Add a logger. + * @param logger - Function to call when logging. + */ + addLogger(logger: DebugLogger): void; + /** + * Calls into the WebAssembly. + * @param name - The method name. + * @param args - The arguments to the method. + * @returns The numeric method result. + */ + call(name: string, ...args: any): number; + /** + * Get the memory used by the WASM module. + * @returns A WebAssembly memory object. + */ + getRawMemory(): WebAssembly.Memory; + /** + * Get the memory used by the WASM module, as a byte array. + * @returns A Uint8Array view of the WASM module memory. + */ + getMemory(): Uint8Array; + /** + * The memory size in bytes. + * @returns Number of bytes. + */ + memSize(): number; + /** + * Get a slice of memory between two addresses. + * @param start - The start address. + * @param end - The end address. + * @returns A Uint8Array view of memory. + */ + getMemorySlice(start: number, end: number): Uint8Array; + /** + * Write data into the heap. + * @param offset - The address to write data at. + * @param arr - The data to write. + */ + writeMemory(offset: number, arr: Uint8Array): void; + /** + * Read WASM memory as a JS string. + * @param addr - The memory address. + * @returns A JS string. + */ + getMemoryAsString(addr: number): string; + /** + * When calling the wasm, sometimes a caller will require exclusive access over a series of calls. + * E.g. When a result is written to address 0, one cannot have another caller writing to the same address via + * writeMemory before the result is read via sliceMemory. + * Acquire() gets a single token from a fifo. The caller must call release() to add the token back. + */ + acquire(): Promise; + /** + * Release the mutex, letting another promise call acquire(). + */ + release(): void; +} +//# sourceMappingURL=wasm_module.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/wasm/wasm_module.d.ts.map b/circuits/ts/.yalc/@aztec/wasm/dest/wasm/wasm_module.d.ts.map new file mode 100644 index 00000000000..2b5649b9d51 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/wasm/wasm_module.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"wasm_module.d.ts","sourceRoot":"","sources":["../../src/wasm/wasm_module.ts"],"names":[],"mappings":";AAAA,OAAO,EAAqB,WAAW,EAAE,MAAM,YAAY,CAAC;AAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAKhC;;;;;;;GAOG;AACH,qBAAa,UAAU;IAcnB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,QAAQ;IAdlB,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,IAAI,CAAc;IAC1B,OAAO,CAAC,QAAQ,CAAC,CAAuB;IACxC,OAAO,CAAC,MAAM,CAA6B;IAC3C,OAAO,CAAC,KAAK,CAAc;IAE3B;;;;;OAKG;gBAEO,MAAM,EAAE,WAAW,CAAC,MAAM,GAAG,MAAM,EACnC,QAAQ,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,GAAG,EAC7C,UAAU,SAAS;IAMrB;;;OAGG;IACI,SAAS,IAAI,WAAW,CAAC,MAAM,GAAG,MAAM;IAG/C;;;;;OAKG;IACU,IAAI,CAAC,OAAO,SAAK,EAAE,OAAO,SAAO;IAwC9C;;;OAGG;IACI,OAAO,IAAI,GAAG;IAOrB;;;OAGG;IACI,SAAS;IAIhB;;;OAGG;IACI,SAAS,CAAC,MAAM,EAAE,WAAW;IAQpC;;;;;OAKG;IACI,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,GAAG,MAAM;IAe/C;;;OAGG;IACI,YAAY,IAAI,WAAW,CAAC,MAAM;IAGzC;;;OAGG;IACI,SAAS,IAAI,UAAU;IAQ9B;;;OAGG;IACI,OAAO,IAAI,MAAM;IAIxB;;;;;OAKG;IACI,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM;IAIhD;;;;OAIG;IACI,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU;IAOlD;;;;OAIG;IACI,iBAAiB,CAAC,IAAI,EAAE,MAAM;IAQrC;;;;;OAKG;IACU,OAAO;IAIpB;;OAEG;IACI,OAAO;CAMf"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/wasm/wasm_module.js b/circuits/ts/.yalc/@aztec/wasm/dest/wasm/wasm_module.js new file mode 100644 index 00000000000..99fb9fe47bc --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/wasm/wasm_module.js @@ -0,0 +1,202 @@ +import { createDebugLogger } from '@aztec/log'; +import { Buffer } from 'buffer'; +import { MemoryFifo } from '../memory_fifo.js'; +import { getEmptyWasiSdk } from './empty_wasi_sdk.js'; +import { randomBytes } from 'crypto'; +/** + * WasmModule: + * Helper over a webassembly module. + * Assumes a few quirks. + * 1) the module expects wasi_snapshot_preview1 with the methods from getEmptyWasiSdk + * 2) of which the webassembly + * we instantiate only uses random_get (update this if more WASI sdk methods are needed). + */ +export class WasmModule { + /** + * Create a wasm module. Should be followed by await init();. + * @param module - The module as a WebAssembly.Module or a Buffer. + * @param importFn - Imports expected by the WASM. + * @param loggerName - Optional, for debug logging. + */ + constructor(module, importFn, loggerName = 'wasm') { + this.module = module; + this.importFn = importFn; + this.mutexQ = new MemoryFifo(); + this.debug = createDebugLogger(loggerName); + this.mutexQ.put(true); + } + /** + * Return the wasm source. + * @returns The source. + */ + getModule() { + return this.module; + } + /** + * Initialize this wasm module. + * @param wasmImportEnv - Linked to a module called "env". Functions implementations referenced from e.g. C++. + * @param initial - 20 pages by default. 20*2**16 \> 1mb stack size plus other overheads. + * @param maximum - 8192 maximum by default. 512mb. + */ + async init(initial = 20, maximum = 8192) { + this.debug(`initial mem: ${initial} pages, ${(initial * 2 ** 16) / (1024 * 1024)}mb. max mem: ${maximum} pages, ${(maximum * 2 ** 16) / (1024 * 1024)}mb`); + this.memory = new WebAssembly.Memory({ initial, maximum }); + // Create a view over the memory buffer. + // We do this once here, as webkit *seems* bugged out and actually shows this as new memory, + // thus displaying double. It's only worse if we create views on demand. I haven't established yet if + // the bug is also exasperating the termination on mobile due to "excessive memory usage". It could be + // that the OS is actually getting an incorrect reading in the same way the memory profiler does... + // The view will have to be recreated if the memory is grown. See getMemory(). + this.heap = new Uint8Array(this.memory.buffer); + // We support the wasi 12 SDK, but only implement random_get + /* eslint-disable camelcase */ + const importObj = { + wasi_snapshot_preview1: { + ...getEmptyWasiSdk(this.debug), + random_get: (arr, length) => { + arr = arr >>> 0; + const heap = this.getMemory(); + const randomData = randomBytes(length); + for (let i = arr; i < arr + length; ++i) { + heap[i] = randomData[i - arr]; + } + }, + }, + env: this.importFn(this), + }; + if (this.module instanceof WebAssembly.Module) { + this.instance = await WebAssembly.instantiate(this.module, importObj); + } + else { + const { instance } = await WebAssembly.instantiate(this.module, importObj); + this.instance = instance; + } + } + /** + * The methods or objects exported by the WASM module. + * @returns An indexable object. + */ + exports() { + if (!this.instance) { + throw new Error('WasmModule: not initialized!'); + } + return this.instance.exports; + } + /** + * Get the current logger. + * @returns Logging function. + */ + getLogger() { + return this.debug; + } + /** + * Add a logger. + * @param logger - Function to call when logging. + */ + addLogger(logger) { + const oldDebug = this.debug; + this.debug = (...args) => { + logger(...args); + oldDebug(...args); + }; + } + /** + * Calls into the WebAssembly. + * @param name - The method name. + * @param args - The arguments to the method. + * @returns The numeric method result. + */ + call(name, ...args) { + if (!this.exports()[name]) { + throw new Error(`WASM function ${name} not found.`); + } + try { + // When returning values from the WASM, use >>> operator to convert + // signed representation to unsigned representation. + return this.exports()[name](...args) >>> 0; + } + catch (err) { + const message = `WASM function ${name} aborted, error: ${err}`; + this.debug(message); + this.debug(err.stack); + throw new Error(message); + } + } + /** + * Get the memory used by the WASM module. + * @returns A WebAssembly memory object. + */ + getRawMemory() { + return this.memory; + } + /** + * Get the memory used by the WASM module, as a byte array. + * @returns A Uint8Array view of the WASM module memory. + */ + getMemory() { + // If the memory is grown, our view over it will be lost. Recreate the view. + if (this.heap.length === 0) { + this.heap = new Uint8Array(this.memory.buffer); + } + return this.heap; + } + /** + * The memory size in bytes. + * @returns Number of bytes. + */ + memSize() { + return this.getMemory().length; + } + /** + * Get a slice of memory between two addresses. + * @param start - The start address. + * @param end - The end address. + * @returns A Uint8Array view of memory. + */ + getMemorySlice(start, end) { + return this.getMemory().slice(start, end); + } + /** + * Write data into the heap. + * @param offset - The address to write data at. + * @param arr - The data to write. + */ + writeMemory(offset, arr) { + const mem = this.getMemory(); + for (let i = 0; i < arr.length; i++) { + mem[i + offset] = arr[i]; + } + } + /** + * Read WASM memory as a JS string. + * @param addr - The memory address. + * @returns A JS string. + */ + getMemoryAsString(addr) { + addr = addr >>> 0; + const m = this.getMemory(); + let i = addr; + for (; m[i] !== 0; ++i) + ; + return Buffer.from(m.slice(addr, i)).toString('ascii'); + } + /** + * When calling the wasm, sometimes a caller will require exclusive access over a series of calls. + * E.g. When a result is written to address 0, one cannot have another caller writing to the same address via + * writeMemory before the result is read via sliceMemory. + * Acquire() gets a single token from a fifo. The caller must call release() to add the token back. + */ + async acquire() { + await this.mutexQ.get(); + } + /** + * Release the mutex, letting another promise call acquire(). + */ + release() { + if (this.mutexQ.length() !== 0) { + throw new Error('Release called but not acquired.'); + } + this.mutexQ.put(true); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2FzbV9tb2R1bGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvd2FzbS93YXNtX21vZHVsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsaUJBQWlCLEVBQWUsTUFBTSxZQUFZLENBQUM7QUFDNUQsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLFFBQVEsQ0FBQztBQUNoQyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDL0MsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ3RELE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxRQUFRLENBQUM7QUFFckM7Ozs7Ozs7R0FPRztBQUNILE1BQU0sT0FBTyxVQUFVO0lBT3JCOzs7OztPQUtHO0lBQ0gsWUFDVSxNQUFtQyxFQUNuQyxRQUFxQyxFQUM3QyxVQUFVLEdBQUcsTUFBTTtRQUZYLFdBQU0sR0FBTixNQUFNLENBQTZCO1FBQ25DLGFBQVEsR0FBUixRQUFRLENBQTZCO1FBWHZDLFdBQU0sR0FBRyxJQUFJLFVBQVUsRUFBVyxDQUFDO1FBY3pDLElBQUksQ0FBQyxLQUFLLEdBQUcsaUJBQWlCLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDM0MsSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDeEIsQ0FBQztJQUVEOzs7T0FHRztJQUNJLFNBQVM7UUFDZCxPQUFPLElBQUksQ0FBQyxNQUFNLENBQUM7SUFDckIsQ0FBQztJQUNEOzs7OztPQUtHO0lBQ0ksS0FBSyxDQUFDLElBQUksQ0FBQyxPQUFPLEdBQUcsRUFBRSxFQUFFLE9BQU8sR0FBRyxJQUFJO1FBQzVDLElBQUksQ0FBQyxLQUFLLENBQ1IsZ0JBQWdCLE9BQU8sV0FBVyxDQUFDLE9BQU8sR0FBRyxDQUFDLElBQUksRUFBRSxDQUFDLEdBQUcsQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDLGdCQUFnQixPQUFPLFdBQzFGLENB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 \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/index.d.ts b/circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/index.d.ts new file mode 100644 index 00000000000..5d25ae688b9 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/index.d.ts @@ -0,0 +1,3 @@ +export * from './web_worker.js'; +export * from './web_data_store.js'; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/index.d.ts.map b/circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/index.d.ts.map new file mode 100644 index 00000000000..c27488b261d --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/worker/browser/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/index.js b/circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/index.js new file mode 100644 index 00000000000..769c36e8a11 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/index.js @@ -0,0 +1,3 @@ +export * from './web_worker.js'; +export * from './web_data_store.js'; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvd29ya2VyL2Jyb3dzZXIvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsY0FBYyxpQkFBaUIsQ0FBQztBQUNoQyxjQUFjLHFCQUFxQixDQUFDIn0= \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/start_web_module.d.ts b/circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/start_web_module.d.ts new file mode 100644 index 00000000000..64305a49267 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/start_web_module.d.ts @@ -0,0 +1,7 @@ +import { WasmModule } from '../../wasm/wasm_module.js'; +/** + * Start the transport server corresponding to this module. + * @param module - The WasmModule to host. + */ +export declare function startWebModule(module: WasmModule): void; +//# sourceMappingURL=start_web_module.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/start_web_module.d.ts.map b/circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/start_web_module.d.ts.map new file mode 100644 index 00000000000..236d51eb892 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/start_web_module.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"start_web_module.d.ts","sourceRoot":"","sources":["../../../src/worker/browser/start_web_module.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAEvD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,QAehD"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/start_web_module.js b/circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/start_web_module.js new file mode 100644 index 00000000000..107b51c3517 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/start_web_module.js @@ -0,0 +1,22 @@ +import { TransportServer, WorkerListener } from '../../transport/index.js'; +/** + * Start the transport server corresponding to this module. + * @param module - The WasmModule to host. + */ +export function startWebModule(module) { + const dispatch = async ({ fn, args }) => { + if (fn === '__destroyWorker__') { + transportServer.stop(); + return; + } + if (!module[fn]) { + throw new Error(`dispatch error, function not found: ${fn}`); + } + return await module[fn](...args); + }; + const transportListener = new WorkerListener(self); + const transportServer = new TransportServer(transportListener, dispatch); + module.addLogger((...args) => transportServer.broadcast({ fn: 'emit', args: ['log', ...args] })); + transportServer.start(); +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RhcnRfd2ViX21vZHVsZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy93b3JrZXIvYnJvd3Nlci9zdGFydF93ZWJfbW9kdWxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBZSxlQUFlLEVBQUUsY0FBYyxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFHeEY7OztHQUdHO0FBQ0gsTUFBTSxVQUFVLGNBQWMsQ0FBQyxNQUFrQjtJQUMvQyxNQUFNLFFBQVEsR0FBRyxLQUFLLEVBQUUsRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFlLEVBQUUsRUFBRTtRQUNuRCxJQUFJLEVBQUUsS0FBSyxtQkFBbUIsRUFBRTtZQUM5QixlQUFlLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDdkIsT0FBTztTQUNSO1FBQ0QsSUFBSSxDQUFFLE1BQWMsQ0FBQyxFQUFFLENBQUMsRUFBRTtZQUN4QixNQUFNLElBQUksS0FBSyxDQUFDLHVDQUF1QyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1NBQzlEO1FBQ0QsT0FBTyxNQUFPLE1BQWMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxDQUFDO0lBQzVDLENBQUMsQ0FBQztJQUNGLE1BQU0saUJBQWlCLEdBQUcsSUFBSSxjQUFjLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDbkQsTUFBTSxlQUFlLEdBQUcsSUFBSSxlQUFlLENBQWMsaUJBQWlCLEVBQUUsUUFBUSxDQUFDLENBQUM7SUFDdEYsTUFBTSxDQUFDLFNBQVMsQ0FBQyxDQUFDLEdBQUcsSUFBVyxFQUFFLEVBQUUsQ0FBQyxlQUFlLENBQUMsU0FBUyxDQUFDLEVBQUUsRUFBRSxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUsQ0FBQyxLQUFLLEVBQUUsR0FBRyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUN4RyxlQUFlLENBQUMsS0FBSyxFQUFFLENBQUM7QUFDMUIsQ0FBQyJ9 \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/web_data_store.d.ts b/circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/web_data_store.d.ts new file mode 100644 index 00000000000..9b5ab4853d9 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/web_data_store.d.ts @@ -0,0 +1,23 @@ +/// +import { DataStore } from '../data_store.js'; +/** + * Cache for data used by wasm module. + * Stores in a LevelUp database. + */ +export declare class WebDataStore implements DataStore { + private db; + constructor(); + /** + * Lookup a key. + * @param key - Key to lookup. + * @returns The buffer. + */ + get(key: string): Promise; + /** + * Alter a key. + * @param key - Key to alter. + * @param value - Buffer to store. + */ + set(key: string, value: Buffer): Promise; +} +//# sourceMappingURL=web_data_store.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/web_data_store.d.ts.map b/circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/web_data_store.d.ts.map new file mode 100644 index 00000000000..b786d902360 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/web_data_store.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"web_data_store.d.ts","sourceRoot":"","sources":["../../../src/worker/browser/web_data_store.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAI7C;;;GAGG;AACH,qBAAa,YAAa,YAAW,SAAS;IAC5C,OAAO,CAAC,EAAE,CAAU;;IAUpB;;;;OAIG;IACG,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAInD;;;;OAIG;IACG,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGrD"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/web_data_store.js b/circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/web_data_store.js new file mode 100644 index 00000000000..49f7cd14172 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/web_data_store.js @@ -0,0 +1,32 @@ +import levelup from 'levelup'; +import memdown from 'memdown'; +/** + * Cache for data used by wasm module. + * Stores in a LevelUp database. + */ +export class WebDataStore { + constructor() { + // TODO: The whole point of this is to reduce memory load in the browser. + // Replace with leveljs so the data is stored in indexeddb and not in memory. + // Hack: Cast as any to work around package "broken" with node16 resolution + // See https://github.com/microsoft/TypeScript/issues/49160 + this.db = levelup(memdown()); + } + /** + * Lookup a key. + * @param key - Key to lookup. + * @returns The buffer. + */ + async get(key) { + return await this.db.get(key).catch(() => { }); + } + /** + * Alter a key. + * @param key - Key to alter. + * @param value - Buffer to store. + */ + async set(key, value) { + await this.db.put(key, value); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2ViX2RhdGFfc3RvcmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvd29ya2VyL2Jyb3dzZXIvd2ViX2RhdGFfc3RvcmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxPQUFvQixNQUFNLFNBQVMsQ0FBQztBQUMzQyxPQUFPLE9BQU8sTUFBTSxTQUFTLENBQUM7QUFFOUI7OztHQUdHO0FBQ0gsTUFBTSxPQUFPLFlBQVk7SUFHdkI7UUFDRSx5RUFBeUU7UUFDekUsNkVBQTZFO1FBQzdFLDJFQUEyRTtRQUMzRSwyREFBMkQ7UUFDM0QsSUFBSSxDQUFDLEVBQUUsR0FBRyxPQUFPLENBQUUsT0FBZSxFQUFFLENBQUMsQ0FBQztJQUN4QyxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILEtBQUssQ0FBQyxHQUFHLENBQUMsR0FBVztRQUNuQixPQUFPLE1BQU0sSUFBSSxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUMsS0FBSyxDQUFDLEdBQUcsRUFBRSxHQUFFLENBQUMsQ0FBQyxDQUFDO0lBQ2hELENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsS0FBSyxDQUFDLEdBQUcsQ0FBQyxHQUFXLEVBQUUsS0FBYTtRQUNsQyxNQUFNLElBQUksQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsQ0FBQztJQUNoQyxDQUFDO0NBQ0YifQ== \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/web_worker.d.ts b/circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/web_worker.d.ts new file mode 100644 index 00000000000..45cdef0a245 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/web_worker.d.ts @@ -0,0 +1,10 @@ +import { WasmWorker } from '../wasm_worker.js'; +/** + * Instantiate a web worker. + * @param url - The URL. + * @param initialMem - Initial memory pages. + * @param maxMem - Maximum memory pages. + * @returns The worker. + */ +export declare function createWebWorker(url: string, initialMem?: number, maxMem?: number): Promise; +//# sourceMappingURL=web_worker.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/web_worker.d.ts.map b/circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/web_worker.d.ts.map new file mode 100644 index 00000000000..2756cc7c5df --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/web_worker.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"web_worker.d.ts","sourceRoot":"","sources":["../../../src/worker/browser/web_worker.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C;;;;;;GAMG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAY5G"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/web_worker.js b/circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/web_worker.js new file mode 100644 index 00000000000..71a0e1b145f --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/web_worker.js @@ -0,0 +1,23 @@ +import { WasmModule } from '../../wasm/wasm_module.js'; +import { createDispatchProxy, TransportClient, WorkerConnector } from '../../transport/index.js'; +/** + * Instantiate a web worker. + * @param url - The URL. + * @param initialMem - Initial memory pages. + * @param maxMem - Maximum memory pages. + * @returns The worker. + */ +export async function createWebWorker(url, initialMem, maxMem) { + const worker = new Worker(url); + const transportConnect = new WorkerConnector(worker); + const transportClient = new TransportClient(transportConnect); + await transportClient.open(); + const remoteModule = createDispatchProxy(WasmModule, transportClient); + remoteModule.destroyWorker = async () => { + await transportClient.request({ fn: '__destroyWorker__', args: [] }); + transportClient.close(); + }; + await remoteModule.init(initialMem, maxMem); + return remoteModule; +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2ViX3dvcmtlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy93b3JrZXIvYnJvd3Nlci93ZWJfd29ya2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUN2RCxPQUFPLEVBQUUsbUJBQW1CLEVBQWUsZUFBZSxFQUFFLGVBQWUsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBRzlHOzs7Ozs7R0FNRztBQUNILE1BQU0sQ0FBQyxLQUFLLFVBQVUsZUFBZSxDQUFDLEdBQVcsRUFBRSxVQUFtQixFQUFFLE1BQWU7SUFDckYsTUFBTSxNQUFNLEdBQUcsSUFBSSxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDL0IsTUFBTSxnQkFBZ0IsR0FBRyxJQUFJLGVBQWUsQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUNyRCxNQUFNLGVBQWUsR0FBRyxJQUFJLGVBQWUsQ0FBYyxnQkFBZ0IsQ0FBQyxDQUFDO0lBQzNFLE1BQU0sZUFBZSxDQUFDLElBQUksRUFBRSxDQUFDO0lBQzdCLE1BQU0sWUFBWSxHQUFHLG1CQUFtQixDQUFDLFVBQVUsRUFBRSxlQUFlLENBQWUsQ0FBQztJQUNwRixZQUFZLENBQUMsYUFBYSxHQUFHLEtBQUssSUFBSSxFQUFFO1FBQ3RDLE1BQU0sZUFBZSxDQUFDLE9BQU8sQ0FBQyxFQUFFLEVBQUUsRUFBRSxtQkFBbUIsRUFBRSxJQUFJLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQztRQUNyRSxlQUFlLENBQUMsS0FBSyxFQUFFLENBQUM7SUFDMUIsQ0FBQyxDQUFDO0lBQ0YsTUFBTSxZQUFZLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxNQUFNLENBQUMsQ0FBQztJQUM1QyxPQUFPLFlBQVksQ0FBQztBQUN0QixDQUFDIn0= \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/worker/data_store.d.ts b/circuits/ts/.yalc/@aztec/wasm/dest/worker/data_store.d.ts new file mode 100644 index 00000000000..0c9bd408c2d --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/worker/data_store.d.ts @@ -0,0 +1,9 @@ +/// +/** + * Simple read/write interface for wasm modules. + */ +export interface DataStore { + get(key: string): Promise; + set(key: string, value: Buffer): Promise; +} +//# sourceMappingURL=data_store.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/worker/data_store.d.ts.map b/circuits/ts/.yalc/@aztec/wasm/dest/worker/data_store.d.ts.map new file mode 100644 index 00000000000..4b0f53fd9d9 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/worker/data_store.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"data_store.d.ts","sourceRoot":"","sources":["../../src/worker/data_store.ts"],"names":[],"mappings":";AAAA;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC9C,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAChD"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/worker/data_store.js b/circuits/ts/.yalc/@aztec/wasm/dest/worker/data_store.js new file mode 100644 index 00000000000..fd170823f17 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/worker/data_store.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0YV9zdG9yZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy93b3JrZXIvZGF0YV9zdG9yZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIn0= \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/worker/index.d.ts b/circuits/ts/.yalc/@aztec/wasm/dest/worker/index.d.ts new file mode 100644 index 00000000000..07a37541295 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/worker/index.d.ts @@ -0,0 +1,3 @@ +export { WorkerPool } from './worker_pool.js'; +export { WasmWorker } from './wasm_worker.js'; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/worker/index.d.ts.map b/circuits/ts/.yalc/@aztec/wasm/dest/worker/index.d.ts.map new file mode 100644 index 00000000000..0960823e41d --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/worker/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/worker/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/worker/index.js b/circuits/ts/.yalc/@aztec/wasm/dest/worker/index.js new file mode 100644 index 00000000000..c36435a7a31 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/worker/index.js @@ -0,0 +1,2 @@ +export { WorkerPool } from './worker_pool.js'; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvd29ya2VyL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQyJ9 \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/worker/node/index.d.ts b/circuits/ts/.yalc/@aztec/wasm/dest/worker/node/index.d.ts new file mode 100644 index 00000000000..be9811545d5 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/worker/node/index.d.ts @@ -0,0 +1,3 @@ +export * from './node_worker.js'; +export * from './node_data_store.js'; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/worker/node/index.d.ts.map b/circuits/ts/.yalc/@aztec/wasm/dest/worker/node/index.d.ts.map new file mode 100644 index 00000000000..a406ecf876d --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/worker/node/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/worker/node/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/worker/node/index.js b/circuits/ts/.yalc/@aztec/wasm/dest/worker/node/index.js new file mode 100644 index 00000000000..cf7a0819450 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/worker/node/index.js @@ -0,0 +1,3 @@ +export * from './node_worker.js'; +export * from './node_data_store.js'; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvd29ya2VyL25vZGUvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsY0FBYyxrQkFBa0IsQ0FBQztBQUNqQyxjQUFjLHNCQUFzQixDQUFDIn0= \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/worker/node/node_data_store.d.ts b/circuits/ts/.yalc/@aztec/wasm/dest/worker/node/node_data_store.d.ts new file mode 100644 index 00000000000..5908d6599bb --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/worker/node/node_data_store.d.ts @@ -0,0 +1,22 @@ +/// +import { DataStore } from '../data_store.js'; +/** + * Cache for data used by wasm module. + */ +export declare class NodeDataStore implements DataStore { + private db; + constructor(path?: string); + /** + * Get a value from our DB. + * @param key - The key to look up. + * @returns The value. + */ + get(key: string): Promise; + /** + * Set a value in our DB. + * @param key - The key to update. + * @param value - The value to set. + */ + set(key: string, value: Buffer): Promise; +} +//# sourceMappingURL=node_data_store.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/worker/node/node_data_store.d.ts.map b/circuits/ts/.yalc/@aztec/wasm/dest/worker/node/node_data_store.d.ts.map new file mode 100644 index 00000000000..496c69d5094 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/worker/node/node_data_store.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"node_data_store.d.ts","sourceRoot":"","sources":["../../../src/worker/node/node_data_store.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAK7C;;GAEG;AACH,qBAAa,aAAc,YAAW,SAAS;IAC7C,OAAO,CAAC,EAAE,CAAU;gBAGR,IAAI,CAAC,EAAE,MAAM;IAMzB;;;;OAIG;IACG,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAInD;;;;OAIG;IACG,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGrD"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/worker/node/node_data_store.js b/circuits/ts/.yalc/@aztec/wasm/dest/worker/node/node_data_store.js new file mode 100644 index 00000000000..57be391030a --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/worker/node/node_data_store.js @@ -0,0 +1,31 @@ +import levelup from 'levelup'; +import leveldown from 'leveldown'; +import memdown from 'memdown'; +/** + * Cache for data used by wasm module. + */ +export class NodeDataStore { + // eslint-disable-next-line + constructor(path) { + // Hack: Cast as any to work around packages "broken" with node16 resolution + // See https://github.com/microsoft/TypeScript/issues/49160 + this.db = levelup(path ? leveldown(path) : memdown()); + } + /** + * Get a value from our DB. + * @param key - The key to look up. + * @returns The value. + */ + async get(key) { + return await this.db.get(key).catch(() => { }); + } + /** + * Set a value in our DB. + * @param key - The key to update. + * @param value - The value to set. + */ + async set(key, value) { + await this.db.put(key, value); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZV9kYXRhX3N0b3JlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3dvcmtlci9ub2RlL25vZGVfZGF0YV9zdG9yZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLE9BQW9CLE1BQU0sU0FBUyxDQUFDO0FBQzNDLE9BQU8sU0FBUyxNQUFNLFdBQVcsQ0FBQztBQUNsQyxPQUFPLE9BQU8sTUFBTSxTQUFTLENBQUM7QUFFOUI7O0dBRUc7QUFDSCxNQUFNLE9BQU8sYUFBYTtJQUd4QiwyQkFBMkI7SUFDM0IsWUFBWSxJQUFhO1FBQ3ZCLDRFQUE0RTtRQUM1RSwyREFBMkQ7UUFDM0QsSUFBSSxDQUFDLEVBQUUsR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBRSxTQUFpQixDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBRSxPQUFlLEVBQUUsQ0FBQyxDQUFDO0lBQzFFLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsS0FBSyxDQUFDLEdBQUcsQ0FBQyxHQUFXO1FBQ25CLE9BQU8sTUFBTSxJQUFJLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFLEdBQUUsQ0FBQyxDQUFDLENBQUM7SUFDaEQsQ0FBQztJQUVEOzs7O09BSUc7SUFDSCxLQUFLLENBQUMsR0FBRyxDQUFDLEdBQVcsRUFBRSxLQUFhO1FBQ2xDLE1BQU0sSUFBSSxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLEtBQUssQ0FBQyxDQUFDO0lBQ2hDLENBQUM7Q0FDRiJ9 \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/worker/node/node_worker.d.ts b/circuits/ts/.yalc/@aztec/wasm/dest/worker/node/node_worker.d.ts new file mode 100644 index 00000000000..5da7e01049d --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/worker/node/node_worker.d.ts @@ -0,0 +1,6 @@ +import { WasmWorker } from '../wasm_worker.js'; +/** + * + */ +export declare function createNodeWorker(filepath: string, initialMem?: number, maxMem?: number): Promise; +//# sourceMappingURL=node_worker.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/worker/node/node_worker.d.ts.map b/circuits/ts/.yalc/@aztec/wasm/dest/worker/node/node_worker.d.ts.map new file mode 100644 index 00000000000..26908ec619c --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/worker/node/node_worker.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"node_worker.d.ts","sourceRoot":"","sources":["../../../src/worker/node/node_worker.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAYlH"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/worker/node/node_worker.js b/circuits/ts/.yalc/@aztec/wasm/dest/worker/node/node_worker.js new file mode 100644 index 00000000000..155e31ba16b --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/worker/node/node_worker.js @@ -0,0 +1,21 @@ +import { Worker } from 'worker_threads'; +import { createDispatchProxy, TransportClient } from '../../transport/index.js'; +import { NodeConnector } from '../../transport/index.js'; +import { WasmModule } from '../../wasm/wasm_module.js'; +/** + * + */ +export async function createNodeWorker(filepath, initialMem, maxMem) { + const worker = new Worker(filepath); + const transportConnect = new NodeConnector(worker); + const transportClient = new TransportClient(transportConnect); + await transportClient.open(); + const remoteModule = createDispatchProxy(WasmModule, transportClient); + remoteModule.destroyWorker = async () => { + await transportClient.request({ fn: '__destroyWorker__', args: [] }); + transportClient.close(); + }; + await remoteModule.init(initialMem, maxMem); + return remoteModule; +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZV93b3JrZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvd29ya2VyL25vZGUvbm9kZV93b3JrZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ3hDLE9BQU8sRUFBRSxtQkFBbUIsRUFBZSxlQUFlLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUM3RixPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDekQsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBR3ZEOztHQUVHO0FBQ0gsTUFBTSxDQUFDLEtBQUssVUFBVSxnQkFBZ0IsQ0FBQyxRQUFnQixFQUFFLFVBQW1CLEVBQUUsTUFBZTtJQUMzRixNQUFNLE1BQU0sR0FBRyxJQUFJLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUNwQyxNQUFNLGdCQUFnQixHQUFHLElBQUksYUFBYSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ25ELE1BQU0sZUFBZSxHQUFHLElBQUksZUFBZSxDQUFjLGdCQUFnQixDQUFDLENBQUM7SUFDM0UsTUFBTSxlQUFlLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDN0IsTUFBTSxZQUFZLEdBQUcsbUJBQW1CLENBQUMsVUFBVSxFQUFFLGVBQWUsQ0FBZSxDQUFDO0lBQ3BGLFlBQVksQ0FBQyxhQUFhLEdBQUcsS0FBSyxJQUFJLEVBQUU7UUFDdEMsTUFBTSxlQUFlLENBQUMsT0FBTyxDQUFDLEVBQUUsRUFBRSxFQUFFLG1CQUFtQixFQUFFLElBQUksRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQ3JFLGVBQWUsQ0FBQyxLQUFLLEVBQUUsQ0FBQztJQUMxQixDQUFDLENBQUM7SUFDRixNQUFNLFlBQVksQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLE1BQU0sQ0FBQyxDQUFDO0lBQzVDLE9BQU8sWUFBWSxDQUFDO0FBQ3RCLENBQUMifQ== \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/worker/node/start_node_module.d.ts b/circuits/ts/.yalc/@aztec/wasm/dest/worker/node/start_node_module.d.ts new file mode 100644 index 00000000000..c118c248f46 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/worker/node/start_node_module.d.ts @@ -0,0 +1,7 @@ +import { WasmModule } from '../../wasm/wasm_module.js'; +/** + * Start the transport server corresponding to this module. + * @param module - The WasmModule to host. + */ +export declare function startNodeModule(module: WasmModule): void; +//# sourceMappingURL=start_node_module.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/worker/node/start_node_module.d.ts.map b/circuits/ts/.yalc/@aztec/wasm/dest/worker/node/start_node_module.d.ts.map new file mode 100644 index 00000000000..f006976f41e --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/worker/node/start_node_module.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"start_node_module.d.ts","sourceRoot":"","sources":["../../../src/worker/node/start_node_module.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAMvD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,UAAU,QAejD"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/worker/node/start_node_module.js b/circuits/ts/.yalc/@aztec/wasm/dest/worker/node/start_node_module.js new file mode 100644 index 00000000000..8d4aee385db --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/worker/node/start_node_module.js @@ -0,0 +1,26 @@ +import { parentPort } from 'worker_threads'; +import { NodeListener, TransportServer } from '../../transport/index.js'; +if (!parentPort) { + throw new Error('InvalidWorker'); +} +/** + * Start the transport server corresponding to this module. + * @param module - The WasmModule to host. + */ +export function startNodeModule(module) { + const dispatch = async ({ fn, args }) => { + if (fn === '__destroyWorker__') { + transportServer.stop(); + return; + } + if (!module[fn]) { + throw new Error(`dispatch error, function not found: ${fn}`); + } + return await module[fn](...args); + }; + const transportListener = new NodeListener(); + const transportServer = new TransportServer(transportListener, dispatch); + module.addLogger((...args) => transportServer.broadcast({ fn: 'emit', args: ['log', ...args] })); + transportServer.start(); +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RhcnRfbm9kZV9tb2R1bGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvd29ya2VyL25vZGUvc3RhcnRfbm9kZV9tb2R1bGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzVDLE9BQU8sRUFBRSxZQUFZLEVBQWUsZUFBZSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFHdEYsSUFBSSxDQUFDLFVBQVUsRUFBRTtJQUNmLE1BQU0sSUFBSSxLQUFLLENBQUMsZUFBZSxDQUFDLENBQUM7Q0FDbEM7QUFFRDs7O0dBR0c7QUFDSCxNQUFNLFVBQVUsZUFBZSxDQUFDLE1BQWtCO0lBQ2hELE1BQU0sUUFBUSxHQUFHLEtBQUssRUFBRSxFQUFFLEVBQUUsRUFBRSxJQUFJLEVBQWUsRUFBRSxFQUFFO1FBQ25ELElBQUksRUFBRSxLQUFLLG1CQUFtQixFQUFFO1lBQzlCLGVBQWUsQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUN2QixPQUFPO1NBQ1I7UUFDRCxJQUFJLENBQUUsTUFBYyxDQUFDLEVBQUUsQ0FBQyxFQUFFO1lBQ3hCLE1BQU0sSUFBSSxLQUFLLENBQUMsdUNBQXVDLEVBQUUsRUFBRSxDQUFDLENBQUM7U0FDOUQ7UUFDRCxPQUFPLE1BQU8sTUFBYyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUM7SUFDNUMsQ0FBQyxDQUFDO0lBQ0YsTUFBTSxpQkFBaUIsR0FBRyxJQUFJLFlBQVksRUFBRSxDQUFDO0lBQzdDLE1BQU0sZUFBZSxHQUFHLElBQUksZUFBZSxDQUFjLGlCQUFpQixFQUFFLFFBQVEsQ0FBQyxDQUFDO0lBQ3RGLE1BQU0sQ0FBQyxTQUFTLENBQUMsQ0FBQyxHQUFHLElBQVcsRUFBRSxFQUFFLENBQUMsZUFBZSxDQUFDLFNBQVMsQ0FBQyxFQUFFLEVBQUUsRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFLENBQUMsS0FBSyxFQUFFLEdBQUcsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDeEcsZUFBZSxDQUFDLEtBQUssRUFBRSxDQUFDO0FBQzFCLENBQUMifQ== \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/worker/wasm_worker.d.ts b/circuits/ts/.yalc/@aztec/wasm/dest/worker/wasm_worker.d.ts new file mode 100644 index 00000000000..5796d84ec9e --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/worker/wasm_worker.d.ts @@ -0,0 +1,9 @@ +import { Proxify } from '../transport/index.js'; +import { WasmModule } from '../wasm/wasm_module.js'; +/** + * Represents either a WASM web worker, or node.js worker. + */ +export type WasmWorker = Proxify & { + destroyWorker(): void; +}; +//# sourceMappingURL=wasm_worker.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/worker/wasm_worker.d.ts.map b/circuits/ts/.yalc/@aztec/wasm/dest/worker/wasm_worker.d.ts.map new file mode 100644 index 00000000000..111acb92bbc --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/worker/wasm_worker.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"wasm_worker.d.ts","sourceRoot":"","sources":["../../src/worker/wasm_worker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEpD;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,GAAG;IAAE,aAAa,IAAI,IAAI,CAAA;CAAE,CAAC"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/worker/wasm_worker.js b/circuits/ts/.yalc/@aztec/wasm/dest/worker/wasm_worker.js new file mode 100644 index 00000000000..a886d8ce72e --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/worker/wasm_worker.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2FzbV93b3JrZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvd29ya2VyL3dhc21fd29ya2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiIifQ== \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/worker/worker_pool.d.ts b/circuits/ts/.yalc/@aztec/wasm/dest/worker/worker_pool.d.ts new file mode 100644 index 00000000000..62f2d879877 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/worker/worker_pool.d.ts @@ -0,0 +1,40 @@ +import { WasmWorker } from './wasm_worker.js'; +/** + * Type of a worker factory. + * Used to customize WorkerPool worker construction. + */ +export type CreateWorker = (name: string, minMem: number, maxMem: number) => WasmWorker; +/** + * Allocates a pool of WasmWorker's. + * Worker 0 is allocated MAX_PAGES memory pages. This is because worker 0 will need to hold the proving key + * (i.e. Has state), whereas the others are pure compute (they hold a little crs state). + */ +export declare class WorkerPool { + /** + * The maximum number of memory pages to be used by the webassembly. + */ + static MAX_PAGES: number; + /** + * The workers in the pool. + */ + private workers; + /** + * Create an instance and initialize the workers. + * @param createWorker - Worker factory. + * @param poolSize - Pool size. + * @returns An initialized WorkerPool. + */ + static new(createWorker: CreateWorker, poolSize: number): Promise; + /** + * Initialize the workers. + * @param createWorker - Worker factory(). + * @param poolSize - Pool size. + * @param maxMem - Max memory pages. + */ + init(createWorker: CreateWorker, poolSize: number, maxMem?: number): Promise; + /** + * Tell all workers in the pool to stop processing. + */ + destroy(): Promise; +} +//# sourceMappingURL=worker_pool.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/worker/worker_pool.d.ts.map b/circuits/ts/.yalc/@aztec/wasm/dest/worker/worker_pool.d.ts.map new file mode 100644 index 00000000000..118733d8c5c --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/worker/worker_pool.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"worker_pool.d.ts","sourceRoot":"","sources":["../../src/worker/worker_pool.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAI9C;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,UAAU,CAAC;AACxF;;;;GAIG;AACH,qBAAa,UAAU;IAYrB;;OAEG;IACH,OAAc,SAAS,SAAQ;IAC/B;;OAEG;IACH,OAAO,CAAC,OAAO,CAAoB;IAEnC;;;;;OAKG;WACU,GAAG,CAAC,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM;IAM7D;;;;;OAKG;IACU,IAAI,CAAC,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,SAAuB;IAY7F;;OAEG;IACU,OAAO;CAGrB"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/worker/worker_pool.js b/circuits/ts/.yalc/@aztec/wasm/dest/worker/worker_pool.js new file mode 100644 index 00000000000..bddeb77620d --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/dest/worker/worker_pool.js @@ -0,0 +1,62 @@ +import { createDebugLogger } from '@aztec/log'; +const debug = createDebugLogger('bb:worker_pool'); +/** + * Allocates a pool of WasmWorker's. + * Worker 0 is allocated MAX_PAGES memory pages. This is because worker 0 will need to hold the proving key + * (i.e. Has state), whereas the others are pure compute (they hold a little crs state). + */ +export class WorkerPool { + constructor() { + /** + * The workers in the pool. + */ + this.workers = []; + } + /** + * Create an instance and initialize the workers. + * @param createWorker - Worker factory. + * @param poolSize - Pool size. + * @returns An initialized WorkerPool. + */ + static async new(createWorker, poolSize) { + const pool = new WorkerPool(); + await pool.init(createWorker, poolSize); + return pool; + } + /** + * Initialize the workers. + * @param createWorker - Worker factory(). + * @param poolSize - Pool size. + * @param maxMem - Max memory pages. + */ + async init(createWorker, poolSize, maxMem = WorkerPool.MAX_PAGES) { + debug(`creating ${poolSize} workers...`); + const start = new Date().getTime(); + this.workers = await Promise.all(Array(poolSize) + .fill(0) + .map((_, i) => createWorker(`${i}`, i === 0 ? Math.min(WorkerPool.MAX_PAGES, maxMem) : 768, maxMem))); + debug(`created workers: ${new Date().getTime() - start}ms`); + } + /** + * Tell all workers in the pool to stop processing. + */ + async destroy() { + await Promise.all(this.workers.map(w => w.destroyWorker())); + } +} +// TODO(AD): Revisit what this means in aztec 3 context +// -- +// Introduction of low mem prover work (polynomial cache) may actually increase mem usage when the backing store isn't +// enabled. We were seeing intermittent failings related to memory in production for some users when limiting to +// 6660 (416MB). It would be nice to understand why this is (the non determinism and/or the increased mem usage). +// For now, increasing mem usage to 512MB. This maybe preferable to backing out the low mem work, but +// ironically may break the chance of us using it in mobile. +// We *could* enable the low memory backing store, but this needs a little bit of work to actually +// read/write from indexeddb, performance testing, and actual further memory load testing. +// At this point it's hard to know what our memory savings would be relative to just fully reverting the LMP. +// public static MAX_PAGES = 6660; +/** + * The maximum number of memory pages to be used by the webassembly. + */ +WorkerPool.MAX_PAGES = 8192; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid29ya2VyX3Bvb2wuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvd29ya2VyL3dvcmtlcl9wb29sLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLFlBQVksQ0FBQztBQUcvQyxNQUFNLEtBQUssR0FBRyxpQkFBaUIsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO0FBT2xEOzs7O0dBSUc7QUFDSCxNQUFNLE9BQU8sVUFBVTtJQUF2QjtRQWdCRTs7V0FFRztRQUNLLFlBQU8sR0FBaUIsRUFBRSxDQUFDO0lBc0NyQyxDQUFDO0lBcENDOzs7OztPQUtHO0lBQ0gsTUFBTSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsWUFBMEIsRUFBRSxRQUFnQjtRQUMzRCxNQUFNLElBQUksR0FBRyxJQUFJLFVBQVUsRUFBRSxDQUFDO1FBQzlCLE1BQU0sSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLEVBQUUsUUFBUSxDQUFDLENBQUM7UUFDeEMsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSSxLQUFLLENBQUMsSUFBSSxDQUFDLFlBQTBCLEVBQUUsUUFBZ0IsRUFBRSxNQUFNLEdBQUcsVUFBVSxDQUFDLFNBQVM7UUFDM0YsS0FBSyxDQUFDLFlBQVksUUFBUSxhQUFhLENBQUMsQ0FBQztRQUN6QyxNQUFNLEtBQUssR0FBRyxJQUFJLElBQUksRUFBRSxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ25DLElBQUksQ0FBQyxPQUFPLEdBQUcsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUM5QixLQUFLLENBQUMsUUFBUSxDQUFDO2FBQ1osSUFBSSxDQUFDLENBQUMsQ0FBQzthQUNQLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLFlBQVksQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLFNBQVMsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQ3ZHLENBQUM7UUFFRixLQUFLLENBQUMsb0JBQW9CLElBQUksSUFBSSxFQUFFLENBQUMsT0FBTyxFQUFFLEdBQUcsS0FBSyxJQUFJLENBQUMsQ0FBQztJQUM5RCxDQUFDO0lBRUQ7O09BRUc7SUFDSSxLQUFLLENBQUMsT0FBTztRQUNsQixNQUFNLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsYUFBYSxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQzlELENBQUM7O0FBdkRELHVEQUF1RDtBQUN2RCxLQUFLO0FBQ0wsc0hBQXNIO0FBQ3RILGdIQUFnSDtBQUNoSCxpSEFBaUg7QUFDakgscUdBQXFHO0FBQ3JHLDREQUE0RDtBQUM1RCxrR0FBa0c7QUFDbEcsMEZBQTBGO0FBQzFGLDZHQUE2RztBQUM3RyxrQ0FBa0M7QUFDbEM7O0dBRUc7QUFDVyxvQkFBUyxHQUFHLElBQUksQ0FBQyJ9 \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/package.json b/circuits/ts/.yalc/@aztec/wasm/package.json new file mode 100644 index 00000000000..46b6958376e --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/package.json @@ -0,0 +1,42 @@ +{ + "name": "@aztec/wasm", + "version": "0.0.0", + "type": "module", + "exports": "./dest/index.js", + "typedoc": { + "entryPoint": "./src/index.ts", + "displayName": "wasm", + "tsconfig": "./tsconfig.dest.json" + }, + "scripts": { + "build": "yarn clean && yarn formatting && tsc -b tsconfig.dest.json", + "build:dev": "tsc -b tsconfig.dest.json --watch", + "clean": "rm -rf ./dest .tsbuildinfo", + "fix-eslint": "run -T eslint --fix ./src", + "formatting": "run -T prettier --check ./src && run -T eslint --max-warnings 53 ./src", + "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --no-cache --passWithNoTests" + }, + "jest": { + "preset": "ts-jest/presets/default-esm", + "globals": { + "ts-jest": { + "useESM": true + } + }, + "moduleNameMapper": { + "^(\\.{1,2}/.*)\\.js$": "$1" + }, + "testRegex": "./src/.*\\.test\\.ts$", + "rootDir": "./src" + }, + "dependencies": { + "@aztec/log": "*", + "@types/leveldown": "^4.0.3", + "detect-node": "^2.1.0", + "leveldown": "^6.1.1", + "levelup": "^5.1.1", + "memdown": "^6.1.1", + "tslib": "^2.4.0" + }, + "yalcSig": "49e137843b2fae07ab3c4df8d2229740" +} diff --git a/circuits/ts/.yalc/@aztec/wasm/src/index.ts b/circuits/ts/.yalc/@aztec/wasm/src/index.ts new file mode 100644 index 00000000000..7b34a6e732f --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/src/index.ts @@ -0,0 +1,7 @@ +export { WebDataStore } from './worker/browser/index.js'; +export { NodeDataStore } from './worker/node/index.js'; +export { WasmWorker, WorkerPool } from './worker/index.js'; +export { WasmModule } from './wasm/index.js'; +export { AsyncCallState, AsyncFnState } from './wasm/index.js'; +export { DispatchMsg, WorkerListener, TransportServer, NodeListener } from './transport/index.js'; +export { Transfer, isTransferDescriptor } from './transport/interface/transferable.js'; diff --git a/circuits/ts/.yalc/@aztec/wasm/src/memory_fifo.ts b/circuits/ts/.yalc/@aztec/wasm/src/memory_fifo.ts new file mode 100644 index 00000000000..03dc63d93ee --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/src/memory_fifo.ts @@ -0,0 +1,104 @@ +// TODO should come from a dependency +/** + * A simple fifo queue. It can grow unbounded. It can have multiple producers and consumers. + * Putting an item onto the queue always succeeds, unless either end() or cancel() has been called in which case + * the item being pushed is simply discarded. + */ +export class MemoryFifo { + private waiting: ((item: T | null) => void)[] = []; + private items: T[] = []; + private flushing = false; + + /** + * Length of queue. + * @returns integer. + */ + public length() { + return this.items.length; + } + + /** + * Returns next item within the queue, or blocks until and item has been put into the queue. + * If given a timeout, the promise will reject if no item is received after `timeout` seconds. + * If the queue is flushing, `null` is returned. + * @param timeout - In seconds. + * @returns Promise of result. + */ + public get(timeout?: number): Promise { + if (this.items.length) { + return Promise.resolve(this.items.shift()!); + } + + if (this.items.length === 0 && this.flushing) { + return Promise.resolve(null); + } + + return new Promise((resolve, reject) => { + this.waiting.push(resolve); + + if (timeout) { + setTimeout(() => { + const index = this.waiting.findIndex(r => r === resolve); + if (index > -1) { + this.waiting.splice(index, 1); + const err = new Error('Timeout getting item from queue.'); + reject(err); + } + }, timeout * 1000); + } + }); + } + + /** + * Put an item onto back of the queue. + * @param item - The item to enqueue. + */ + public put(item: T) { + if (this.flushing) { + return; + } else if (this.waiting.length) { + this.waiting.shift()!(item); + } else { + this.items.push(item); + } + } + + /** + * Once ended, no further items are added to queue. Consumers will consume remaining items within the queue. + * The queue is not reusable after calling `end()`. + * Any consumers waiting for an item receive null. + */ + public end() { + this.flushing = true; + this.waiting.forEach(resolve => resolve(null)); + } + + /** + * Once cancelled, all items are discarded from the queue, and no further items are added to the queue. + * The queue is not reusable after calling `cancel()`. + * Any consumers waiting for an item receive null. + */ + public cancel() { + this.flushing = true; + this.items = []; + this.waiting.forEach(resolve => resolve(null)); + } + + /** + * Helper method that can be used to continously consume and process items on the queue. + * @param handler - The item handler function. + */ + public async process(handler: (item: T) => Promise) { + try { + while (true) { + const item = await this.get(); + if (item === null) { + break; + } + await handler(item); + } + } catch (err) { + console.error('Queue handler exception:', err); + } + } +} diff --git a/circuits/ts/.yalc/@aztec/wasm/src/test/gcd.wasm b/circuits/ts/.yalc/@aztec/wasm/src/test/gcd.wasm new file mode 100644 index 0000000000000000000000000000000000000000..19a859c306c3acf6de25eef3ea26711d05e783bb GIT binary patch literal 76 zcmWN@!3lsc5Cp*8&Evo`JzRW>MWmF7f-ga^fNNdnHQ3*q0B9V_WEK%-EZ1=Y)5eud Xb@f0+uxX~39t { + this.port.postMessage(msg, transfer); + return Promise.resolve(); + } + + /** + * Add a message handler. + * @param cb - The handler. + */ + registerHandler(cb: (msg: any) => any): void { + this.port.onmessage = event => cb(event.data); + } + + /** + * Close this message port. + */ + close() { + void this.send(undefined); + this.port.onmessage = null; + this.port.close(); + } +} diff --git a/circuits/ts/.yalc/@aztec/wasm/src/transport/browser/shared_worker_connector.ts b/circuits/ts/.yalc/@aztec/wasm/src/transport/browser/shared_worker_connector.ts new file mode 100644 index 00000000000..d6167961760 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/src/transport/browser/shared_worker_connector.ts @@ -0,0 +1,21 @@ +import { Connector } from '../interface/connector.js'; +import { MessagePortSocket } from './message_port_socket.js'; + +/** + * Connector implementation which wraps a SharedWorker. + */ +export class SharedWorkerConnector implements Connector { + /** + * Create a SharedWorkerConnector. + * @param worker - A shared worker. + */ + constructor(private worker: SharedWorker) {} + + /** + * Create a Socket implementation with our mesage port. + * @returns The socket. + */ + createSocket() { + return Promise.resolve(new MessagePortSocket(this.worker.port)); + } +} diff --git a/circuits/ts/.yalc/@aztec/wasm/src/transport/browser/shared_worker_listener.ts b/circuits/ts/.yalc/@aztec/wasm/src/transport/browser/shared_worker_listener.ts new file mode 100644 index 00000000000..cafd280e6e6 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/src/transport/browser/shared_worker_listener.ts @@ -0,0 +1,52 @@ +import EventEmitter from 'events'; +import { Listener } from '../interface/listener.js'; +import { MessagePortSocket } from './message_port_socket.js'; + +/** + * See https://developer.mozilla.org/en-US/docs/Web/API/SharedWorkerGlobalScope. + */ +declare interface SharedWorkerGlobalScope { + /** + * Fired on shared workers when a new client connects. + */ + onconnect: any; +} + +/** + * Listens for connections to a shared worker. + */ +export class SharedWorkerListener extends EventEmitter implements Listener { + /** + * + * @param worker + */ + constructor(private worker: SharedWorkerGlobalScope) { + super(); + } + + /** + * + */ + open() { + this.worker.onconnect = this.handleMessageEvent; + } + + /** + * + */ + close() { + this.worker.onconnect = () => {}; + } + + /** + * + * @param event + */ + private handleMessageEvent = (event: MessageEvent) => { + const [port] = event.ports; + if (!port) { + return; + } + this.emit('new_socket', new MessagePortSocket(port)); + }; +} diff --git a/circuits/ts/.yalc/@aztec/wasm/src/transport/browser/worker_connector.ts b/circuits/ts/.yalc/@aztec/wasm/src/transport/browser/worker_connector.ts new file mode 100644 index 00000000000..fbfc7efd22e --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/src/transport/browser/worker_connector.ts @@ -0,0 +1,22 @@ +import { Connector } from '../interface/connector.js'; +import { MessagePortSocket } from './message_port_socket.js'; + +/** + * + */ +export class WorkerConnector implements Connector { + /** + * + * @param worker + */ + constructor(private worker: Worker) {} + + /** + * + */ + createSocket() { + const channel = new MessageChannel(); + this.worker.postMessage('', [channel.port2]); + return Promise.resolve(new MessagePortSocket(channel.port1)); + } +} diff --git a/circuits/ts/.yalc/@aztec/wasm/src/transport/browser/worker_listener.ts b/circuits/ts/.yalc/@aztec/wasm/src/transport/browser/worker_listener.ts new file mode 100644 index 00000000000..201b3a68573 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/src/transport/browser/worker_listener.ts @@ -0,0 +1,52 @@ +import EventEmitter from 'events'; +import { Listener } from '../interface/listener.js'; +import { MessagePortSocket } from './message_port_socket.js'; + +/** + * + */ +declare interface DedicatedWorkerGlobalScope { + /** + * + */ + onmessage: any; +} + +/** + * + */ +export class WorkerListener extends EventEmitter implements Listener { + /** + * + * @param worker + */ + constructor(private worker: DedicatedWorkerGlobalScope) { + super(); + } + + /** + * + */ + open() { + this.worker.onmessage = this.handleMessageEvent; + } + + /** + * + */ + close() { + this.worker.onmessage = () => {}; + } + + /** + * + * @param event + */ + private handleMessageEvent = (event: MessageEvent) => { + const [port] = event.ports; + if (!port) { + return; + } + this.emit('new_socket', new MessagePortSocket(port)); + }; +} diff --git a/circuits/ts/.yalc/@aztec/wasm/src/transport/dispatch/create_dispatch_fn.ts b/circuits/ts/.yalc/@aztec/wasm/src/transport/dispatch/create_dispatch_fn.ts new file mode 100644 index 00000000000..6e23e25a25f --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/src/transport/dispatch/create_dispatch_fn.ts @@ -0,0 +1,24 @@ +/** + * + */ +export interface DispatchMsg { + /** + * + */ + fn: string; + /** + * + */ + args: any[]; +} + +/** + * + */ +export function createDispatchFn(targetFn: () => any, debug = console.error) { + return async ({ fn, args }: DispatchMsg) => { + const target = targetFn(); + debug(`dispatching to ${target}: ${fn}`, args); + return await target[fn](...args); + }; +} diff --git a/circuits/ts/.yalc/@aztec/wasm/src/transport/dispatch/create_dispatch_proxy.ts b/circuits/ts/.yalc/@aztec/wasm/src/transport/dispatch/create_dispatch_proxy.ts new file mode 100644 index 00000000000..e9538448d3d --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/src/transport/dispatch/create_dispatch_proxy.ts @@ -0,0 +1,88 @@ +import { DispatchMsg } from './create_dispatch_fn.js'; +import { TransportClient } from '../transport_client.js'; +import { EventEmitter } from 'events'; +import { isTransferDescriptor, TransferDescriptor } from '../interface/transferable.js'; + +type FilterOutAttributes = { + [Key in keyof Base]: Base[Key] extends (...args: any) => any ? Base[Key] : never; +}; + +type PromisifyFunction any> = (...args: Parameters) => Promise>; + +type Promisify any }> = { + [Key in keyof Base]: ReturnType extends Promise ? Base[Key] : PromisifyFunction; +}; + +/** + * Unpack transfer types + */ +type TransferTypes = { + [Index in keyof Tuple]: Tuple[Index] | (Tuple[Index] extends Transferable ? TransferDescriptor : never); +}; + +/** + * Annoying: https://github.com/microsoft/TypeScript/issues/29919 + * There's a bug that means we can't map over the tuple or function parameter types to make them transferrable, if + * we use the Parameters builtin, and then try to map. + * So instead we inline the Parameters builtin and apply the TransferTypes to the parameters within the inline. + * Once the above is fixed we could in theory just do: + * + * type MakeFunctionTransferrable any> = ( + * ...args: TransferTypes> + * ) => ReturnType;. + */ +type MakeFunctionTransferrable any> = ( + ...args: TFunction extends (...args: infer P) => any ? TransferTypes

: never +) => ReturnType; + +type Transferrable any }> = { + [Key in keyof Base]: MakeFunctionTransferrable; +}; + +export type Proxify = Promisify>>; + +export function createDispatchProxyFromFn( + class_: { new (...args: any[]): T }, + requestFn: (fn: string) => (...args: any[]) => Promise, +): Proxify { + const proxy: any = class_.prototype instanceof EventEmitter ? new EventEmitter() : {}; + for (const fn of Object.getOwnPropertyNames(class_.prototype)) { + if (fn === 'constructor') { + continue; + } + proxy[fn] = requestFn(fn); + } + return proxy; +} + +/** + * Create a proxy object of our class T that uses transportClient + * @param class_ - Our class T. + * @param transportClient - The transport infrastructure. + * @returns A proxy over T. + */ +export function createDispatchProxy( + class_: { new (...args: any[]): T }, + transportClient: TransportClient, +): Proxify { + // Create a proxy of class_ that passes along methods over our transportClient + const proxy = createDispatchProxyFromFn(class_, (fn: string) => (...args: any[]) => { + // Pass our proxied function name and arguments over our transport client + const transfer: Transferable[] = args.reduce( + (acc, a) => (isTransferDescriptor(a) ? [...acc, ...a.transferables] : acc), + [] as Transferable[], + ); + args = args.map(a => (isTransferDescriptor(a) ? a.send : a)); + return transportClient.request({ fn, args }, transfer); + }); + if (proxy instanceof EventEmitter) { + // Handle proxied 'emit' calls if our proxy object is an EventEmitter + transportClient.on('event_msg', ({ fn, args }) => { + if (fn === 'emit') { + const [eventName, ...restArgs] = args; + proxy.emit(eventName, ...restArgs); + } + }); + } + return proxy; +} diff --git a/circuits/ts/.yalc/@aztec/wasm/src/transport/dispatch/messages.ts b/circuits/ts/.yalc/@aztec/wasm/src/transport/dispatch/messages.ts new file mode 100644 index 00000000000..49704dbde84 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/src/transport/dispatch/messages.ts @@ -0,0 +1,51 @@ +/** + * Represents a transport bus request. + */ +export interface RequestMessage { + /** + * The message ID. + */ + msgId: number; + /** + * The data. + */ + payload: Payload; +} + +/** + * Represents a transport bus response. + */ +export interface ResponseMessage { + /** + * The message ID. + */ + msgId: number; + /** + * The data. + */ + payload?: Payload; + /** + * The error, if any. + */ + error?: string; +} + +/** + * A message stemming from an event. + */ +export interface EventMessage { + /** + * The event data. + */ + payload: Payload; +} + +/** + * Is this an event message? + * @returns If the msgId was blank. + */ +export function isEventMessage( + msg: ResponseMessage | EventMessage, +): msg is EventMessage { + return (msg as ResponseMessage).msgId === undefined; +} diff --git a/circuits/ts/.yalc/@aztec/wasm/src/transport/index.ts b/circuits/ts/.yalc/@aztec/wasm/src/transport/index.ts new file mode 100644 index 00000000000..1ea1f8c30cf --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/src/transport/index.ts @@ -0,0 +1,11 @@ +export * from './dispatch/create_dispatch_fn.js'; +export * from './dispatch/create_dispatch_proxy.js'; +export * from './dispatch/messages.js'; +export * from './interface/connector.js'; +export * from './interface/listener.js'; +export * from './interface/socket.js'; +export * from './interface/transferable.js'; +export * from './transport_client.js'; +export * from './transport_server.js'; +export * from './browser/index.js'; +export * from './node/index.js'; diff --git a/circuits/ts/.yalc/@aztec/wasm/src/transport/interface/connector.ts b/circuits/ts/.yalc/@aztec/wasm/src/transport/interface/connector.ts new file mode 100644 index 00000000000..9d72f6574f7 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/src/transport/interface/connector.ts @@ -0,0 +1,8 @@ +import { Socket } from './socket.js'; + +/** + * Opens a socket with corresponding TransportListener. + */ +export interface Connector { + createSocket(): Promise; +} diff --git a/circuits/ts/.yalc/@aztec/wasm/src/transport/interface/listener.ts b/circuits/ts/.yalc/@aztec/wasm/src/transport/interface/listener.ts new file mode 100644 index 00000000000..b6e533570a7 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/src/transport/interface/listener.ts @@ -0,0 +1,14 @@ +import EventEmitter from 'events'; +import { Socket } from './socket.js'; + +/** + * Once opened, an implementation of a TransportListener will emit `new_socket` events as new clients connect. + * Possible implementations could include MessageChannels or WebSockets. + */ +export interface Listener extends EventEmitter { + open(): void; + + close(): void; + + on(name: 'new_socket', cb: (client: Socket) => void): this; +} diff --git a/circuits/ts/.yalc/@aztec/wasm/src/transport/interface/socket.ts b/circuits/ts/.yalc/@aztec/wasm/src/transport/interface/socket.ts new file mode 100644 index 00000000000..6da7ca436ed --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/src/transport/interface/socket.ts @@ -0,0 +1,12 @@ +/** + * Represents one end of a socket connection. + * A message sent via `send` will be handled by the corresponding Socket's handler function at the other end. + * Implementations could use e.g. MessagePorts for communication between browser workers, + * or WebSockets for communication between processes. + * If `registerHandler` callback receives `undefined` that signals the other end closed. + */ +export interface Socket { + send(msg: any, transfer?: Transferable[]): Promise; + registerHandler(cb: (msg: any) => any): void; + close(): void; +} diff --git a/circuits/ts/.yalc/@aztec/wasm/src/transport/interface/transferable.ts b/circuits/ts/.yalc/@aztec/wasm/src/transport/interface/transferable.ts new file mode 100644 index 00000000000..3ce8c59b320 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/src/transport/interface/transferable.ts @@ -0,0 +1,92 @@ +const $transferable = Symbol('thread.transferable'); + +/** + * A descriptor representing a payload with transferable components. + * These components will have ownership transfered when published on an event bus. + */ +export interface TransferDescriptor { + /** + * Marked as transferable. + */ + [$transferable]: true; + /** + * The payload with the transferable objects. + */ + send: T; + /** + * The objects to transfer. + */ + transferables: Transferable[]; +} + +/** + * + */ +function isTransferable(thing: any): thing is Transferable { + if (!thing || typeof thing !== 'object') return false; + // Don't check too thoroughly, since the list of transferable things in JS might grow over time + return true; +} + +/** + * + */ +export function isTransferDescriptor(thing: any): thing is TransferDescriptor { + return thing && typeof thing === 'object' && thing[$transferable]; +} + +/** + * Mark a transferable object as such, so it will no be serialized and + * deserialized on messaging with the main thread, but to transfer + * ownership of it to the receiving thread. + * + * Only works with array buffers, message ports and few more special + * types of objects, but it's much faster than serializing and + * deserializing them. + * + * Note: + * The transferable object cannot be accessed by this thread again + * unless the receiving thread transfers it back again! + * + * @param transferable - Array buffer, message port or similar. + * @see https://developers.google.com/web/updates/2011/12/Transferable-Objects-Lightning-Fast + */ +export function Transfer(transferable: Transferable): TransferDescriptor; + +/** + * Mark transferable objects within an arbitrary object or array as + * being a transferable object. They will then not be serialized + * and deserialized on messaging with the main thread, but ownership + * of them will be tranferred to the receiving thread. + * + * Only array buffers, message ports and few more special types of + * objects can be transferred, but it's much faster than serializing and + * deserializing them. + * + * Note: + * The transferable object cannot be accessed by this thread again + * unless the receiving thread transfers it back again! + * + * @param transferable - Array buffer, message port or similar. + * @see https://developers.google.com/web/updates/2011/12/Transferable-Objects-Lightning-Fast + */ +export function Transfer(payload: T, transferables: Transferable[]): TransferDescriptor; + +/** + * Create a transfer descriptor, marking these as transferable. + * @param payload - The payload. + * @param transferables - The transferable objects. + * @returns The descriptor. + */ +export function Transfer(payload: T, transferables?: Transferable[]): TransferDescriptor { + if (!transferables) { + if (!isTransferable(payload)) throw Error(); + transferables = [payload]; + } + + return { + [$transferable]: true, + send: payload, + transferables, + }; +} diff --git a/circuits/ts/.yalc/@aztec/wasm/src/transport/node/index.ts b/circuits/ts/.yalc/@aztec/wasm/src/transport/node/index.ts new file mode 100644 index 00000000000..cf87befc85e --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/src/transport/node/index.ts @@ -0,0 +1,2 @@ +export * from './node_connector.js'; +export * from './node_listener.js'; diff --git a/circuits/ts/.yalc/@aztec/wasm/src/transport/node/node_connector.ts b/circuits/ts/.yalc/@aztec/wasm/src/transport/node/node_connector.ts new file mode 100644 index 00000000000..bf74c2a5d72 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/src/transport/node/node_connector.ts @@ -0,0 +1,18 @@ +import { Worker } from 'worker_threads'; +import { Connector } from '../interface/connector.js'; +import { NodeConnectorSocket } from './node_connector_socket.js'; + +/** + * Creates sockets backed by a Node worker. + */ +export class NodeConnector implements Connector { + constructor(private worker: Worker) {} + + /** + * Creates a socket backed by a node worker. + * @returns The socket. + */ + createSocket() { + return Promise.resolve(new NodeConnectorSocket(this.worker)); + } +} diff --git a/circuits/ts/.yalc/@aztec/wasm/src/transport/node/node_connector_socket.ts b/circuits/ts/.yalc/@aztec/wasm/src/transport/node/node_connector_socket.ts new file mode 100644 index 00000000000..39b1b2e04b4 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/src/transport/node/node_connector_socket.ts @@ -0,0 +1,36 @@ +import { TransferListItem, Worker } from 'worker_threads'; +import { Socket } from '../interface/socket.js'; + +/** + * A socket implementation using a Node worker. + */ +export class NodeConnectorSocket implements Socket { + constructor(private worker: Worker) {} + + /** + * Send a message. + * @param msg - The message. + * @param transfer - Objects to transfer ownership of. + * @returns A void promise. + */ + send(msg: any, transfer: Transferable[] = []): Promise { + this.worker.postMessage(msg, transfer as TransferListItem[]); + return Promise.resolve(); + } + + /** + * Register a message handler. + * @param cb - The handler function. + */ + registerHandler(cb: (msg: any) => any): void { + this.worker.on('message', cb); + } + + /** + * Remove all listeners from our worker. + */ + close() { + void this.send(undefined); + this.worker.removeAllListeners(); + } +} diff --git a/circuits/ts/.yalc/@aztec/wasm/src/transport/node/node_listener.ts b/circuits/ts/.yalc/@aztec/wasm/src/transport/node/node_listener.ts new file mode 100644 index 00000000000..92c753410fb --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/src/transport/node/node_listener.ts @@ -0,0 +1,25 @@ +import { parentPort } from 'worker_threads'; +import EventEmitter from 'events'; +import { Listener } from '../interface/listener.js'; +import { NodeListenerSocket } from './node_listener_socket.js'; + +/** + * A socket listener that works with Node. + */ +export class NodeListener extends EventEmitter implements Listener { + constructor() { + super(); + } + + /** + * Open the listener. + */ + open() { + this.emit('new_socket', new NodeListenerSocket(parentPort as any)); + } + + /** + * Close the listener. + */ + close() {} +} diff --git a/circuits/ts/.yalc/@aztec/wasm/src/transport/node/node_listener_socket.ts b/circuits/ts/.yalc/@aztec/wasm/src/transport/node/node_listener_socket.ts new file mode 100644 index 00000000000..d492d45c602 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/src/transport/node/node_listener_socket.ts @@ -0,0 +1,37 @@ +import { MessagePort, TransferListItem } from 'worker_threads'; +import { Socket } from '../interface/socket.js'; + +/** + * An implementation of a TransportSocket using MessagePorts. + */ +export class NodeListenerSocket implements Socket { + constructor(private port: MessagePort) {} + + /** + * Send a message over this port. + * @param msg - The message. + * @param transfer - Transferable objects. + * @returns A void promise. + */ + send(msg: any, transfer: Transferable[] = []): Promise { + this.port.postMessage(msg, transfer as TransferListItem[]); + return Promise.resolve(); + } + + /** + * Add a handler to this port. + * @param cb - The handler function. + */ + registerHandler(cb: (msg: any) => any): void { + this.port.on('message', cb); + } + + /** + * Close this socket. + */ + close() { + void this.send(undefined); + this.port.removeAllListeners(); + this.port.close(); + } +} diff --git a/circuits/ts/.yalc/@aztec/wasm/src/transport/transport_client.ts b/circuits/ts/.yalc/@aztec/wasm/src/transport/transport_client.ts new file mode 100644 index 00000000000..5577d7a5ed5 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/src/transport/transport_client.ts @@ -0,0 +1,106 @@ +import { createDebugLogger } from '@aztec/log'; +import EventEmitter from 'events'; +import { EventMessage, isEventMessage, ResponseMessage } from './dispatch/messages.js'; +import { Connector } from './interface/connector.js'; +import { Socket } from './interface/socket.js'; + +const debug = createDebugLogger('aztec:transport_client'); + +/** + * A pending request. + */ +interface PendingRequest { + /** + * The message ID. + */ + msgId: number; + resolve(data: any): void; + reject(error: Error): void; +} + +/** + * Augments the TransportClient class with more precise EventEmitter types. + */ +export interface TransportClient extends EventEmitter { + on(name: 'event_msg', handler: (payload: Payload) => void): this; + emit(name: 'event_msg', payload: Payload): boolean; +} + +/** + * A TransportClient provides a request/response and event api to a corresponding TransportServer. + * If `broadcast` is called on TransportServer, TransportClients will emit an `event_msg`. + * The `request` method will block until a response is returned from the TransportServer's dispatch function. + * Request multiplexing is supported. + */ +export class TransportClient extends EventEmitter { + private msgId = 0; + private pendingRequests: PendingRequest[] = []; + private socket?: Socket; + + constructor(private transportConnect: Connector) { + super(); + } + + /** + * Create and register our socket using our Connector. + */ + async open() { + this.socket = await this.transportConnect.createSocket(); + this.socket.registerHandler(msg => this.handleSocketMessage(msg)); + } + + /** + * Close this and stop listening for messages. + */ + close() { + this.socket?.close(); + this.socket = undefined; + this.removeAllListeners(); + } + + /** + * Queue a request. + * @param payload - The request payload. + * @param transfer - Objects to transfer ownership of. + * @returns A promise of the query result. + */ + request(payload: Payload, transfer?: Transferable[]) { + if (!this.socket) { + throw new Error('Socket not open.'); + } + const msgId = this.msgId++; + const msg = { msgId, payload }; + debug(`->`, msg); + return new Promise((resolve, reject) => { + this.pendingRequests.push({ resolve, reject, msgId }); + this.socket!.send(msg, transfer).catch(reject); + }); + } + + /** + * Handle an incoming socket message. + * @param msg - The message. + */ + private handleSocketMessage(msg: ResponseMessage | EventMessage | undefined) { + if (msg === undefined) { + // The remote socket closed. + this.close(); + return; + } + debug(`<-`, msg); + if (isEventMessage(msg)) { + this.emit('event_msg', msg.payload); + return; + } + const reqIndex = this.pendingRequests.findIndex(r => r.msgId === msg.msgId); + if (reqIndex === -1) { + return; + } + const [pending] = this.pendingRequests.splice(reqIndex, 1); + if (msg.error) { + pending.reject(new Error(msg.error)); + } else { + pending.resolve(msg.payload); + } + } +} diff --git a/circuits/ts/.yalc/@aztec/wasm/src/transport/transport_server.ts b/circuits/ts/.yalc/@aztec/wasm/src/transport/transport_server.ts new file mode 100644 index 00000000000..0cb5aecf7e2 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/src/transport/transport_server.ts @@ -0,0 +1,96 @@ +import { RequestMessage, ResponseMessage } from './dispatch/messages.js'; +import { Listener } from './interface/listener.js'; +import { Socket } from './interface/socket.js'; +import { isTransferDescriptor } from './interface/transferable.js'; + +/** + * Keeps track of clients, providing a broadcast, and request/response api with multiplexing. + */ +export class TransportServer { + private sockets: Socket[] = []; + + constructor(private listener: Listener, private msgHandlerFn: (msg: Payload) => Promise) {} + + /** + * Start accepting new connections. + */ + start() { + this.listener.on('new_socket', client => this.handleNewSocket(client)); + this.listener.open(); + } + + /** + * Stops accepting new connections. It doesn't close existing sockets. + * It's expected the clients will gracefully complete by closing their end, sending an `undefined` message. + */ + stop() { + this.listener.close(); + } + + /** + * Broadcast a message. + * @param msg - The message. + */ + async broadcast(msg: Payload) { + await Promise.all(this.sockets.map(s => s.send({ payload: msg }))); + } + + /** + * New socket registration. + * @param socket - The socket to register. + */ + private handleNewSocket(socket: Socket) { + socket.registerHandler(async msg => { + if (msg === undefined) { + // Client socket has closed. Remove it from the list of sockets. Call close on it for any cleanup. + const socketIndex = this.sockets.findIndex(s => s === socket); + const [closingSocket] = this.sockets.splice(socketIndex, 1); + closingSocket.close(); + return; + } + return await this.handleSocketMessage(socket, msg); + }); + this.sockets.push(socket); + } + + /** + * Detect the 'transferables' argument to our socket from our message + * handler return type. + * @param data - The return object. + * @returns - The data and the. + */ + private getPayloadAndTransfers(data: any): [any, Transferable[]] { + if (isTransferDescriptor(data)) { + // We treat PayloadWithTransfers specially so that we're able to + // attach transferables while keeping a simple return-type based usage + return [data.send, data.transferables]; + } + if (data instanceof Uint8Array) { + // We may want to devise a better solution to this. We maybe given a view over a non cloneable/transferrable + // ArrayBuffer (such as a view over wasm memory). In this case we want to take a copy, and then transfer it. + const respPayload = data instanceof Uint8Array && ArrayBuffer.isView(data) ? new Uint8Array(data) : data; + const transferables = data instanceof Uint8Array ? [respPayload.buffer] : []; + return [respPayload, transferables]; + } + return [data, []]; + } + /** + * Handles a socket message from a listener. + * @param socket - The socket. + * @param requestMessage - The message to handle. + * @returns The socket response. + */ + private async handleSocketMessage(socket: Socket, { msgId, payload }: RequestMessage) { + try { + const data = await this.msgHandlerFn(payload); + + const [respPayload, transferables] = this.getPayloadAndTransfers(data); + const rep: ResponseMessage = { msgId, payload: respPayload }; + + await socket.send(rep, transferables); + } catch (err: any) { + const rep: ResponseMessage = { msgId, error: err.stack }; + await socket.send(rep); + } + } +} diff --git a/circuits/ts/.yalc/@aztec/wasm/src/wasm/async_call_state.ts b/circuits/ts/.yalc/@aztec/wasm/src/wasm/async_call_state.ts new file mode 100644 index 00000000000..17554f4889d --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/src/wasm/async_call_state.ts @@ -0,0 +1,136 @@ +import { WasmModule } from './wasm_module.js'; + +/** + * The state of an asynchronous WASM function. + */ +export interface AsyncFnState { + /** + * Is this a contination? + */ + continuation: boolean; + /** + * A result, if one exists. + */ + result?: any; +} + +/** + * To enable asynchronous callbacks from wasm to js, we leverage asyncify. + * Https://kripken.github.io/blog/wasm/2019/07/16/asyncify.html. + * + * This class holds state and logic specific to handling async calls from wasm to js. + * A single instance of this class is instantiated as part of BarretenbergWasm. + * It allocates some memory for the asyncify stack data and initialises it. + * + * To make an async call into the wasm, just call `call` the same as in BarretenbergWasm, only it returns a promise. + * + * To make an async import that will be called from the wasm, wrap a function with the signature: + * my_func(state: AsyncFnState, ...args) + * with a call to `wrapImportFn`. + * The arguments are whatever the original call arguments were. The addition of AsyncFnState as the first argument + * allows for the detection of wether the function is continuing after the the async call has completed. + * If `state.continuation` is false, the function should start its async operation and return the promise. + * If `state.continuation` is true, the function can get the result from `state.result` perform any finalisation, + * and return an (optional) value to the wasm. + */ +export class AsyncCallState { + private ASYNCIFY_DATA_SIZE = 16 * 1024; + private asyncifyDataAddr!: number; + private asyncPromise?: Promise; + private wasm!: WasmModule; + private state?: AsyncFnState; + private callExport!: (...args: any[]) => number; + + /** + * Initialize the call hooks with a WasmModule. + * @param wasm - The module. + */ + public init(wasm: WasmModule) { + this.wasm = wasm; + this.callExport = (name: string, ...args: any[]) => wasm.call(name, ...args); + // Allocate memory for asyncify stack data. + this.asyncifyDataAddr = this.callExport('bbmalloc', this.ASYNCIFY_DATA_SIZE); + // TODO: is this view construction problematic like in WasmModule? + const view = new Uint32Array(wasm.getRawMemory().buffer); + // First two integers of asyncify data, are the start and end of the stack region. + view[this.asyncifyDataAddr >> 2] = this.asyncifyDataAddr + 8; + view[(this.asyncifyDataAddr + 4) >> 2] = this.asyncifyDataAddr + this.ASYNCIFY_DATA_SIZE; + } + + /** + * Log a message. + * @param args - The message arguments. + */ + private debug(...args: any[]) { + this.wasm.getLogger()(...args); + } + + /** + * Free the data associated with async call states. + */ + public destroy() { + // Free call stack data. + this.callExport('bbfree', this.asyncifyDataAddr); + } + + /** + * We call the wasm function, that will in turn call back into js via callImport and set this.asyncPromise and + * enable the instrumented "record stack unwinding" code path. + * Once the stack has unwound out of the wasm call, we enter into a loop of resolving the promise set in the call + * to callImport, and calling back into the wasm to rewind the stack and continue execution. + * @param name - The function name. + * @param args - The function args. + * @returns The function result. + */ + public async call(name: string, ...args: any) { + if (this.state) { + throw new Error(`Can only handle one async call at a time: ${name}(${args})`); + } + this.state = { continuation: false }; + let result = this.callExport(name, ...args); + + while (this.asyncPromise) { + // Disable the instrumented "record stack unwinding" code path. + this.callExport('asyncify_stop_unwind'); + this.debug('stack unwound.'); + // Wait for the async work to complete. + this.state.result = await this.asyncPromise; + this.state.continuation = true; + this.debug('result set starting rewind.'); + // Enable "stack rewinding" code path. + this.callExport('asyncify_start_rewind', this.asyncifyDataAddr); + // Call function again to rebuild the stack, and continue where we left off. + result = this.callExport(name, ...args); + } + + // Cleanup + this.state = undefined; + + return result; + } + + /** + * Wrap a WASM import function. + * @param fn - The function. + * @returns A wrapped version with asyncify calls. + */ + public wrapImportFn(fn: (state: AsyncFnState, ...args: any[]) => any) { + return (...args: any[]) => { + if (!this.asyncPromise) { + // We are in the normal code path. Start the async fetch of data. + this.asyncPromise = fn(this.state!, ...args); + // Enable "record stack unwinding" code path and return. + this.callExport('asyncify_start_unwind', this.asyncifyDataAddr); + } else { + // We are in the stack rewind code path, called once the promise is resolved. + // Save the result data back to the wasm, disable stack rewind code paths, and return. + this.callExport('asyncify_stop_rewind'); + const result = fn(this.state!, ...args); + // Cleanup. + this.asyncPromise = undefined; + this.state = { continuation: false }; + return result; + } + }; + } +} diff --git a/circuits/ts/.yalc/@aztec/wasm/src/wasm/empty_wasi_sdk.ts b/circuits/ts/.yalc/@aztec/wasm/src/wasm/empty_wasi_sdk.ts new file mode 100644 index 00000000000..5d475696ca5 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/src/wasm/empty_wasi_sdk.ts @@ -0,0 +1,61 @@ +import { createDebugLogger } from '@aztec/log'; + +/** + * Dummy implementation of a necessary part of the wasi api: + * https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md + * We don't use these functions, but the environment expects them. + * TODO find a way to update off of wasi 12. + */ +/* eslint-disable camelcase */ +/* eslint-disable jsdoc/require-jsdoc */ +export const getEmptyWasiSdk = (debug = createDebugLogger('wasm:empty_wasi_sdk')) => ({ + clock_time_get() { + debug('clock_time_get'); + }, + environ_get() { + debug('environ_get'); + }, + environ_sizes_get() { + debug('environ_sizes_get'); + }, + fd_close() { + debug('fd_close'); + }, + fd_read() { + debug('fd_read'); + }, + fd_write() { + debug('fd_write'); + }, + fd_seek() { + debug('fd_seek'); + }, + fd_fdstat_get() { + debug('fd_fdstat_get'); + }, + fd_fdstat_set_flags() { + debug('fd_fdstat_set_flags'); + }, + fd_prestat_get() { + debug('fd_prestat_get'); + return 8; + }, + fd_prestat_dir_name() { + debug('fd_prestat_dir_name'); + return 28; + }, + path_open() { + debug('path_open'); + }, + path_filestat_get() { + debug('path_filestat_get'); + }, + proc_exit() { + debug('proc_exit'); + return 52; + }, + random_get() { + debug('random_get'); + return 1; + }, +}); diff --git a/circuits/ts/.yalc/@aztec/wasm/src/wasm/index.ts b/circuits/ts/.yalc/@aztec/wasm/src/wasm/index.ts new file mode 100644 index 00000000000..2fb5a8b9afe --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/src/wasm/index.ts @@ -0,0 +1,2 @@ +export { AsyncCallState, AsyncFnState } from './async_call_state.js'; +export { WasmModule } from './wasm_module.js'; diff --git a/circuits/ts/.yalc/@aztec/wasm/src/wasm/wasm_module.test.ts b/circuits/ts/.yalc/@aztec/wasm/src/wasm/wasm_module.test.ts new file mode 100644 index 00000000000..63c73a88c81 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/src/wasm/wasm_module.test.ts @@ -0,0 +1,27 @@ +import { WasmModule } from './wasm_module.js'; +import { fileURLToPath } from 'url'; +import { readFile } from 'fs/promises'; +import { dirname } from 'path'; + +/** + * Fetch a simple WASM. + */ +async function fetchCode() { + const __dirname = dirname(fileURLToPath(import.meta.url)); + return await readFile(`${__dirname}/../test/gcd.wasm`); +} + +describe('barretenberg wasm', () => { + let wasm!: WasmModule; + + beforeAll(async () => { + wasm = new WasmModule(await fetchCode(), () => ({ + /*no imports*/ + })); + await wasm.init(); + }); + + it('should call gcd with correct result', () => { + expect(wasm.call('gcd', 12312, 12123)).toBe(27); + }); +}); diff --git a/circuits/ts/.yalc/@aztec/wasm/src/wasm/wasm_module.ts b/circuits/ts/.yalc/@aztec/wasm/src/wasm/wasm_module.ts new file mode 100644 index 00000000000..abcec5ef385 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/src/wasm/wasm_module.ts @@ -0,0 +1,223 @@ +import { createDebugLogger, DebugLogger } from '@aztec/log'; +import { Buffer } from 'buffer'; +import { MemoryFifo } from '../memory_fifo.js'; +import { getEmptyWasiSdk } from './empty_wasi_sdk.js'; +import { randomBytes } from 'crypto'; + +/** + * WasmModule: + * Helper over a webassembly module. + * Assumes a few quirks. + * 1) the module expects wasi_snapshot_preview1 with the methods from getEmptyWasiSdk + * 2) of which the webassembly + * we instantiate only uses random_get (update this if more WASI sdk methods are needed). + */ +export class WasmModule { + private memory!: WebAssembly.Memory; + private heap!: Uint8Array; + private instance?: WebAssembly.Instance; + private mutexQ = new MemoryFifo(); + private debug: DebugLogger; + + /** + * Create a wasm module. Should be followed by await init();. + * @param module - The module as a WebAssembly.Module or a Buffer. + * @param importFn - Imports expected by the WASM. + * @param loggerName - Optional, for debug logging. + */ + constructor( + private module: WebAssembly.Module | Buffer, + private importFn: (module: WasmModule) => any, + loggerName = 'wasm', + ) { + this.debug = createDebugLogger(loggerName); + this.mutexQ.put(true); + } + + /** + * Return the wasm source. + * @returns The source. + */ + public getModule(): WebAssembly.Module | Buffer { + return this.module; + } + /** + * Initialize this wasm module. + * @param wasmImportEnv - Linked to a module called "env". Functions implementations referenced from e.g. C++. + * @param initial - 20 pages by default. 20*2**16 \> 1mb stack size plus other overheads. + * @param maximum - 8192 maximum by default. 512mb. + */ + public async init(initial = 20, maximum = 8192) { + this.debug( + `initial mem: ${initial} pages, ${(initial * 2 ** 16) / (1024 * 1024)}mb. max mem: ${maximum} pages, ${ + (maximum * 2 ** 16) / (1024 * 1024) + }mb`, + ); + this.memory = new WebAssembly.Memory({ initial, maximum }); + // Create a view over the memory buffer. + // We do this once here, as webkit *seems* bugged out and actually shows this as new memory, + // thus displaying double. It's only worse if we create views on demand. I haven't established yet if + // the bug is also exasperating the termination on mobile due to "excessive memory usage". It could be + // that the OS is actually getting an incorrect reading in the same way the memory profiler does... + // The view will have to be recreated if the memory is grown. See getMemory(). + this.heap = new Uint8Array(this.memory.buffer); + + // We support the wasi 12 SDK, but only implement random_get + /* eslint-disable camelcase */ + const importObj = { + wasi_snapshot_preview1: { + ...getEmptyWasiSdk(this.debug), + random_get: (arr: number, length: number) => { + arr = arr >>> 0; + const heap = this.getMemory(); + const randomData = randomBytes(length); + for (let i = arr; i < arr + length; ++i) { + heap[i] = randomData[i - arr]; + } + }, + }, + env: this.importFn(this), + }; + + if (this.module instanceof WebAssembly.Module) { + this.instance = await WebAssembly.instantiate(this.module, importObj); + } else { + const { instance } = await WebAssembly.instantiate(this.module, importObj); + this.instance = instance; + } + } + + /** + * The methods or objects exported by the WASM module. + * @returns An indexable object. + */ + public exports(): any { + if (!this.instance) { + throw new Error('WasmModule: not initialized!'); + } + return this.instance.exports; + } + + /** + * Get the current logger. + * @returns Logging function. + */ + public getLogger() { + return this.debug; + } + + /** + * Add a logger. + * @param logger - Function to call when logging. + */ + public addLogger(logger: DebugLogger) { + const oldDebug = this.debug; + this.debug = (...args: any[]) => { + logger(...args); + oldDebug(...args); + }; + } + + /** + * Calls into the WebAssembly. + * @param name - The method name. + * @param args - The arguments to the method. + * @returns The numeric method result. + */ + public call(name: string, ...args: any): number { + if (!this.exports()[name]) { + throw new Error(`WASM function ${name} not found.`); + } + try { + // When returning values from the WASM, use >>> operator to convert + // signed representation to unsigned representation. + return this.exports()[name](...args) >>> 0; + } catch (err: any) { + const message = `WASM function ${name} aborted, error: ${err}`; + this.debug(message); + this.debug(err.stack); + throw new Error(message); + } + } + /** + * Get the memory used by the WASM module. + * @returns A WebAssembly memory object. + */ + public getRawMemory(): WebAssembly.Memory { + return this.memory; + } + /** + * Get the memory used by the WASM module, as a byte array. + * @returns A Uint8Array view of the WASM module memory. + */ + public getMemory(): Uint8Array { + // If the memory is grown, our view over it will be lost. Recreate the view. + if (this.heap.length === 0) { + this.heap = new Uint8Array(this.memory.buffer); + } + return this.heap; + } + + /** + * The memory size in bytes. + * @returns Number of bytes. + */ + public memSize(): number { + return this.getMemory().length; + } + + /** + * Get a slice of memory between two addresses. + * @param start - The start address. + * @param end - The end address. + * @returns A Uint8Array view of memory. + */ + public getMemorySlice(start: number, end: number) { + return this.getMemory().slice(start, end); + } + + /** + * Write data into the heap. + * @param offset - The address to write data at. + * @param arr - The data to write. + */ + public writeMemory(offset: number, arr: Uint8Array) { + const mem = this.getMemory(); + for (let i = 0; i < arr.length; i++) { + mem[i + offset] = arr[i]; + } + } + + /** + * Read WASM memory as a JS string. + * @param addr - The memory address. + * @returns A JS string. + */ + public getMemoryAsString(addr: number) { + addr = addr >>> 0; + const m = this.getMemory(); + let i = addr; + for (; m[i] !== 0; ++i); + return Buffer.from(m.slice(addr, i)).toString('ascii'); + } + + /** + * When calling the wasm, sometimes a caller will require exclusive access over a series of calls. + * E.g. When a result is written to address 0, one cannot have another caller writing to the same address via + * writeMemory before the result is read via sliceMemory. + * Acquire() gets a single token from a fifo. The caller must call release() to add the token back. + */ + public async acquire() { + await this.mutexQ.get(); + } + + /** + * Release the mutex, letting another promise call acquire(). + */ + public release() { + if (this.mutexQ.length() !== 0) { + throw new Error('Release called but not acquired.'); + } + this.mutexQ.put(true); + } +} diff --git a/circuits/ts/.yalc/@aztec/wasm/src/worker/browser/index.ts b/circuits/ts/.yalc/@aztec/wasm/src/worker/browser/index.ts new file mode 100644 index 00000000000..ae6a02c0771 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/src/worker/browser/index.ts @@ -0,0 +1,2 @@ +export * from './web_worker.js'; +export * from './web_data_store.js'; diff --git a/circuits/ts/.yalc/@aztec/wasm/src/worker/browser/start_web_module.ts b/circuits/ts/.yalc/@aztec/wasm/src/worker/browser/start_web_module.ts new file mode 100644 index 00000000000..e6b05bbd365 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/src/worker/browser/start_web_module.ts @@ -0,0 +1,23 @@ +import { DispatchMsg, TransportServer, WorkerListener } from '../../transport/index.js'; +import { WasmModule } from '../../wasm/wasm_module.js'; + +/** + * Start the transport server corresponding to this module. + * @param module - The WasmModule to host. + */ +export function startWebModule(module: WasmModule) { + const dispatch = async ({ fn, args }: DispatchMsg) => { + if (fn === '__destroyWorker__') { + transportServer.stop(); + return; + } + if (!(module as any)[fn]) { + throw new Error(`dispatch error, function not found: ${fn}`); + } + return await (module as any)[fn](...args); + }; + const transportListener = new WorkerListener(self); + const transportServer = new TransportServer(transportListener, dispatch); + module.addLogger((...args: any[]) => transportServer.broadcast({ fn: 'emit', args: ['log', ...args] })); + transportServer.start(); +} diff --git a/circuits/ts/.yalc/@aztec/wasm/src/worker/browser/web_data_store.ts b/circuits/ts/.yalc/@aztec/wasm/src/worker/browser/web_data_store.ts new file mode 100644 index 00000000000..79f9c6a60eb --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/src/worker/browser/web_data_store.ts @@ -0,0 +1,37 @@ +import { DataStore } from '../data_store.js'; +import levelup, { LevelUp } from 'levelup'; +import memdown from 'memdown'; + +/** + * Cache for data used by wasm module. + * Stores in a LevelUp database. + */ +export class WebDataStore implements DataStore { + private db: LevelUp; + + constructor() { + // TODO: The whole point of this is to reduce memory load in the browser. + // Replace with leveljs so the data is stored in indexeddb and not in memory. + // Hack: Cast as any to work around package "broken" with node16 resolution + // See https://github.com/microsoft/TypeScript/issues/49160 + this.db = levelup((memdown as any)()); + } + + /** + * Lookup a key. + * @param key - Key to lookup. + * @returns The buffer. + */ + async get(key: string): Promise { + return await this.db.get(key).catch(() => {}); + } + + /** + * Alter a key. + * @param key - Key to alter. + * @param value - Buffer to store. + */ + async set(key: string, value: Buffer): Promise { + await this.db.put(key, value); + } +} diff --git a/circuits/ts/.yalc/@aztec/wasm/src/worker/browser/web_worker.ts b/circuits/ts/.yalc/@aztec/wasm/src/worker/browser/web_worker.ts new file mode 100644 index 00000000000..2f62882d4d8 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/src/worker/browser/web_worker.ts @@ -0,0 +1,24 @@ +import { WasmModule } from '../../wasm/wasm_module.js'; +import { createDispatchProxy, DispatchMsg, TransportClient, WorkerConnector } from '../../transport/index.js'; +import { WasmWorker } from '../wasm_worker.js'; + +/** + * Instantiate a web worker. + * @param url - The URL. + * @param initialMem - Initial memory pages. + * @param maxMem - Maximum memory pages. + * @returns The worker. + */ +export async function createWebWorker(url: string, initialMem?: number, maxMem?: number): Promise { + const worker = new Worker(url); + const transportConnect = new WorkerConnector(worker); + const transportClient = new TransportClient(transportConnect); + await transportClient.open(); + const remoteModule = createDispatchProxy(WasmModule, transportClient) as WasmWorker; + remoteModule.destroyWorker = async () => { + await transportClient.request({ fn: '__destroyWorker__', args: [] }); + transportClient.close(); + }; + await remoteModule.init(initialMem, maxMem); + return remoteModule; +} diff --git a/circuits/ts/.yalc/@aztec/wasm/src/worker/data_store.ts b/circuits/ts/.yalc/@aztec/wasm/src/worker/data_store.ts new file mode 100644 index 00000000000..4390b2775ee --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/src/worker/data_store.ts @@ -0,0 +1,7 @@ +/** + * Simple read/write interface for wasm modules. + */ +export interface DataStore { + get(key: string): Promise; + set(key: string, value: Buffer): Promise; +} diff --git a/circuits/ts/.yalc/@aztec/wasm/src/worker/index.ts b/circuits/ts/.yalc/@aztec/wasm/src/worker/index.ts new file mode 100644 index 00000000000..de4da352751 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/src/worker/index.ts @@ -0,0 +1,2 @@ +export { WorkerPool } from './worker_pool.js'; +export { WasmWorker } from './wasm_worker.js'; diff --git a/circuits/ts/.yalc/@aztec/wasm/src/worker/node/index.ts b/circuits/ts/.yalc/@aztec/wasm/src/worker/node/index.ts new file mode 100644 index 00000000000..6ac2cfb6ba3 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/src/worker/node/index.ts @@ -0,0 +1,2 @@ +export * from './node_worker.js'; +export * from './node_data_store.js'; diff --git a/circuits/ts/.yalc/@aztec/wasm/src/worker/node/node_data_store.ts b/circuits/ts/.yalc/@aztec/wasm/src/worker/node/node_data_store.ts new file mode 100644 index 00000000000..d3835350c30 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/src/worker/node/node_data_store.ts @@ -0,0 +1,36 @@ +import { DataStore } from '../data_store.js'; +import levelup, { LevelUp } from 'levelup'; +import leveldown from 'leveldown'; +import memdown from 'memdown'; + +/** + * Cache for data used by wasm module. + */ +export class NodeDataStore implements DataStore { + private db: LevelUp; + + // eslint-disable-next-line + constructor(path?: string) { + // Hack: Cast as any to work around packages "broken" with node16 resolution + // See https://github.com/microsoft/TypeScript/issues/49160 + this.db = levelup(path ? (leveldown as any)(path) : (memdown as any)()); + } + + /** + * Get a value from our DB. + * @param key - The key to look up. + * @returns The value. + */ + async get(key: string): Promise { + return await this.db.get(key).catch(() => {}); + } + + /** + * Set a value in our DB. + * @param key - The key to update. + * @param value - The value to set. + */ + async set(key: string, value: Buffer): Promise { + await this.db.put(key, value); + } +} diff --git a/circuits/ts/.yalc/@aztec/wasm/src/worker/node/node_worker.ts b/circuits/ts/.yalc/@aztec/wasm/src/worker/node/node_worker.ts new file mode 100644 index 00000000000..a11f379196a --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/src/worker/node/node_worker.ts @@ -0,0 +1,22 @@ +import { Worker } from 'worker_threads'; +import { createDispatchProxy, DispatchMsg, TransportClient } from '../../transport/index.js'; +import { NodeConnector } from '../../transport/index.js'; +import { WasmModule } from '../../wasm/wasm_module.js'; +import { WasmWorker } from '../wasm_worker.js'; + +/** + * + */ +export async function createNodeWorker(filepath: string, initialMem?: number, maxMem?: number): Promise { + const worker = new Worker(filepath); + const transportConnect = new NodeConnector(worker); + const transportClient = new TransportClient(transportConnect); + await transportClient.open(); + const remoteModule = createDispatchProxy(WasmModule, transportClient) as WasmWorker; + remoteModule.destroyWorker = async () => { + await transportClient.request({ fn: '__destroyWorker__', args: [] }); + transportClient.close(); + }; + await remoteModule.init(initialMem, maxMem); + return remoteModule; +} diff --git a/circuits/ts/.yalc/@aztec/wasm/src/worker/node/start_node_module.ts b/circuits/ts/.yalc/@aztec/wasm/src/worker/node/start_node_module.ts new file mode 100644 index 00000000000..ca0c1c9fd9e --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/src/worker/node/start_node_module.ts @@ -0,0 +1,28 @@ +import { parentPort } from 'worker_threads'; +import { NodeListener, DispatchMsg, TransportServer } from '../../transport/index.js'; +import { WasmModule } from '../../wasm/wasm_module.js'; + +if (!parentPort) { + throw new Error('InvalidWorker'); +} + +/** + * Start the transport server corresponding to this module. + * @param module - The WasmModule to host. + */ +export function startNodeModule(module: WasmModule) { + const dispatch = async ({ fn, args }: DispatchMsg) => { + if (fn === '__destroyWorker__') { + transportServer.stop(); + return; + } + if (!(module as any)[fn]) { + throw new Error(`dispatch error, function not found: ${fn}`); + } + return await (module as any)[fn](...args); + }; + const transportListener = new NodeListener(); + const transportServer = new TransportServer(transportListener, dispatch); + module.addLogger((...args: any[]) => transportServer.broadcast({ fn: 'emit', args: ['log', ...args] })); + transportServer.start(); +} diff --git a/circuits/ts/.yalc/@aztec/wasm/src/worker/wasm_worker.ts b/circuits/ts/.yalc/@aztec/wasm/src/worker/wasm_worker.ts new file mode 100644 index 00000000000..a9dcb4a7ad2 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/src/worker/wasm_worker.ts @@ -0,0 +1,7 @@ +import { Proxify } from '../transport/index.js'; +import { WasmModule } from '../wasm/wasm_module.js'; + +/** + * Represents either a WASM web worker, or node.js worker. + */ +export type WasmWorker = Proxify & { destroyWorker(): void }; diff --git a/circuits/ts/.yalc/@aztec/wasm/src/worker/worker_pool.ts b/circuits/ts/.yalc/@aztec/wasm/src/worker/worker_pool.ts new file mode 100644 index 00000000000..7ac278ba571 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/src/worker/worker_pool.ts @@ -0,0 +1,73 @@ +import { createDebugLogger } from '@aztec/log'; +import { WasmWorker } from './wasm_worker.js'; + +const debug = createDebugLogger('bb:worker_pool'); + +/** + * Type of a worker factory. + * Used to customize WorkerPool worker construction. + */ +export type CreateWorker = (name: string, minMem: number, maxMem: number) => WasmWorker; +/** + * Allocates a pool of WasmWorker's. + * Worker 0 is allocated MAX_PAGES memory pages. This is because worker 0 will need to hold the proving key + * (i.e. Has state), whereas the others are pure compute (they hold a little crs state). + */ +export class WorkerPool { + // TODO(AD): Revisit what this means in aztec 3 context + // -- + // Introduction of low mem prover work (polynomial cache) may actually increase mem usage when the backing store isn't + // enabled. We were seeing intermittent failings related to memory in production for some users when limiting to + // 6660 (416MB). It would be nice to understand why this is (the non determinism and/or the increased mem usage). + // For now, increasing mem usage to 512MB. This maybe preferable to backing out the low mem work, but + // ironically may break the chance of us using it in mobile. + // We *could* enable the low memory backing store, but this needs a little bit of work to actually + // read/write from indexeddb, performance testing, and actual further memory load testing. + // At this point it's hard to know what our memory savings would be relative to just fully reverting the LMP. + // public static MAX_PAGES = 6660; + /** + * The maximum number of memory pages to be used by the webassembly. + */ + public static MAX_PAGES = 8192; + /** + * The workers in the pool. + */ + private workers: WasmWorker[] = []; + + /** + * Create an instance and initialize the workers. + * @param createWorker - Worker factory. + * @param poolSize - Pool size. + * @returns An initialized WorkerPool. + */ + static async new(createWorker: CreateWorker, poolSize: number) { + const pool = new WorkerPool(); + await pool.init(createWorker, poolSize); + return pool; + } + + /** + * Initialize the workers. + * @param createWorker - Worker factory(). + * @param poolSize - Pool size. + * @param maxMem - Max memory pages. + */ + public async init(createWorker: CreateWorker, poolSize: number, maxMem = WorkerPool.MAX_PAGES) { + debug(`creating ${poolSize} workers...`); + const start = new Date().getTime(); + this.workers = await Promise.all( + Array(poolSize) + .fill(0) + .map((_, i) => createWorker(`${i}`, i === 0 ? Math.min(WorkerPool.MAX_PAGES, maxMem) : 768, maxMem)), + ); + + debug(`created workers: ${new Date().getTime() - start}ms`); + } + + /** + * Tell all workers in the pool to stop processing. + */ + public async destroy() { + await Promise.all(this.workers.map(w => w.destroyWorker())); + } +} diff --git a/circuits/ts/.yalc/@aztec/wasm/tsconfig.dest.json b/circuits/ts/.yalc/@aztec/wasm/tsconfig.dest.json new file mode 100644 index 00000000000..965aaa1c433 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/tsconfig.dest.json @@ -0,0 +1,4 @@ +{ + "extends": ".", + "exclude": ["**/*.test.*", "**/fixtures/*"] +} diff --git a/circuits/ts/.yalc/@aztec/wasm/tsconfig.json b/circuits/ts/.yalc/@aztec/wasm/tsconfig.json new file mode 100644 index 00000000000..f67ddec9fd6 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "..", + "compilerOptions": { + "outDir": "dest", + "rootDir": "src", + "tsBuildInfoFile": ".tsbuildinfo" + }, + "include": ["src"] +} diff --git a/circuits/ts/.yalc/@aztec/wasm/yalc.sig b/circuits/ts/.yalc/@aztec/wasm/yalc.sig new file mode 100644 index 00000000000..924c15826a5 --- /dev/null +++ b/circuits/ts/.yalc/@aztec/wasm/yalc.sig @@ -0,0 +1 @@ +49e137843b2fae07ab3c4df8d2229740 \ No newline at end of file From f2f06041b7af01b3903bdf801ac250eb251dd25b Mon Sep 17 00:00:00 2001 From: spalladino Date: Tue, 21 Mar 2023 18:58:45 +0000 Subject: [PATCH 080/166] Use address types, fixes forVK, and serialize kernel proof --- .../verifier_reference_string.cpp | 3 +- .../verifier_reference_string.hpp | 17 ++++++++- .../abis/base_rollup/base_rollup_inputs.hpp | 36 +++++++++---------- .../abis/contract_deployment_data.hpp | 9 ++--- .../abis/optionally_revealed_data.hpp | 5 +-- .../abis/private_kernel/new_contract_data.hpp | 9 ++--- .../private_kernel/previous_kernel_data.hpp | 5 +-- 7 files changed, 51 insertions(+), 33 deletions(-) diff --git a/circuits/cpp/src/aztec3/circuits/abis/barretenberg/verifier_reference_string.cpp b/circuits/cpp/src/aztec3/circuits/abis/barretenberg/verifier_reference_string.cpp index 151a52153f6..f99501ed412 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/barretenberg/verifier_reference_string.cpp +++ b/circuits/cpp/src/aztec3/circuits/abis/barretenberg/verifier_reference_string.cpp @@ -9,7 +9,8 @@ static std::shared_ptr* global_verifier_reference // TODO(AD): After Milestone 1, rewrite this with better injection mechanism. std::shared_ptr get_global_verifier_reference_string() { - return *global_verifier_reference_string; + return global_verifier_reference_string ? *global_verifier_reference_string + : std::shared_ptr(); } // TODO(AD): After Milestone 1, rewrite this with better injection mechanism. void set_global_verifier_reference_string(std::shared_ptr const& vrs) diff --git a/circuits/cpp/src/aztec3/circuits/abis/barretenberg/verifier_reference_string.hpp b/circuits/cpp/src/aztec3/circuits/abis/barretenberg/verifier_reference_string.hpp index 7854b838ebd..4cfea82ed7c 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/barretenberg/verifier_reference_string.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/barretenberg/verifier_reference_string.hpp @@ -2,6 +2,7 @@ #include #include "barretenberg/srs/reference_string/reference_string.hpp" +#include "barretenberg/common/streams.hpp" #include "barretenberg/proof_system/verification_key/verification_key.hpp" namespace serialize { @@ -26,4 +27,18 @@ inline void write(std::vector& buf, std::shared_ptr const& key) +{ + return os << "composer_type: " << key->composer_type << '\n' + << "circuit_size: " << key->circuit_size << '\n' + << "num_public_inputs: " << key->num_public_inputs << '\n' + << "commitments: " << key->commitments << '\n' + << "contains_recursive_proof: " << key->contains_recursive_proof << '\n' + << "recursive_proof_public_input_indices: " << key->recursive_proof_public_input_indices << '\n'; +} + +} // namespace std \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/abis/base_rollup/base_rollup_inputs.hpp b/circuits/cpp/src/aztec3/circuits/abis/base_rollup/base_rollup_inputs.hpp index 84bd08fb50c..64d0c4a1a9b 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/base_rollup/base_rollup_inputs.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/base_rollup/base_rollup_inputs.hpp @@ -38,8 +38,7 @@ template void read(uint8_t const*& it, BaseRollupInputs& obj { using serialize::read; - // TODO: serialization of kernel data - // read(it, obj.kernel_data); + read(it, obj.kernel_data); read(it, obj.start_nullifier_tree_snapshot); read(it, obj.low_nullifier_leaf_preimages); read(it, obj.low_nullifier_membership_witness); @@ -53,8 +52,7 @@ template void write(std::vector& buf, BaseRollupInputs void write(std::vector& buf, BaseRollupInputs std::ostream& operator<<(std::ostream& os, BaseRollupInputs const& obj) { - return os - //<< "kernel_data: " << obj.kernel_data << "\n" - << "start_nullifier_tree_snapshot:\n" - << obj.start_nullifier_tree_snapshot << "\n" - << "low_nullifier_leaf_preimages:\n" - << obj.low_nullifier_leaf_preimages << "\n" - << "low_nullifier_membership_witness:\n" - << obj.low_nullifier_membership_witness << "\n" - << "historic_private_data_tree_root_membership_witnesses:\n" - << obj.historic_private_data_tree_root_membership_witnesses << "\n" - << "historic_contract_tree_root_membership_witnesses:\n" - << obj.historic_contract_tree_root_membership_witnesses << "\n" - << "constants:\n" - << obj.constants << "\n" - << "prover_id: " << obj.prover_id << "\n"; + return os << "kernel_data:\n" + << obj.kernel_data << "\n" + << "start_nullifier_tree_snapshot:\n" + << obj.start_nullifier_tree_snapshot << "\n" + << "low_nullifier_leaf_preimages:\n" + << obj.low_nullifier_leaf_preimages << "\n" + << "low_nullifier_membership_witness:\n" + << obj.low_nullifier_membership_witness << "\n" + << "historic_private_data_tree_root_membership_witnesses:\n" + << obj.historic_private_data_tree_root_membership_witnesses << "\n" + << "historic_contract_tree_root_membership_witnesses:\n" + << obj.historic_contract_tree_root_membership_witnesses << "\n" + << "constants:\n" + << obj.constants << "\n" + << "prover_id: " << obj.prover_id << "\n"; } } // namespace aztec3::circuits::abis \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/abis/contract_deployment_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/contract_deployment_data.hpp index 22b08b10ddf..1111d1c4bdb 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/contract_deployment_data.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/contract_deployment_data.hpp @@ -14,13 +14,14 @@ using plonk::stdlib::witness_t; using std::is_same; template struct ContractDeploymentData { + typedef typename NCT::address address; typedef typename NCT::boolean boolean; typedef typename NCT::fr fr; fr constructor_vk_hash; fr function_tree_root; fr contract_address_salt; - fr portal_contract_address; // TODO: no uint160 circuit type? + address portal_contract_address; bool operator==(ContractDeploymentData const&) const = default; @@ -66,7 +67,7 @@ template struct ContractDeploymentData { constructor_vk_hash.assert_is_zero(); function_tree_root.assert_is_zero(); contract_address_salt.assert_is_zero(); - portal_contract_address.assert_is_zero(); + portal_contract_address.to_field().assert_is_zero(); } void set_public() @@ -76,7 +77,7 @@ template struct ContractDeploymentData { constructor_vk_hash.set_public(); function_tree_root.set_public(); contract_address_salt.set_public(); - portal_contract_address.set_public(); + portal_contract_address.to_field().set_public(); } fr hash() const @@ -85,7 +86,7 @@ template struct ContractDeploymentData { constructor_vk_hash, function_tree_root, contract_address_salt, - portal_contract_address, + portal_contract_address.to_field(), }; return NCT::compress(inputs, GeneratorIndex::CONTRACT_DEPLOYMENT_DATA); diff --git a/circuits/cpp/src/aztec3/circuits/abis/optionally_revealed_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/optionally_revealed_data.hpp index 298b28737e2..5c2b4c2504d 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/optionally_revealed_data.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/optionally_revealed_data.hpp @@ -11,6 +11,7 @@ using aztec3::utils::types::NativeTypes; using plonk::stdlib::witness_t; template struct OptionallyRevealedData { + typedef typename NCT::address address; typedef typename NCT::boolean boolean; typedef typename NCT::fr fr; @@ -18,7 +19,7 @@ template struct OptionallyRevealedData { FunctionData function_data; std::array emitted_events; fr vk_hash; - fr portal_contract_address; // an ETH address + address portal_contract_address; boolean pay_fee_from_l1; boolean pay_fee_from_public_l2; boolean called_from_l1; @@ -68,7 +69,7 @@ template struct OptionallyRevealedData { function_data.set_public(); set_array_public(emitted_events); vk_hash.set_public(); - portal_contract_address.set_public(); + portal_contract_address.to_field().set_public(); fr(pay_fee_from_l1).set_public(); fr(pay_fee_from_public_l2).set_public(); fr(called_from_l1).set_public(); diff --git a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/new_contract_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/new_contract_data.hpp index 9ac222126e2..ac04f6b2376 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/new_contract_data.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/new_contract_data.hpp @@ -11,11 +11,12 @@ using plonk::stdlib::witness_t; using std::is_same; template struct NewContractData { + typedef typename NCT::address address; typedef typename NCT::fr fr; typedef typename NCT::boolean boolean; - fr contract_address; // TODO: Change to aztec address type - fr portal_contract_address; // TODO: Change to eth address type + address contract_address; + address portal_contract_address; fr function_tree_root; template NewContractData> to_circuit_type(Composer& composer) const @@ -48,8 +49,8 @@ template struct NewContractData { { static_assert(!(std::is_same::value)); - contract_address.set_public(); - portal_contract_address.set_public(); + contract_address.to_field().set_public(); + portal_contract_address.to_field().set_public(); function_tree_root.set_public(); } }; diff --git a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp index aa342438f07..afcd5a284b9 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp @@ -1,4 +1,5 @@ #pragma once +#include "../barretenberg/proof.hpp" #include "aztec3/circuits/abis/private_kernel/public_inputs.hpp" #include "aztec3/circuits/abis/barretenberg/verifier_reference_string.hpp" #include "aztec3/circuits/abis/barretenberg/proof.hpp" @@ -64,7 +65,7 @@ template void read(uint8_t const*& it, PreviousKernelData& k using serialize::read; read(it, kernel_data.public_inputs); - // read(it, kernel_data.proof); TODO + read(it, kernel_data.proof); read(it, kernel_data.vk); read(it, kernel_data.vk_index); read(it, kernel_data.vk_path); @@ -76,7 +77,7 @@ template void write(std::vector& buf, PreviousKernelData using serialize::write; write(buf, kernel_data.public_inputs); - // write(buf, kernel_data.proof); TODO + write(buf, kernel_data.proof); write(buf, kernel_data.vk); write(buf, kernel_data.vk_index); write(buf, kernel_data.vk_path); From 5212af13021915484fb74b588f834432cccf9431 Mon Sep 17 00:00:00 2001 From: ludamad Date: Tue, 21 Mar 2023 15:18:26 -0400 Subject: [PATCH 081/166] Update c_bind.cpp --- circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp b/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp index 01e80933a9b..8299124a94c 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp +++ b/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp @@ -173,7 +173,9 @@ WASM_EXPORT void abis__set_global_verifier_reference_string(uint8_t* data) serialize::set_global_verifier_reference_string(vrs); } -/*** Serialization test helpers ***/ +/* Typescript test helpers that call as_string_output() to stress serialization. + * Each of these take an object buffer, and a string size pointer. + * They return a string pointer (to be bbfree'd) and write to the string size pointer. */ WASM_EXPORT const char* abis__test_roundtrip_serialize_tx_context(uint8_t const* tx_context_buf, uint32_t* size) { return as_string_output>(tx_context_buf, size); From 0f69abe505b3d375fed68b8d867fc94fa08d1973 Mon Sep 17 00:00:00 2001 From: Adam Domurad Date: Tue, 21 Mar 2023 17:41:45 -0400 Subject: [PATCH 082/166] fix(style): remove unneeded typedefs --- .../cpp/src/aztec3/circuits/abis/contract_deployment_data.hpp | 1 - .../src/aztec3/circuits/abis/private_circuit_public_inputs.hpp | 3 --- .../aztec3/circuits/abis/private_kernel/new_contract_data.hpp | 1 - 3 files changed, 5 deletions(-) diff --git a/circuits/cpp/src/aztec3/circuits/abis/contract_deployment_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/contract_deployment_data.hpp index 1111d1c4bdb..8f6d2ac7b14 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/contract_deployment_data.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/contract_deployment_data.hpp @@ -15,7 +15,6 @@ using std::is_same; template struct ContractDeploymentData { typedef typename NCT::address address; - typedef typename NCT::boolean boolean; typedef typename NCT::fr fr; fr constructor_vk_hash; diff --git a/circuits/cpp/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp index 7082007e13f..59c46a99c4e 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp @@ -20,7 +20,6 @@ using plonk::stdlib::witness_t; template class PrivateCircuitPublicInputs { typedef typename NCT::fr fr; - typedef typename NCT::boolean boolean; public: CallContext call_context; @@ -213,9 +212,7 @@ std::ostream& operator<<(std::ostream& os, PrivateCircuitPublicInputs const // std::nullopt) template class OptionalPrivateCircuitPublicInputs { typedef typename NCT::fr fr; - typedef typename NCT::boolean boolean; typedef typename std::optional opt_fr; - typedef typename std::optional opt_boolean; public: std::optional> call_context; diff --git a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/new_contract_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/new_contract_data.hpp index ac04f6b2376..0653901aa26 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/new_contract_data.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/new_contract_data.hpp @@ -13,7 +13,6 @@ using std::is_same; template struct NewContractData { typedef typename NCT::address address; typedef typename NCT::fr fr; - typedef typename NCT::boolean boolean; address contract_address; address portal_contract_address; From aabbe2a37d36c805a2a1c2744a5835ac8a15d856 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Wed, 22 Mar 2023 14:50:44 -0300 Subject: [PATCH 083/166] feat(ts): TS structs for C++ circuit abis (#76) * Typescript structs for rollup and kernel * Update README.md * Delete index.ts --------- Co-authored-by: ludamad --- circuits/ts/.eslintrc.cjs | 6 + circuits/ts/.gitignore | 1 + .../ts/.yalc/@aztec/eslint-config/index.js | 17 +- circuits/ts/README.md | 15 + circuits/ts/package.json | 63 + circuits/ts/src/crs/index.ts | 173 + .../__snapshots__/base_rollup.test.ts.snap | 488 +++ .../__snapshots__/function_data.test.ts.snap | 8 + .../structs/__snapshots__/kernel.test.ts.snap | 146 + ...private_circuit_public_inputs.test.ts.snap | 32 + .../src/structs/__snapshots__/tx.test.ts.snap | 13 + circuits/ts/src/structs/base_rollup.test.ts | 96 + circuits/ts/src/structs/base_rollup.ts | 190 + circuits/ts/src/structs/call_context.ts | 31 + circuits/ts/src/structs/constants.ts | 34 + circuits/ts/src/structs/function_data.test.ts | 12 + circuits/ts/src/structs/function_data.ts | 24 + circuits/ts/src/structs/kernel.test.ts | 20 + circuits/ts/src/structs/kernel.ts | 180 + .../private_circuit_public_inputs.test.ts | 70 + .../structs/private_circuit_public_inputs.ts | 89 + circuits/ts/src/structs/shared.ts | 191 + circuits/ts/src/structs/tx.test.ts | 12 + circuits/ts/src/structs/tx.ts | 50 + circuits/ts/src/structs/verification_key.ts | 82 + .../tests/expectSerializeToMatchSnapshot.ts | 54 + circuits/ts/src/tests/factories.ts | 159 + .../writeGlobalVerifierReferenceString.ts | 19 + circuits/ts/src/utils/jsUtils.ts | 56 + circuits/ts/src/wasm/aztec3-circuits.wasm | 1 + circuits/ts/src/wasm/circuits_wasm.test.ts | 30 + circuits/ts/src/wasm/circuits_wasm.ts | 176 + circuits/ts/src/wasm/index.ts | 1 + circuits/ts/src/wasm/serialize.ts | 155 + circuits/ts/tsconfig.dest.json | 4 + circuits/ts/tsconfig.json | 22 + circuits/ts/yalc.lock | 22 + circuits/ts/yarn.lock | 3505 +++++++++++++++++ 38 files changed, 6242 insertions(+), 5 deletions(-) create mode 100644 circuits/ts/.eslintrc.cjs create mode 100644 circuits/ts/.gitignore create mode 100644 circuits/ts/README.md create mode 100644 circuits/ts/package.json create mode 100644 circuits/ts/src/crs/index.ts create mode 100644 circuits/ts/src/structs/__snapshots__/base_rollup.test.ts.snap create mode 100644 circuits/ts/src/structs/__snapshots__/function_data.test.ts.snap create mode 100644 circuits/ts/src/structs/__snapshots__/kernel.test.ts.snap create mode 100644 circuits/ts/src/structs/__snapshots__/private_circuit_public_inputs.test.ts.snap create mode 100644 circuits/ts/src/structs/__snapshots__/tx.test.ts.snap create mode 100644 circuits/ts/src/structs/base_rollup.test.ts create mode 100644 circuits/ts/src/structs/base_rollup.ts create mode 100644 circuits/ts/src/structs/call_context.ts create mode 100644 circuits/ts/src/structs/constants.ts create mode 100644 circuits/ts/src/structs/function_data.test.ts create mode 100644 circuits/ts/src/structs/function_data.ts create mode 100644 circuits/ts/src/structs/kernel.test.ts create mode 100644 circuits/ts/src/structs/kernel.ts create mode 100644 circuits/ts/src/structs/private_circuit_public_inputs.test.ts create mode 100644 circuits/ts/src/structs/private_circuit_public_inputs.ts create mode 100644 circuits/ts/src/structs/shared.ts create mode 100644 circuits/ts/src/structs/tx.test.ts create mode 100644 circuits/ts/src/structs/tx.ts create mode 100644 circuits/ts/src/structs/verification_key.ts create mode 100644 circuits/ts/src/tests/expectSerializeToMatchSnapshot.ts create mode 100644 circuits/ts/src/tests/factories.ts create mode 100644 circuits/ts/src/tests/writeGlobalVerifierReferenceString.ts create mode 100644 circuits/ts/src/utils/jsUtils.ts create mode 120000 circuits/ts/src/wasm/aztec3-circuits.wasm create mode 100644 circuits/ts/src/wasm/circuits_wasm.test.ts create mode 100644 circuits/ts/src/wasm/circuits_wasm.ts create mode 100644 circuits/ts/src/wasm/index.ts create mode 100644 circuits/ts/src/wasm/serialize.ts create mode 100644 circuits/ts/tsconfig.dest.json create mode 100644 circuits/ts/tsconfig.json create mode 100644 circuits/ts/yalc.lock create mode 100644 circuits/ts/yarn.lock diff --git a/circuits/ts/.eslintrc.cjs b/circuits/ts/.eslintrc.cjs new file mode 100644 index 00000000000..0f8669c4ac0 --- /dev/null +++ b/circuits/ts/.eslintrc.cjs @@ -0,0 +1,6 @@ +require("@rushstack/eslint-patch/modern-module-resolution"); + +module.exports = { + extends: ["@aztec/eslint-config"], + parserOptions: { tsconfigRootDir: __dirname }, +}; diff --git a/circuits/ts/.gitignore b/circuits/ts/.gitignore new file mode 100644 index 00000000000..3c3629e647f --- /dev/null +++ b/circuits/ts/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/circuits/ts/.yalc/@aztec/eslint-config/index.js b/circuits/ts/.yalc/@aztec/eslint-config/index.js index 3e30099520f..ee45c8912bf 100644 --- a/circuits/ts/.yalc/@aztec/eslint-config/index.js +++ b/circuits/ts/.yalc/@aztec/eslint-config/index.js @@ -1,8 +1,9 @@ const contexts = [ 'TSMethodDefinition', 'MethodDefinition', - // 'TSPropertyDefinition', - // 'PropertyDefinition', + 'TSParameterProperty[accessibility=public]', + 'TSPropertyDefinition[accessibility=public]', + 'PropertyDefinition[accessibility=public]', 'TSPropertySignature', 'PropertySignature', 'TSInterfaceDeclaration', @@ -26,7 +27,11 @@ const contexts = [ ]; module.exports = { - extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'], + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + 'prettier', + ], root: true, parser: '@typescript-eslint/parser', plugins: ['@typescript-eslint', 'eslint-plugin-tsdoc', 'jsdoc'], @@ -57,11 +62,13 @@ module.exports = { patterns: [ { group: ['client-dest'], - message: "Fix this absolute garbage import. It's your duty to solve it before it spreads.", + message: + 'Fix this absolute garbage import. It's your duty to solve it before it spreads.', }, { group: ['dest'], - message: 'You should not be importing from a build directory. Did you accidentally do a relative import?', + message: + 'You should not be importing from a build directory. Did you accidentally do a relative import?', }, ], }, diff --git a/circuits/ts/README.md b/circuits/ts/README.md new file mode 100644 index 00000000000..15c3f5eb258 --- /dev/null +++ b/circuits/ts/README.md @@ -0,0 +1,15 @@ +# Circuits.js + +Javascript bindings for aztec3-circuits WASM. + +## To run: + +`yarn && yarn test` + +## To rebundle local dependencies from aztec3-packages + +Currently relies on dependencies locally linked from `aztec3-packages`. +Run `yarn bundle-deps` to rebundle them (committed to the repo for simplicity). +Run `yarn dev-deps` if you have ../../.. as the `aztec3-packages` path. + +TODO worker API diff --git a/circuits/ts/package.json b/circuits/ts/package.json new file mode 100644 index 00000000000..e1128bd3edb --- /dev/null +++ b/circuits/ts/package.json @@ -0,0 +1,63 @@ +{ + "name": "@aztec/circuits.js", + "version": "0.0.0", + "type": "module", + "exports": "./dest/index.js", + "typedoc": { + "entryPoint": "./src/index.ts", + "displayName": "Circuits.js", + "tsconfig": "./tsconfig.dest.json" + }, + "scripts": { + "build": "yarn clean && yarn formatting && tsc -b tsconfig.dest.json", + "build:dev": "tsc -b tsconfig.dest.json --watch", + "clean": "rm -rf ./dest .tsbuildinfo", + "bundle-deps": "yalc add @aztec/wasm-worker @aztec/log && yalc add -D @aztec/eslint-config", + "dev-deps": "rm -r node_modules/@aztec/wasm-worker ; yarn link ../../yarn-project/wasm-worker ; cd ../../yarn-project/wasm-worker ; yarn build:dev", + "formatting": "prettier --check ./src && eslint --max-warnings 0 ./src", + "formatting:fix": "prettier -w ./src", + "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --no-cache --passWithNoTests", + "test-debug": "NODE_NO_WARNINGS=1 node --inspect-brk --experimental-vm-modules $(yarn bin jest) --no-cache --passWithNoTests --runInBand" + }, + "jest": { + "preset": "ts-jest/presets/default-esm", + "globals": { + "ts-jest": { + "useESM": true + } + }, + "moduleNameMapper": { + "^(\\.{1,2}/.*)\\.js$": "$1" + }, + "testRegex": "./src/.*\\.test\\.ts$", + "rootDir": "./src" + }, + "dependencies": { + "@aztec/log": "file:.yalc/@aztec/log", + "@aztec/wasm": "file:.yalc/@aztec/wasm", + "@aztec/wasm-worker": "file:.yalc/@aztec/wasm-worker", + "cross-fetch": "^3.1.5", + "detect-node": "^2.1.0", + "eslint": "^8.35.0", + "tslib": "^2.4.0" + }, + "devDependencies": { + "@aztec/eslint-config": "file:.yalc/@aztec/eslint-config", + "@jest/globals": "^29.4.3", + "@rushstack/eslint-patch": "^1.1.4", + "@types/detect-node": "^2.0.0", + "@types/jest": "^29.4.0", + "@types/node": "^18.7.23", + "@typescript-eslint/eslint-plugin": "^5.54.1", + "@typescript-eslint/parser": "^5.54.1", + "jest": "^28.1.3", + "prettier": "^2.8.4", + "ts-dedent": "^2.2.0", + "ts-jest": "^28.0.7", + "ts-node": "^10.9.1", + "typescript": "^4.9.5" + }, + "resolutions": { + "@aztec/log": "file:.yalc/@aztec/log" + } +} diff --git a/circuits/ts/src/crs/index.ts b/circuits/ts/src/crs/index.ts new file mode 100644 index 00000000000..38c2b0d26b2 --- /dev/null +++ b/circuits/ts/src/crs/index.ts @@ -0,0 +1,173 @@ +import { readFile } from "fs/promises"; +import { existsSync } from "fs"; + +import { dirname } from "path"; +import { fileURLToPath } from "url"; + +/** + * The path to our SRS object, assuming that we are in aztec3-circuits/ts folder. + */ +const SRS_DEV_PATH = + dirname(fileURLToPath(import.meta.url)) + + "../cpp/barretenberg/cpp/srs_db/ignition/monomial/transcript00.dat"; +/** + * Downloader for CRS from the web or local. + */ +export class NetCrs { + private data!: Uint8Array; + private g2Data!: Uint8Array; + + constructor( + /** + * The number of circuit gates. + */ + public readonly numPoints: number + ) {} + + /** + * Download the data. + */ + async init() { + // We need (circuitSize + 1) number of g1 points. + const g1Start = 28; + const g1End = g1Start + (this.numPoints + 1) * 64 - 1; + + // Download required range of data. + const response = await fetch( + "https://aztec-ignition.s3.amazonaws.com/MAIN%20IGNITION/sealed/transcript00.dat", + { + headers: { + Range: `bytes=${g1Start}-${g1End}`, + }, + } + ); + + this.data = new Uint8Array(await response.arrayBuffer()); + + await this.downloadG2Data(); + } + + /** + * Download the G2 points data. + */ + async downloadG2Data() { + const g2Start = 28 + 5040000 * 64; + const g2End = g2Start + 128 - 1; + + const response2 = await fetch( + "https://aztec-ignition.s3.amazonaws.com/MAIN%20IGNITION/sealed/transcript00.dat", + { + headers: { + Range: `bytes=${g2Start}-${g2End}`, + }, + } + ); + + this.g2Data = new Uint8Array(await response2.arrayBuffer()); + } + + /** + * Verification key data. + * @returns The verification key. + */ + getData(): Uint8Array { + return this.data; + } + + /** + * G2 points data. + * @returns The points data. + */ + getG2Data(): Uint8Array { + return this.g2Data; + } +} + +/** + * Downloader for CRS from a local file (for Node). + */ +export class FileCrs { + private data!: Uint8Array; + private g2Data!: Uint8Array; + + constructor( + /** + * The number of circuit gates. + */ + public readonly numPoints: number, + private path: string + ) {} + + /** + * Read the data file. + */ + async init() { + // We need (circuitSize + 1) number of g1 points. + const g1Start = 28; + const g1End = g1Start + (this.numPoints + 1) * 64; + + const data = await readFile(this.path); + this.data = data.subarray(g1Start, g1End); + + const g2Start = 28 + 5040000 * 64; + const g2End = g2Start + 128; + this.g2Data = data.subarray(g2Start, g2End); + } + + /** + * Verification key data. + * @returns The verification key. + */ + getData(): Uint8Array { + return this.data; + } + + /** + * G2 points data. + * @returns The points data. + */ + getG2Data(): Uint8Array { + return this.g2Data; + } +} + +/** + * Generic CRS finder utility class. + */ +export class Crs { + private crs: FileCrs | NetCrs; + + constructor( + /** + * The number of circuit gates. + */ + public readonly numPoints: number + ) { + this.crs = existsSync(SRS_DEV_PATH) + ? new FileCrs(numPoints, SRS_DEV_PATH) + : new NetCrs(numPoints); + } + + /** + * Read CRS from our chosen source. + */ + async init() { + await this.crs.init(); + } + + /** + * Verification key data. + * @returns The verification key. + */ + getData(): Uint8Array { + return this.crs.getData(); + } + + /** + * G2 points data. + * @returns The points data. + */ + getG2Data(): Uint8Array { + return this.crs.getG2Data(); + } +} diff --git a/circuits/ts/src/structs/__snapshots__/base_rollup.test.ts.snap b/circuits/ts/src/structs/__snapshots__/base_rollup.test.ts.snap new file mode 100644 index 00000000000..57319e04034 --- /dev/null +++ b/circuits/ts/src/structs/__snapshots__/base_rollup.test.ts.snap @@ -0,0 +1,488 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`structs/base_rollup serializes and prints object 1`] = ` +"kernel_data: +[ public_inputs: end: +aggregation_object: +P0: { 0x100, 0x101 } +P1: { 0x200, 0x201 } +public_inputs: +[ + 0x102 + 0x103 + 0x104 + 0x105 +] +proof_witness_indices: +[ 106 107 108 109 10a 10b ] +has_data: 0 + +private_call_count: 0x10c +new_commitments: +[ 0x200 0x201 0x202 0x203 0x204 0x205 0x206 0x207 0x208 0x209 0x20a 0x20b 0x20c 0x20d 0x20e 0x20f ] +new_nullifiers: +[ 0x300 0x301 0x302 0x303 0x304 0x305 0x306 0x307 0x308 0x309 0x30a 0x30b 0x30c 0x30d 0x30e 0x30f ] +private_call_stack: +[ 0x400 0x401 0x402 0x403 0x404 0x405 0x406 0x407 ] +public_call_stack: +[ 0x500 0x501 0x502 0x503 0x504 0x505 0x506 0x507 ] +l1_msg_stack: +[ 0x600 0x601 0x602 0x603 ] +new_contracts: +[ contract_address: 0x700 +portal_contract_address: 0x101010101010101010101010101010101010101 +function_tree_root: 0x702 + contract_address: 0x701 +portal_contract_address: 0x202020202020202020202020202020202020202 +function_tree_root: 0x703 + contract_address: 0x702 +portal_contract_address: 0x303030303030303030303030303030303030303 +function_tree_root: 0x704 + contract_address: 0x703 +portal_contract_address: 0x404040404040404040404040404040404040404 +function_tree_root: 0x705 + contract_address: 0x704 +portal_contract_address: 0x505050505050505050505050505050505050505 +function_tree_root: 0x706 + contract_address: 0x705 +portal_contract_address: 0x606060606060606060606060606060606060606 +function_tree_root: 0x707 + contract_address: 0x706 +portal_contract_address: 0x707070707070707070707070707070707070707 +function_tree_root: 0x708 + contract_address: 0x707 +portal_contract_address: 0x808080808080808080808080808080808080808 +function_tree_root: 0x709 + ] +optionally_revealed_data: +[ call_stack_item_hash: 0x800 +function_data: +function_selector: 801 +is_private: 1 +is_constructor: 1 + +emitted_events: +[ 0x900 0x901 0x902 0x903 ] +vk_hash: 0x802 +portal_contract_address: 0x303030303030303030303030303030303030303 +pay_fee_from_l1: 1 +pay_fee_from_public_l2: 0 +called_from_l1: 1 +called_from_public_l2: 0 + call_stack_item_hash: 0x801 +function_data: +function_selector: 802 +is_private: 1 +is_constructor: 1 + +emitted_events: +[ 0x901 0x902 0x903 0x904 ] +vk_hash: 0x803 +portal_contract_address: 0x404040404040404040404040404040404040404 +pay_fee_from_l1: 1 +pay_fee_from_public_l2: 0 +called_from_l1: 1 +called_from_public_l2: 0 + call_stack_item_hash: 0x802 +function_data: +function_selector: 803 +is_private: 1 +is_constructor: 1 + +emitted_events: +[ 0x902 0x903 0x904 0x905 ] +vk_hash: 0x804 +portal_contract_address: 0x505050505050505050505050505050505050505 +pay_fee_from_l1: 1 +pay_fee_from_public_l2: 0 +called_from_l1: 1 +called_from_public_l2: 0 + call_stack_item_hash: 0x803 +function_data: +function_selector: 804 +is_private: 1 +is_constructor: 1 + +emitted_events: +[ 0x903 0x904 0x905 0x906 ] +vk_hash: 0x805 +portal_contract_address: 0x606060606060606060606060606060606060606 +pay_fee_from_l1: 1 +pay_fee_from_public_l2: 0 +called_from_l1: 1 +called_from_public_l2: 0 + ] + +constants: +old_tree_roots: private_data_tree_root: 0x200 +nullifier_tree_root: 0x201 +contract_tree_root: 0x202 +private_kernel_vk_tree_root: 0x203 + +tx_context: is_fee_payment_tx: 0 +is_rebate_payment_tx: 0 +is_contract_deployment_tx: 1 +contract_deployment_data: +constructor_vk_hash: 0x204 +function_tree_root: 0x205 +contract_address_salt: 0x206 +portal_contract_address: 0x707070707070707070707070707070707070707 + + +is_private: 1 + +proof: [ 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ] +vk: composer_type: 0 +circuit_size: 65 +num_public_inputs: 66 +commitments: [ + A: { 0x200, 0x300 } +] +contains_recursive_proof: 1 +recursive_proof_public_input_indices: [ 190 191 192 193 194 ] + +vk_index: 42 +vk_path: [ 0x1000 0x1001 0x1002 ] + public_inputs: end: +aggregation_object: +P0: { 0x200, 0x201 } +P1: { 0x300, 0x301 } +public_inputs: +[ + 0x202 + 0x203 + 0x204 + 0x205 +] +proof_witness_indices: +[ 206 207 208 209 20a 20b ] +has_data: 0 + +private_call_count: 0x20c +new_commitments: +[ 0x300 0x301 0x302 0x303 0x304 0x305 0x306 0x307 0x308 0x309 0x30a 0x30b 0x30c 0x30d 0x30e 0x30f ] +new_nullifiers: +[ 0x400 0x401 0x402 0x403 0x404 0x405 0x406 0x407 0x408 0x409 0x40a 0x40b 0x40c 0x40d 0x40e 0x40f ] +private_call_stack: +[ 0x500 0x501 0x502 0x503 0x504 0x505 0x506 0x507 ] +public_call_stack: +[ 0x600 0x601 0x602 0x603 0x604 0x605 0x606 0x607 ] +l1_msg_stack: +[ 0x700 0x701 0x702 0x703 ] +new_contracts: +[ contract_address: 0x800 +portal_contract_address: 0x101010101010101010101010101010101010101 +function_tree_root: 0x802 + contract_address: 0x801 +portal_contract_address: 0x202020202020202020202020202020202020202 +function_tree_root: 0x803 + contract_address: 0x802 +portal_contract_address: 0x303030303030303030303030303030303030303 +function_tree_root: 0x804 + contract_address: 0x803 +portal_contract_address: 0x404040404040404040404040404040404040404 +function_tree_root: 0x805 + contract_address: 0x804 +portal_contract_address: 0x505050505050505050505050505050505050505 +function_tree_root: 0x806 + contract_address: 0x805 +portal_contract_address: 0x606060606060606060606060606060606060606 +function_tree_root: 0x807 + contract_address: 0x806 +portal_contract_address: 0x707070707070707070707070707070707070707 +function_tree_root: 0x808 + contract_address: 0x807 +portal_contract_address: 0x808080808080808080808080808080808080808 +function_tree_root: 0x809 + ] +optionally_revealed_data: +[ call_stack_item_hash: 0x900 +function_data: +function_selector: 901 +is_private: 1 +is_constructor: 1 + +emitted_events: +[ 0xa00 0xa01 0xa02 0xa03 ] +vk_hash: 0x902 +portal_contract_address: 0x303030303030303030303030303030303030303 +pay_fee_from_l1: 1 +pay_fee_from_public_l2: 0 +called_from_l1: 1 +called_from_public_l2: 0 + call_stack_item_hash: 0x901 +function_data: +function_selector: 902 +is_private: 1 +is_constructor: 1 + +emitted_events: +[ 0xa01 0xa02 0xa03 0xa04 ] +vk_hash: 0x903 +portal_contract_address: 0x404040404040404040404040404040404040404 +pay_fee_from_l1: 1 +pay_fee_from_public_l2: 0 +called_from_l1: 1 +called_from_public_l2: 0 + call_stack_item_hash: 0x902 +function_data: +function_selector: 903 +is_private: 1 +is_constructor: 1 + +emitted_events: +[ 0xa02 0xa03 0xa04 0xa05 ] +vk_hash: 0x904 +portal_contract_address: 0x505050505050505050505050505050505050505 +pay_fee_from_l1: 1 +pay_fee_from_public_l2: 0 +called_from_l1: 1 +called_from_public_l2: 0 + call_stack_item_hash: 0x903 +function_data: +function_selector: 904 +is_private: 1 +is_constructor: 1 + +emitted_events: +[ 0xa03 0xa04 0xa05 0xa06 ] +vk_hash: 0x905 +portal_contract_address: 0x606060606060606060606060606060606060606 +pay_fee_from_l1: 1 +pay_fee_from_public_l2: 0 +called_from_l1: 1 +called_from_public_l2: 0 + ] + +constants: +old_tree_roots: private_data_tree_root: 0x300 +nullifier_tree_root: 0x301 +contract_tree_root: 0x302 +private_kernel_vk_tree_root: 0x303 + +tx_context: is_fee_payment_tx: 0 +is_rebate_payment_tx: 0 +is_contract_deployment_tx: 1 +contract_deployment_data: +constructor_vk_hash: 0x304 +function_tree_root: 0x305 +contract_address_salt: 0x306 +portal_contract_address: 0x707070707070707070707070707070707070707 + + +is_private: 1 + +proof: [ 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ] +vk: composer_type: 0 +circuit_size: 65 +num_public_inputs: 66 +commitments: [ + A: { 0x200, 0x300 } +] +contains_recursive_proof: 1 +recursive_proof_public_input_indices: [ 190 191 192 193 194 ] + +vk_index: 42 +vk_path: [ 0x1000 0x1001 0x1002 ] + ] +start_nullifier_tree_snapshot: +root: 0x100 +next_available_leaf_index: 256 + +low_nullifier_leaf_preimages: +[ leaf_value: 0x1000 +next_value: 0x1100 +next_index: 1200 + leaf_value: 0x1001 +next_value: 0x1101 +next_index: 1201 + leaf_value: 0x1002 +next_value: 0x1102 +next_index: 1202 + leaf_value: 0x1003 +next_value: 0x1103 +next_index: 1203 + leaf_value: 0x1004 +next_value: 0x1104 +next_index: 1204 + leaf_value: 0x1005 +next_value: 0x1105 +next_index: 1205 + leaf_value: 0x1006 +next_value: 0x1106 +next_index: 1206 + leaf_value: 0x1007 +next_value: 0x1107 +next_index: 1207 + leaf_value: 0x1008 +next_value: 0x1108 +next_index: 1208 + leaf_value: 0x1009 +next_value: 0x1109 +next_index: 1209 + leaf_value: 0x100a +next_value: 0x110a +next_index: 120a + leaf_value: 0x100b +next_value: 0x110b +next_index: 120b + leaf_value: 0x100c +next_value: 0x110c +next_index: 120c + leaf_value: 0x100d +next_value: 0x110d +next_index: 120d + leaf_value: 0x100e +next_value: 0x110e +next_index: 120e + leaf_value: 0x100f +next_value: 0x110f +next_index: 120f + leaf_value: 0x1010 +next_value: 0x1110 +next_index: 1210 + leaf_value: 0x1011 +next_value: 0x1111 +next_index: 1211 + leaf_value: 0x1012 +next_value: 0x1112 +next_index: 1212 + leaf_value: 0x1013 +next_value: 0x1113 +next_index: 1213 + leaf_value: 0x1014 +next_value: 0x1114 +next_index: 1214 + leaf_value: 0x1015 +next_value: 0x1115 +next_index: 1215 + leaf_value: 0x1016 +next_value: 0x1116 +next_index: 1216 + leaf_value: 0x1017 +next_value: 0x1117 +next_index: 1217 + leaf_value: 0x1018 +next_value: 0x1118 +next_index: 1218 + leaf_value: 0x1019 +next_value: 0x1119 +next_index: 1219 + leaf_value: 0x101a +next_value: 0x111a +next_index: 121a + leaf_value: 0x101b +next_value: 0x111b +next_index: 121b + leaf_value: 0x101c +next_value: 0x111c +next_index: 121c + leaf_value: 0x101d +next_value: 0x111d +next_index: 121d + leaf_value: 0x101e +next_value: 0x111e +next_index: 121e + leaf_value: 0x101f +next_value: 0x111f +next_index: 121f + ] +low_nullifier_membership_witness: +[ leaf_index: 2000 +sibling_path: [ 0x2000 0x2001 0x2002 0x2003 0x2004 0x2005 0x2006 0x2007 ] + leaf_index: 2001 +sibling_path: [ 0x2001 0x2002 0x2003 0x2004 0x2005 0x2006 0x2007 0x2008 ] + leaf_index: 2002 +sibling_path: [ 0x2002 0x2003 0x2004 0x2005 0x2006 0x2007 0x2008 0x2009 ] + leaf_index: 2003 +sibling_path: [ 0x2003 0x2004 0x2005 0x2006 0x2007 0x2008 0x2009 0x200a ] + leaf_index: 2004 +sibling_path: [ 0x2004 0x2005 0x2006 0x2007 0x2008 0x2009 0x200a 0x200b ] + leaf_index: 2005 +sibling_path: [ 0x2005 0x2006 0x2007 0x2008 0x2009 0x200a 0x200b 0x200c ] + leaf_index: 2006 +sibling_path: [ 0x2006 0x2007 0x2008 0x2009 0x200a 0x200b 0x200c 0x200d ] + leaf_index: 2007 +sibling_path: [ 0x2007 0x2008 0x2009 0x200a 0x200b 0x200c 0x200d 0x200e ] + leaf_index: 2008 +sibling_path: [ 0x2008 0x2009 0x200a 0x200b 0x200c 0x200d 0x200e 0x200f ] + leaf_index: 2009 +sibling_path: [ 0x2009 0x200a 0x200b 0x200c 0x200d 0x200e 0x200f 0x2010 ] + leaf_index: 200a +sibling_path: [ 0x200a 0x200b 0x200c 0x200d 0x200e 0x200f 0x2010 0x2011 ] + leaf_index: 200b +sibling_path: [ 0x200b 0x200c 0x200d 0x200e 0x200f 0x2010 0x2011 0x2012 ] + leaf_index: 200c +sibling_path: [ 0x200c 0x200d 0x200e 0x200f 0x2010 0x2011 0x2012 0x2013 ] + leaf_index: 200d +sibling_path: [ 0x200d 0x200e 0x200f 0x2010 0x2011 0x2012 0x2013 0x2014 ] + leaf_index: 200e +sibling_path: [ 0x200e 0x200f 0x2010 0x2011 0x2012 0x2013 0x2014 0x2015 ] + leaf_index: 200f +sibling_path: [ 0x200f 0x2010 0x2011 0x2012 0x2013 0x2014 0x2015 0x2016 ] + leaf_index: 2010 +sibling_path: [ 0x2010 0x2011 0x2012 0x2013 0x2014 0x2015 0x2016 0x2017 ] + leaf_index: 2011 +sibling_path: [ 0x2011 0x2012 0x2013 0x2014 0x2015 0x2016 0x2017 0x2018 ] + leaf_index: 2012 +sibling_path: [ 0x2012 0x2013 0x2014 0x2015 0x2016 0x2017 0x2018 0x2019 ] + leaf_index: 2013 +sibling_path: [ 0x2013 0x2014 0x2015 0x2016 0x2017 0x2018 0x2019 0x201a ] + leaf_index: 2014 +sibling_path: [ 0x2014 0x2015 0x2016 0x2017 0x2018 0x2019 0x201a 0x201b ] + leaf_index: 2015 +sibling_path: [ 0x2015 0x2016 0x2017 0x2018 0x2019 0x201a 0x201b 0x201c ] + leaf_index: 2016 +sibling_path: [ 0x2016 0x2017 0x2018 0x2019 0x201a 0x201b 0x201c 0x201d ] + leaf_index: 2017 +sibling_path: [ 0x2017 0x2018 0x2019 0x201a 0x201b 0x201c 0x201d 0x201e ] + leaf_index: 2018 +sibling_path: [ 0x2018 0x2019 0x201a 0x201b 0x201c 0x201d 0x201e 0x201f ] + leaf_index: 2019 +sibling_path: [ 0x2019 0x201a 0x201b 0x201c 0x201d 0x201e 0x201f 0x2020 ] + leaf_index: 201a +sibling_path: [ 0x201a 0x201b 0x201c 0x201d 0x201e 0x201f 0x2020 0x2021 ] + leaf_index: 201b +sibling_path: [ 0x201b 0x201c 0x201d 0x201e 0x201f 0x2020 0x2021 0x2022 ] + leaf_index: 201c +sibling_path: [ 0x201c 0x201d 0x201e 0x201f 0x2020 0x2021 0x2022 0x2023 ] + leaf_index: 201d +sibling_path: [ 0x201d 0x201e 0x201f 0x2020 0x2021 0x2022 0x2023 0x2024 ] + leaf_index: 201e +sibling_path: [ 0x201e 0x201f 0x2020 0x2021 0x2022 0x2023 0x2024 0x2025 ] + leaf_index: 201f +sibling_path: [ 0x201f 0x2020 0x2021 0x2022 0x2023 0x2024 0x2025 0x2026 ] + ] +historic_private_data_tree_root_membership_witnesses: +[ leaf_index: 3000 +sibling_path: [ 0x3000 0x3001 0x3002 0x3003 0x3004 0x3005 0x3006 0x3007 ] + leaf_index: 4000 +sibling_path: [ 0x4000 0x4001 0x4002 0x4003 0x4004 0x4005 0x4006 0x4007 ] + ] +historic_contract_tree_root_membership_witnesses: +[ leaf_index: 5000 +sibling_path: [ 0x5000 0x5001 0x5002 0x5003 0x5004 0x5005 0x5006 0x5007 ] + leaf_index: 6000 +sibling_path: [ 0x6000 0x6001 0x6002 0x6003 0x6004 0x6005 0x6006 0x6007 ] + ] +constants: +start_tree_of_historic_private_data_tree_roots_snapshot: + root: 0x100 +next_available_leaf_index: 256 + +start_tree_of_historic_contract_tree_roots_snapshot: +root: 0x200 +next_available_leaf_index: 512 + +tree_of_historic_l1_to_l2_msg_tree_roots_snapshot: +root: 0x300 +next_available_leaf_index: 768 + +private_kernel_vk_tree_root: 0x400 +public_kernel_vk_tree_root: 0x500 +base_rollup_vk_hash: 0x600 +merge_rollup_vk_hash: 0x700 + +prover_id: 0x42 +" +`; diff --git a/circuits/ts/src/structs/__snapshots__/function_data.test.ts.snap b/circuits/ts/src/structs/__snapshots__/function_data.test.ts.snap new file mode 100644 index 00000000000..63e3145ef36 --- /dev/null +++ b/circuits/ts/src/structs/__snapshots__/function_data.test.ts.snap @@ -0,0 +1,8 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`basic FunctionData serialization serializes a trivial FunctionData and prints it 1`] = ` +"function_selector: 123 +is_private: 1 +is_constructor: 1 +" +`; diff --git a/circuits/ts/src/structs/__snapshots__/kernel.test.ts.snap b/circuits/ts/src/structs/__snapshots__/kernel.test.ts.snap new file mode 100644 index 00000000000..64845a7f911 --- /dev/null +++ b/circuits/ts/src/structs/__snapshots__/kernel.test.ts.snap @@ -0,0 +1,146 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`structs/kernel serializes and prints previous_kernel_data 1`] = ` +"public_inputs: end: +aggregation_object: +P0: { 0x1, 0x2 } +P1: { 0x101, 0x102 } +public_inputs: +[ + 0x3 + 0x4 + 0x5 + 0x6 +] +proof_witness_indices: +[ 7 8 9 10 11 12 ] +has_data: 0 + +private_call_count: 0xd +new_commitments: +[ 0x101 0x102 0x103 0x104 0x105 0x106 0x107 0x108 0x109 0x10a 0x10b 0x10c 0x10d 0x10e 0x10f 0x110 ] +new_nullifiers: +[ 0x201 0x202 0x203 0x204 0x205 0x206 0x207 0x208 0x209 0x20a 0x20b 0x20c 0x20d 0x20e 0x20f 0x210 ] +private_call_stack: +[ 0x301 0x302 0x303 0x304 0x305 0x306 0x307 0x308 ] +public_call_stack: +[ 0x401 0x402 0x403 0x404 0x405 0x406 0x407 0x408 ] +l1_msg_stack: +[ 0x501 0x502 0x503 0x504 ] +new_contracts: +[ contract_address: 0x601 +portal_contract_address: 0x202020202020202020202020202020202020202 +function_tree_root: 0x603 + contract_address: 0x602 +portal_contract_address: 0x303030303030303030303030303030303030303 +function_tree_root: 0x604 + contract_address: 0x603 +portal_contract_address: 0x404040404040404040404040404040404040404 +function_tree_root: 0x605 + contract_address: 0x604 +portal_contract_address: 0x505050505050505050505050505050505050505 +function_tree_root: 0x606 + contract_address: 0x605 +portal_contract_address: 0x606060606060606060606060606060606060606 +function_tree_root: 0x607 + contract_address: 0x606 +portal_contract_address: 0x707070707070707070707070707070707070707 +function_tree_root: 0x608 + contract_address: 0x607 +portal_contract_address: 0x808080808080808080808080808080808080808 +function_tree_root: 0x609 + contract_address: 0x608 +portal_contract_address: 0x909090909090909090909090909090909090909 +function_tree_root: 0x60a + ] +optionally_revealed_data: +[ call_stack_item_hash: 0x701 +function_data: +function_selector: 702 +is_private: 1 +is_constructor: 1 + +emitted_events: +[ 0x801 0x802 0x803 0x804 ] +vk_hash: 0x703 +portal_contract_address: 0x404040404040404040404040404040404040404 +pay_fee_from_l1: 1 +pay_fee_from_public_l2: 0 +called_from_l1: 1 +called_from_public_l2: 0 + call_stack_item_hash: 0x702 +function_data: +function_selector: 703 +is_private: 1 +is_constructor: 1 + +emitted_events: +[ 0x802 0x803 0x804 0x805 ] +vk_hash: 0x704 +portal_contract_address: 0x505050505050505050505050505050505050505 +pay_fee_from_l1: 1 +pay_fee_from_public_l2: 0 +called_from_l1: 1 +called_from_public_l2: 0 + call_stack_item_hash: 0x703 +function_data: +function_selector: 704 +is_private: 1 +is_constructor: 1 + +emitted_events: +[ 0x803 0x804 0x805 0x806 ] +vk_hash: 0x705 +portal_contract_address: 0x606060606060606060606060606060606060606 +pay_fee_from_l1: 1 +pay_fee_from_public_l2: 0 +called_from_l1: 1 +called_from_public_l2: 0 + call_stack_item_hash: 0x704 +function_data: +function_selector: 705 +is_private: 1 +is_constructor: 1 + +emitted_events: +[ 0x804 0x805 0x806 0x807 ] +vk_hash: 0x706 +portal_contract_address: 0x707070707070707070707070707070707070707 +pay_fee_from_l1: 1 +pay_fee_from_public_l2: 0 +called_from_l1: 1 +called_from_public_l2: 0 + ] + +constants: +old_tree_roots: private_data_tree_root: 0x101 +nullifier_tree_root: 0x102 +contract_tree_root: 0x103 +private_kernel_vk_tree_root: 0x104 + +tx_context: is_fee_payment_tx: 0 +is_rebate_payment_tx: 0 +is_contract_deployment_tx: 1 +contract_deployment_data: +constructor_vk_hash: 0x105 +function_tree_root: 0x106 +contract_address_salt: 0x107 +portal_contract_address: 0x808080808080808080808080808080808080808 + + +is_private: 1 + +proof: [ 81 81 81 81 81 81 81 81 81 81 81 81 81 81 81 81 ] +vk: composer_type: 0 +circuit_size: 101 +num_public_inputs: 102 +commitments: [ + A: { 0x200, 0x300 } +] +contains_recursive_proof: 1 +recursive_proof_public_input_indices: [ 400 401 402 403 404 ] + +vk_index: 66 +vk_path: [ 0x1000 0x1001 0x1002 ] +" +`; diff --git a/circuits/ts/src/structs/__snapshots__/private_circuit_public_inputs.test.ts.snap b/circuits/ts/src/structs/__snapshots__/private_circuit_public_inputs.test.ts.snap new file mode 100644 index 00000000000..feea1c3ad7d --- /dev/null +++ b/circuits/ts/src/structs/__snapshots__/private_circuit_public_inputs.test.ts.snap @@ -0,0 +1,32 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`basic PrivateCircuitPublicInputs serialization serializes a trivial PrivateCircuitPublicInputs and prints it 1`] = ` +"call_context: msg_sender: 0x1 +storage_contract_address: 0x2 +tx_origin: 0x3 +is_delegate_call: 1 +is_static_call: 1 +is_contract_deployment: 1 + +args: [ 0x100 0x101 0x102 0x103 0x104 0x105 0x106 0x107 ] +return_values: [ 0x300 0x301 0x302 0x303 ] +emitted_events: [ 0x200 0x201 0x202 0x203 ] +new_commitments: [ 0x400 0x401 0x402 0x403 ] +new_nullifiers: [ 0x500 0x501 0x502 0x503 ] +private_call_stack: [ 0x600 0x601 0x602 0x603 ] +public_call_stack: [ 0x700 0x701 0x702 0x703 ] +l1_msg_stack: [ 0x800 0x801 ] +historic_private_data_tree_root: 0x1000 +historic_nullifier_tree_root: 0x1100 +contract_deployment_data: constructor_vk_hash: 0x1 +function_tree_root: 0x2 +contract_address_salt: 0x3 +portal_contract_address: 0x4 + +contract_deployment_data: constructor_vk_hash: 0x1 +function_tree_root: 0x2 +contract_address_salt: 0x3 +portal_contract_address: 0x4 + +" +`; diff --git a/circuits/ts/src/structs/__snapshots__/tx.test.ts.snap b/circuits/ts/src/structs/__snapshots__/tx.test.ts.snap new file mode 100644 index 00000000000..beecda1a92b --- /dev/null +++ b/circuits/ts/src/structs/__snapshots__/tx.test.ts.snap @@ -0,0 +1,13 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`structs/tx serializes and prints object 1`] = ` +"is_fee_payment_tx: 0 +is_rebate_payment_tx: 0 +is_contract_deployment_tx: 1 +contract_deployment_data: +constructor_vk_hash: 0x1 +function_tree_root: 0x2 +contract_address_salt: 0x3 +portal_contract_address: 0x404040404040404040404040404040404040404 +" +`; diff --git a/circuits/ts/src/structs/base_rollup.test.ts b/circuits/ts/src/structs/base_rollup.test.ts new file mode 100644 index 00000000000..c779ec8b03d --- /dev/null +++ b/circuits/ts/src/structs/base_rollup.test.ts @@ -0,0 +1,96 @@ +import { expectSerializeToMatchSnapshot } from "../tests/expectSerializeToMatchSnapshot.js"; +import { fr, makePreviousKernelData } from "../tests/factories.js"; +import { writeGlobalVerifierReferenceString } from "../tests/writeGlobalVerifierReferenceString"; +import { range } from "../utils/jsUtils.js"; +import { CircuitsWasm } from "../wasm/circuits_wasm.js"; +import { + AppendOnlyTreeSnapshot, + BaseRollupInputs, + ConstantBaseRollupData, + NullifierLeafPreimage, +} from "./base_rollup.js"; +import { + CONTRACT_TREE_ROOTS_TREE_HEIGHT, + KERNEL_NEW_NULLIFIERS_LENGTH, + NULLIFIER_TREE_HEIGHT, + PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT, +} from "./constants.js"; +import { PreviousKernelData } from "./kernel.js"; +import { MembershipWitness } from "./shared.js"; + +describe("structs/base_rollup", () => { + it(`serializes and prints object`, async () => { + const kernelData: [PreviousKernelData, PreviousKernelData] = [ + makePreviousKernelData(0x100), + makePreviousKernelData(0x200), + ]; + + const startNullifierTreeSnapshot = new AppendOnlyTreeSnapshot( + fr(0x100), + 0x100 + ); + + const lowNullifierLeafPreimages = range( + 2 * KERNEL_NEW_NULLIFIERS_LENGTH, + 0x1000 + ).map((x) => new NullifierLeafPreimage(fr(x), fr(x + 0x100), x + 0x200)); + + const lowNullifierMembershipWitness = range( + 2 * KERNEL_NEW_NULLIFIERS_LENGTH, + 0x2000 + ).map((x) => MembershipWitness.mock(NULLIFIER_TREE_HEIGHT, x)); + + const historicPrivateDataTreeRootMembershipWitnesses: BaseRollupInputs["historicPrivateDataTreeRootMembershipWitnesses"] = + [ + MembershipWitness.mock(PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT, 0x3000), + MembershipWitness.mock(PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT, 0x4000), + ]; + + const historicContractsTreeRootMembershipWitnesses: BaseRollupInputs["historicContractsTreeRootMembershipWitnesses"] = + [ + MembershipWitness.mock(CONTRACT_TREE_ROOTS_TREE_HEIGHT, 0x5000), + MembershipWitness.mock(CONTRACT_TREE_ROOTS_TREE_HEIGHT, 0x6000), + ]; + + const constants = ConstantBaseRollupData.from({ + startTreeOfHistoricPrivateDataTreeRootsSnapshot: + new AppendOnlyTreeSnapshot(fr(0x100), 0x100), + startTreeOfHistoricContractTreeRootsSnapshot: new AppendOnlyTreeSnapshot( + fr(0x200), + 0x200 + ), + treeOfHistoricL1ToL2MsgTreeRootsSnapshot: new AppendOnlyTreeSnapshot( + fr(0x300), + 0x300 + ), + privateKernelVkTreeRoot: fr(0x400), + publicKernelVkTreeRoot: fr(0x500), + baseRollupVkHash: fr(0x600), + mergeRollupVkHash: fr(0x700), + }); + + const proverId = fr(0x42); + + const baseRollupInputs = BaseRollupInputs.from({ + kernelData, + startNullifierTreeSnapshot, + lowNullifierLeafPreimages, + lowNullifierMembershipWitness, + historicPrivateDataTreeRootMembershipWitnesses, + historicContractsTreeRootMembershipWitnesses, + constants, + proverId, + }); + + const wasm = await CircuitsWasm.new(); + await writeGlobalVerifierReferenceString( + wasm, + /* example circuit size */ 100 + ); + await expectSerializeToMatchSnapshot( + baseRollupInputs.toBuffer(), + "abis__test_roundtrip_serialize_base_rollup_inputs", + wasm + ); + }); +}); diff --git a/circuits/ts/src/structs/base_rollup.ts b/circuits/ts/src/structs/base_rollup.ts new file mode 100644 index 00000000000..1697089ade0 --- /dev/null +++ b/circuits/ts/src/structs/base_rollup.ts @@ -0,0 +1,190 @@ +import { assertLength, FieldsOf } from "../utils/jsUtils.js"; +import { serializeToBuffer } from "../wasm/serialize.js"; +import { + CONTRACT_TREE_ROOTS_TREE_HEIGHT, + KERNEL_NEW_NULLIFIERS_LENGTH, + NULLIFIER_TREE_HEIGHT, + PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT, +} from "./constants.js"; +import { PreviousKernelData } from "./kernel.js"; +import { AggregationObject, Fr, MembershipWitness, UInt32 } from "./shared.js"; + +export class NullifierLeafPreimage { + constructor( + public leafValue: Fr, + public nextValue: Fr, + public nextIndex: UInt32 + ) {} + + toBuffer() { + return serializeToBuffer(this.leafValue, this.nextValue, this.nextIndex); + } +} + +export class AppendOnlyTreeSnapshot { + constructor(public root: Fr, public nextAvailableLeafIndex: UInt32) {} + + toBuffer() { + return serializeToBuffer(this.root, this.nextAvailableLeafIndex); + } +} + +export class ConstantBaseRollupData { + constructor( + // The very latest roots as at the very beginning of the entire rollup: + public startTreeOfHistoricPrivateDataTreeRootsSnapshot: AppendOnlyTreeSnapshot, + public startTreeOfHistoricContractTreeRootsSnapshot: AppendOnlyTreeSnapshot, + public treeOfHistoricL1ToL2MsgTreeRootsSnapshot: AppendOnlyTreeSnapshot, + + // Some members of this struct tbd: + public privateKernelVkTreeRoot: Fr, + public publicKernelVkTreeRoot: Fr, + public baseRollupVkHash: Fr, + public mergeRollupVkHash: Fr + ) {} + + static from( + fields: FieldsOf + ): ConstantBaseRollupData { + return new ConstantBaseRollupData( + ...ConstantBaseRollupData.getFields(fields) + ); + } + + static getFields(fields: FieldsOf) { + return [ + fields.startTreeOfHistoricPrivateDataTreeRootsSnapshot, + fields.startTreeOfHistoricContractTreeRootsSnapshot, + fields.treeOfHistoricL1ToL2MsgTreeRootsSnapshot, + fields.privateKernelVkTreeRoot, + fields.publicKernelVkTreeRoot, + fields.baseRollupVkHash, + fields.mergeRollupVkHash, + ] as const; + } + + toBuffer() { + return serializeToBuffer(...ConstantBaseRollupData.getFields(this)); + } +} + +/** + * Inputs to the base rollup circuit + */ +export class BaseRollupInputs { + constructor( + public kernelData: [PreviousKernelData, PreviousKernelData], + + public startNullifierTreeSnapshot: AppendOnlyTreeSnapshot, + public lowNullifierLeafPreimages: NullifierLeafPreimage[], + public lowNullifierMembershipWitness: MembershipWitness< + typeof NULLIFIER_TREE_HEIGHT + >[], + + public historicPrivateDataTreeRootMembershipWitnesses: [ + MembershipWitness, + MembershipWitness + ], + public historicContractsTreeRootMembershipWitnesses: [ + MembershipWitness, + MembershipWitness + ], + + public constants: ConstantBaseRollupData, + + public proverId: Fr + ) { + assertLength( + this, + "lowNullifierLeafPreimages", + 2 * KERNEL_NEW_NULLIFIERS_LENGTH + ); + assertLength( + this, + "lowNullifierMembershipWitness", + 2 * KERNEL_NEW_NULLIFIERS_LENGTH + ); + } + + static from(fields: FieldsOf): BaseRollupInputs { + return new BaseRollupInputs(...BaseRollupInputs.getFields(fields)); + } + + static getFields(fields: FieldsOf) { + return [ + fields.kernelData, + fields.startNullifierTreeSnapshot, + fields.lowNullifierLeafPreimages, + fields.lowNullifierMembershipWitness, + fields.historicPrivateDataTreeRootMembershipWitnesses, + fields.historicContractsTreeRootMembershipWitnesses, + fields.constants, + fields.proverId, + ] as const; + } + + toBuffer() { + return serializeToBuffer(...BaseRollupInputs.getFields(this)); + } +} + +enum RollupTypes { + Base = 0, + Rollup = 1, +} + +/** + * Output of the base rollup circuit + */ +export class BaseRollupPublicInputs { + constructor( + public rollupType: RollupTypes.Base, + + public endAggregationObject: AggregationObject, + public constants: ConstantBaseRollupData, + + // The only tree root actually updated in this circuit is the nullifier tree, because earlier leaves (of low_nullifiers) must be updated to point to the new nullifiers in this circuit. + public startNullifierTreeSnapshot: AppendOnlyTreeSnapshot, + public endNullifierTreeSnapshots: AppendOnlyTreeSnapshot, + + public newCommitmentsSubtreeRoot: Fr, + public newNullifiersSubtreeRoot: Fr, + public newContractLeavesSubtreeRoot: Fr, + + // Hashes (probably sha256) to make public inputs constant-sized (to then be unpacked on-chain) + public newCommitmentsHash: Fr, + public newNullifiersHash: Fr, + public newL1MsgsHash: Fr, + public newContractDataHash: Fr, + public proverContributionsHash: Fr + ) {} + + static fromBuffer(buffer: Buffer): BaseRollupPublicInputs { + throw new Error("Not implemented"); + } + + /** + * Serialize this as a buffer. + * @returns The buffer. + */ + toBuffer() { + return serializeToBuffer( + this.rollupType.valueOf(), // TODO: Check the size of the enum in cpp land + this.endAggregationObject, + this.constants, + + this.startNullifierTreeSnapshot, + this.endNullifierTreeSnapshots, + + this.newCommitmentsSubtreeRoot, + this.newNullifiersSubtreeRoot, + this.newContractLeavesSubtreeRoot, + + this.newCommitmentsHash, + this.newNullifiersHash, + this.newL1MsgsHash, + this.newContractDataHash, + this.proverContributionsHash + ); + } +} diff --git a/circuits/ts/src/structs/call_context.ts b/circuits/ts/src/structs/call_context.ts new file mode 100644 index 00000000000..14bdb89400f --- /dev/null +++ b/circuits/ts/src/structs/call_context.ts @@ -0,0 +1,31 @@ +import { serializeToBuffer } from "../wasm/serialize.js"; +import { AztecAddress, EthAddress } from "./shared.js"; + +/** + * Call context. + * @see abis/call_context.hpp + */ +export class CallContext { + constructor( + public msgSender: AztecAddress, + public storageContractAddress: AztecAddress, + public portalContractAddress: EthAddress, + public isDelegateCall: boolean, + public isStaticCall: boolean, + public isContractDeployment: boolean + ) {} + /** + * Serialize this as a buffer. + * @returns The buffer. + */ + toBuffer(): Buffer { + return serializeToBuffer( + this.msgSender, + this.storageContractAddress, + this.portalContractAddress.toBuffer(), + this.isDelegateCall, + this.isStaticCall, + this.isContractDeployment + ); + } +} diff --git a/circuits/ts/src/structs/constants.ts b/circuits/ts/src/structs/constants.ts new file mode 100644 index 00000000000..be242ebe1b6 --- /dev/null +++ b/circuits/ts/src/structs/constants.ts @@ -0,0 +1,34 @@ +// See aztec3/constants.hpp +// Copied here for prototyping purposes +// In future: structured serialization? +export const ARGS_LENGTH = 8; +export const RETURN_VALUES_LENGTH = 4; +export const EMITTED_EVENTS_LENGTH = 4; + +export const NEW_COMMITMENTS_LENGTH = 4; +export const NEW_NULLIFIERS_LENGTH = 4; + +export const STATE_TRANSITIONS_LENGTH = 4; +export const STATE_READS_LENGTH = 4; + +export const PRIVATE_CALL_STACK_LENGTH = 4; +export const PUBLIC_CALL_STACK_LENGTH = 4; +export const L1_MSG_STACK_LENGTH = 2; + +export const KERNEL_NEW_COMMITMENTS_LENGTH = 16; +export const KERNEL_NEW_NULLIFIERS_LENGTH = 16; +export const KERNEL_NEW_CONTRACTS_LENGTH = 8; +export const KERNEL_PRIVATE_CALL_STACK_LENGTH = 8; +export const KERNEL_PUBLIC_CALL_STACK_LENGTH = 8; +export const KERNEL_L1_MSG_STACK_LENGTH = 4; +export const KERNEL_OPTIONALLY_REVEALED_DATA_LENGTH = 4; + +export const VK_TREE_HEIGHT = 3; +export const CONTRACT_TREE_HEIGHT = 4; +export const PRIVATE_DATA_TREE_HEIGHT = 8; +export const NULLIFIER_TREE_HEIGHT = 8; + +export const PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT = 8; +export const CONTRACT_TREE_ROOTS_TREE_HEIGHT = 8; + +export const FUNCTION_SELECTOR_NUM_BYTES = 31; diff --git a/circuits/ts/src/structs/function_data.test.ts b/circuits/ts/src/structs/function_data.test.ts new file mode 100644 index 00000000000..01e1c0a3955 --- /dev/null +++ b/circuits/ts/src/structs/function_data.test.ts @@ -0,0 +1,12 @@ +import { expectSerializeToMatchSnapshot } from "../tests/expectSerializeToMatchSnapshot.js"; +import { FunctionData } from "./function_data.js"; + +describe("basic FunctionData serialization", () => { + it(`serializes a trivial FunctionData and prints it`, async () => { + // Test the data case: writing (mostly) sequential numbers + await expectSerializeToMatchSnapshot( + new FunctionData(123, true, true).toBuffer(), + "abis__test_roundtrip_serialize_function_data" + ); + }); +}); diff --git a/circuits/ts/src/structs/function_data.ts b/circuits/ts/src/structs/function_data.ts new file mode 100644 index 00000000000..7db5d1c8da5 --- /dev/null +++ b/circuits/ts/src/structs/function_data.ts @@ -0,0 +1,24 @@ +import { serializeToBuffer } from "../wasm/serialize.js"; + +/** + * Function description for circuit. + * @see abis/function_data.hpp + */ +export class FunctionData { + constructor( + public functionSelector: number, + public isPrivate: true, + public isConstructor: true + ) {} + /** + * Serialize this as a buffer. + * @returns The buffer. + */ + toBuffer(): Buffer { + return serializeToBuffer( + this.functionSelector, + this.isPrivate, + this.isConstructor + ); + } +} diff --git a/circuits/ts/src/structs/kernel.test.ts b/circuits/ts/src/structs/kernel.test.ts new file mode 100644 index 00000000000..3eaa77b7a9e --- /dev/null +++ b/circuits/ts/src/structs/kernel.test.ts @@ -0,0 +1,20 @@ +import { expectSerializeToMatchSnapshot } from "../tests/expectSerializeToMatchSnapshot.js"; +import { makePreviousKernelData } from "../tests/factories.js"; +import { writeGlobalVerifierReferenceString } from "../tests/writeGlobalVerifierReferenceString.js"; +import { CircuitsWasm } from "../wasm/circuits_wasm.js"; + +describe("structs/kernel", () => { + it(`serializes and prints previous_kernel_data`, async () => { + const wasm = await CircuitsWasm.new(); + const previousKernelData = makePreviousKernelData(); + await writeGlobalVerifierReferenceString( + wasm, + /* example circuit size */ 100 + ); + await expectSerializeToMatchSnapshot( + previousKernelData.toBuffer(), + "abis__test_roundtrip_serialize_previous_kernel_data", + wasm + ); + }); +}); diff --git a/circuits/ts/src/structs/kernel.ts b/circuits/ts/src/structs/kernel.ts new file mode 100644 index 00000000000..1529ba75ba5 --- /dev/null +++ b/circuits/ts/src/structs/kernel.ts @@ -0,0 +1,180 @@ +import { assertLength, checkLength } from "../utils/jsUtils.js"; +import { serializeToBuffer } from "../wasm/serialize.js"; +import { + KERNEL_L1_MSG_STACK_LENGTH, + KERNEL_NEW_COMMITMENTS_LENGTH, + KERNEL_NEW_CONTRACTS_LENGTH, + KERNEL_NEW_NULLIFIERS_LENGTH, + KERNEL_PRIVATE_CALL_STACK_LENGTH, + KERNEL_PUBLIC_CALL_STACK_LENGTH, + KERNEL_OPTIONALLY_REVEALED_DATA_LENGTH, + VK_TREE_HEIGHT, + EMITTED_EVENTS_LENGTH, +} from "./constants.js"; +import { FunctionData } from "./function_data.js"; +import { + AggregationObject, + AztecAddress, + EthAddress, + Fr, + UInt8Vector, + UInt32, +} from "./shared.js"; +import { TxContext } from "./tx.js"; +import { VerificationKey } from "./verification_key.js"; + +export class OldTreeRoots { + constructor( + public privateDataTreeRoot: Fr, + public nullifierTreeRoot: Fr, + public contractTreeRoot: Fr, + public privateKernelVkTreeRoot: Fr // future enhancement + ) {} + + toBuffer() { + return serializeToBuffer( + this.privateDataTreeRoot, + this.nullifierTreeRoot, + this.contractTreeRoot, + this.privateKernelVkTreeRoot + ); + } +} + +export class ConstantData { + constructor(public oldTreeRoots: OldTreeRoots, public txContext: TxContext) {} + + toBuffer() { + return serializeToBuffer(this.oldTreeRoots, this.txContext); + } +} + +// Not to be confused with ContractDeploymentData (maybe think of better names) +export class NewContractData { + constructor( + public contractAddress: AztecAddress, + public portalContractAddress: EthAddress, + public functionTreeRoot: Fr + ) {} + + toBuffer() { + return serializeToBuffer( + this.contractAddress, + this.portalContractAddress, + this.functionTreeRoot + ); + } +} + +export class OptionallyRevealedData { + constructor( + public callStackItemHash: Fr, + public functionData: FunctionData, + public emittedEvents: Fr[], + public vkHash: Fr, + public portalContractAddress: EthAddress, + public payFeeFromL1: boolean, + public payFeeFromPublicL2: boolean, + public calledFromL1: boolean, + public calledFromPublicL2: boolean + ) { + assertLength(this, "emittedEvents", EMITTED_EVENTS_LENGTH); + } + + toBuffer() { + return serializeToBuffer( + this.callStackItemHash, + this.functionData, + this.emittedEvents, + this.vkHash, + this.portalContractAddress, + this.payFeeFromL1, + this.payFeeFromPublicL2, + this.calledFromL1, + this.calledFromPublicL2 + ); + } +} + +export class AccumulatedData { + constructor( + public aggregationObject: AggregationObject, // Contains the aggregated proof of all previous kernel iterations + + public privateCallCount: Fr, + + public newCommitments: Fr[], + public newNullifiers: Fr[], + + public privateCallStack: Fr[], + public publicCallStack: Fr[], + public l1MsgStack: Fr[], + + public newContracts: NewContractData[], + + public optionallyRevealedData: OptionallyRevealedData[] + ) { + assertLength(this, "newCommitments", KERNEL_NEW_COMMITMENTS_LENGTH); + assertLength(this, "newNullifiers", KERNEL_NEW_NULLIFIERS_LENGTH); + assertLength(this, "privateCallStack", KERNEL_PRIVATE_CALL_STACK_LENGTH); + assertLength(this, "publicCallStack", KERNEL_PUBLIC_CALL_STACK_LENGTH); + assertLength(this, "l1MsgStack", KERNEL_L1_MSG_STACK_LENGTH); + assertLength(this, "newContracts", KERNEL_NEW_CONTRACTS_LENGTH); + assertLength( + this, + "optionallyRevealedData", + KERNEL_OPTIONALLY_REVEALED_DATA_LENGTH + ); + } + + toBuffer() { + return serializeToBuffer( + this.aggregationObject, + this.privateCallCount, + this.newCommitments, + this.newNullifiers, + this.privateCallStack, + this.publicCallStack, + this.l1MsgStack, + this.newContracts, + this.optionallyRevealedData + ); + } +} + +export class PrivateKernelPublicInputs { + constructor( + public end: AccumulatedData, + public constants: ConstantData, + public isPrivateKernel: true + ) {} + + toBuffer() { + return serializeToBuffer(this.end, this.constants, this.isPrivateKernel); + } +} + +export class PreviousKernelData { + constructor( + public publicInputs: PrivateKernelPublicInputs, + public proof: UInt8Vector, + public vk: VerificationKey, + public vkIndex: UInt32, // the index of the kernel circuit's vk in a big tree of kernel circuit vks + public vkSiblingPath: Fr[] + ) { + checkLength(this.vkSiblingPath, VK_TREE_HEIGHT, "vkSiblingPath"); + } + + /** + * Serialize this as a buffer. + * @returns The buffer. + */ + toBuffer() { + return serializeToBuffer( + this.publicInputs, + this.proof, + this.vk, + this.vkIndex, + this.vkSiblingPath + ); + } +} diff --git a/circuits/ts/src/structs/private_circuit_public_inputs.test.ts b/circuits/ts/src/structs/private_circuit_public_inputs.test.ts new file mode 100644 index 00000000000..54e7750d8e1 --- /dev/null +++ b/circuits/ts/src/structs/private_circuit_public_inputs.test.ts @@ -0,0 +1,70 @@ +import { expectSerializeToMatchSnapshot } from "../tests/expectSerializeToMatchSnapshot.js"; +import { fr } from "../tests/factories.js"; +import { range } from "../utils/jsUtils.js"; +import { numToUInt32BE } from "../wasm/serialize.js"; +import { CallContext } from "./call_context.js"; +import { + ARGS_LENGTH, + EMITTED_EVENTS_LENGTH, + RETURN_VALUES_LENGTH, + NEW_COMMITMENTS_LENGTH, + NEW_NULLIFIERS_LENGTH, + PRIVATE_CALL_STACK_LENGTH, + PUBLIC_CALL_STACK_LENGTH, + L1_MSG_STACK_LENGTH, +} from "./constants.js"; +import { PrivateCircuitPublicInputs } from "./private_circuit_public_inputs.js"; +import { EthAddress, Fr } from "./shared.js"; +import { ContractDeploymentData } from "./tx.js"; + +/** + * Create sequential test data for ContractDeploymentData. + * @returns Test data. + */ +function contractDeploymentData() { + return new ContractDeploymentData( + new Fr(numToUInt32BE(1, 32)), + new Fr(numToUInt32BE(2, 32)), + new Fr(numToUInt32BE(3, 32)), + new EthAddress(numToUInt32BE(4, 20)) + ); +} + +/** + * Create sequential test data for PrivateCircuitPublicInputs. + * @returns Test data. + */ +function privateCircuitPublicInputs() { + return PrivateCircuitPublicInputs.from({ + callContext: new CallContext( + fr(1), + fr(2), + new EthAddress(numToUInt32BE(3, /* eth address is 20 bytes */ 20)), + true, + true, + true + ), + args: range(ARGS_LENGTH, 0x100).map(fr), + emittedEvents: range(EMITTED_EVENTS_LENGTH, 0x200).map(fr), // TODO not in spec + returnValues: range(RETURN_VALUES_LENGTH, 0x300).map(fr), + newCommitments: range(NEW_COMMITMENTS_LENGTH, 0x400).map(fr), + newNullifiers: range(NEW_NULLIFIERS_LENGTH, 0x500).map(fr), + privateCallStack: range(PRIVATE_CALL_STACK_LENGTH, 0x600).map(fr), + publicCallStack: range(PUBLIC_CALL_STACK_LENGTH, 0x700).map(fr), + l1MsgStack: range(L1_MSG_STACK_LENGTH, 0x800).map(fr), + historicContractTreeRoot: new Fr(numToUInt32BE(0x900, 32)), // TODO not in spec + historicPrivateDataTreeRoot: new Fr(numToUInt32BE(0x1000, 32)), + historicPrivateNullifierTreeRoot: new Fr(numToUInt32BE(0x1100, 32)), // TODO not in spec + contractDeploymentData: contractDeploymentData(), + }); +} + +describe("basic PrivateCircuitPublicInputs serialization", () => { + it(`serializes a trivial PrivateCircuitPublicInputs and prints it`, async () => { + // Test the data case: writing (mostly) sequential numbers + await expectSerializeToMatchSnapshot( + privateCircuitPublicInputs().toBuffer(), + "abis__test_roundtrip_serialize_private_circuit_public_inputs" + ); + }); +}); diff --git a/circuits/ts/src/structs/private_circuit_public_inputs.ts b/circuits/ts/src/structs/private_circuit_public_inputs.ts new file mode 100644 index 00000000000..b1e73898397 --- /dev/null +++ b/circuits/ts/src/structs/private_circuit_public_inputs.ts @@ -0,0 +1,89 @@ +import { assertLength, FieldsOf } from "../utils/jsUtils.js"; +import { serializeToBuffer } from "../wasm/serialize.js"; +import { CallContext } from "./call_context.js"; +import { + ARGS_LENGTH, + EMITTED_EVENTS_LENGTH, + L1_MSG_STACK_LENGTH, + NEW_COMMITMENTS_LENGTH, + NEW_NULLIFIERS_LENGTH, + PRIVATE_CALL_STACK_LENGTH, + PUBLIC_CALL_STACK_LENGTH, + RETURN_VALUES_LENGTH, +} from "./constants.js"; +import { Fr } from "./shared.js"; +import { ContractDeploymentData } from "./tx.js"; + +/** + * Public inputs to a private circuit. + * @see abis/private_circuit_public_inputs.hpp. + */ +export class PrivateCircuitPublicInputs { + constructor( + // NOTE: Must have same order as CPP. + public callContext: CallContext, + public args: Fr[], + public returnValues: Fr[], + public emittedEvents: Fr[], + public newCommitments: Fr[], + public newNullifiers: Fr[], + public privateCallStack: Fr[], + public publicCallStack: Fr[], + public l1MsgStack: Fr[], + public historicPrivateDataTreeRoot: Fr, + public historicPrivateNullifierTreeRoot: Fr, + public historicContractTreeRoot: Fr, + public contractDeploymentData: ContractDeploymentData + ) { + assertLength(this, "args", ARGS_LENGTH); + assertLength(this, "returnValues", RETURN_VALUES_LENGTH); + assertLength(this, "emittedEvents", EMITTED_EVENTS_LENGTH); + assertLength(this, "newCommitments", NEW_COMMITMENTS_LENGTH); + assertLength(this, "newNullifiers", NEW_NULLIFIERS_LENGTH); + assertLength(this, "privateCallStack", PRIVATE_CALL_STACK_LENGTH); + assertLength(this, "publicCallStack", PUBLIC_CALL_STACK_LENGTH); + assertLength(this, "l1MsgStack", L1_MSG_STACK_LENGTH); + } + /** + * Create PrivateCircuitPublicInputs from a fields dictionary. + * @param fields - The dictionary. + * @returns A PrivateCircuitPublicInputs object. + */ + static from( + fields: FieldsOf + ): PrivateCircuitPublicInputs { + return new PrivateCircuitPublicInputs( + ...PrivateCircuitPublicInputs.getFields(fields) + ); + } + /** + * Serialize into a field array. Low-level utility. + * @param fields - Object with fields. + * @returns The array. + */ + static getFields(fields: FieldsOf) { + return [ + // NOTE: Must have same order as CPP. + fields.callContext, + fields.args, + fields.returnValues, + fields.emittedEvents, + fields.newCommitments, + fields.newNullifiers, + fields.privateCallStack, + fields.publicCallStack, + fields.l1MsgStack, + fields.historicPrivateDataTreeRoot, + fields.historicPrivateNullifierTreeRoot, + fields.historicContractTreeRoot, + fields.contractDeploymentData, + ] as const; + } + /** + * Serialize this as a buffer. + * @returns The buffer. + */ + toBuffer(): Buffer { + return serializeToBuffer(...PrivateCircuitPublicInputs.getFields(this)); + } +} diff --git a/circuits/ts/src/structs/shared.ts b/circuits/ts/src/structs/shared.ts new file mode 100644 index 00000000000..909f130e323 --- /dev/null +++ b/circuits/ts/src/structs/shared.ts @@ -0,0 +1,191 @@ +import { checkLength, range } from "../utils/jsUtils.js"; +import { + Bufferable, + numToUInt32BE, + serializeToBuffer, +} from "../wasm/serialize.js"; + +abstract class Field { + static SIZE_IN_BYTES = 32; + + private buffer: Buffer; + + constructor(input: Buffer | number) { + if (Buffer.isBuffer(input)) { + if (input.length != Field.SIZE_IN_BYTES) { + throw new Error( + `Unexpected buffer size ${input.length} (expected ${Field.SIZE_IN_BYTES} bytes)` + ); + } + this.buffer = input; + } else { + if (BigInt(input) > this.maxValue()) { + throw new Error( + `Input value ${input} too large (expected ${this.maxValue()})` + ); + } + this.buffer = numToUInt32BE(input, 32); + } + } + + abstract maxValue(): BigInt; + + toString() { + return "0x" + this.buffer.toString("hex"); + } + + toBuffer() { + return this.buffer; + } +} + +export class Fr extends Field { + /** + * Maximum represntable value in a field is the curve prime minus one + * @returns 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000n + */ + maxValue() { + return ( + 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001n - 1n + ); + } +} + +export class Fq extends Field { + /** + * Maximum represntable vaue in a field is the curve prime minus one + * TODO: Find out actual max value for Fq + * @returns 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000n + */ + maxValue() { + return ( + 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001n - 1n + ); + } +} + +/** + * For Ethereum addresses, which must be treated as 32 bytes. + * @param buffer - The 20 byte ethereum address buffer. + * @returns The 32 byte padded buffer. + */ +function pad32(buffer: Buffer) { + // Create a 32-byte Buffer filled with zeros + const paddedBuffer = Buffer.alloc(32); + + // Calculate the padding length + const paddingLength = paddedBuffer.length - buffer.length; + + // Copy the original Buffer into the padded Buffer with an offset + buffer.copy(paddedBuffer, paddingLength); + return paddedBuffer; +} + +export class EthAddress { + static SIZE_IN_BYTES = 20; + + constructor(private buffer: Buffer) { + if (buffer.length != EthAddress.SIZE_IN_BYTES) { + throw new Error( + `Unexpected buffer size ${buffer.length} (expected ${EthAddress.SIZE_IN_BYTES} bytes)` + ); + } + } + + toString() { + return "0x" + this.buffer.toString("hex"); + } + + toBuffer() { + return pad32(this.buffer); + } +} + +export class MembershipWitness { + constructor(pathSize: N, public leafIndex: UInt32, public siblingPath: Fr[]) { + checkLength(this.siblingPath, pathSize, "MembershipWitness.siblingPath"); + } + + toBuffer() { + return serializeToBuffer(this.leafIndex, ...this.siblingPath); + } + + static mock(size: number, start: number) { + return new MembershipWitness( + size, + start, + range(size, start).map((x) => new Fr(numToUInt32BE(x, 32))) + ); + } +} + +export class AggregationObject { + public hasData: false = false; + + public publicInputs: Vector; + public proofWitnessIndices: Vector; + + constructor( + public p0: AffineElement, + public p1: AffineElement, + publicInputsData: Fr[], + proofWitnessIndicesData: UInt32[] + ) { + this.publicInputs = new Vector(publicInputsData); + this.proofWitnessIndices = new Vector(proofWitnessIndicesData); + } + + toBuffer() { + return serializeToBuffer( + this.p0, + this.p1, + this.publicInputs, + this.proofWitnessIndices, + this.hasData + ); + } +} + +export class Vector { + constructor(public items: T[]) {} + + toBuffer() { + return serializeToBuffer(this.items.length, this.items); + } +} + +export class UInt8Vector { + constructor(public buffer: Buffer) {} + + toBuffer() { + return serializeToBuffer(this.buffer.length, this.buffer); + } +} + +export type UInt32 = number; + +// TODO: Define proper type for AztecAddress +export type AztecAddress = Fr; + +/** + * Affine element of a group, composed of two elements in Fq + * cpp/barretenberg/cpp/src/aztec/ecc/groups/affine_element.hpp + * cpp/barretenberg/cpp/src/aztec/ecc/curves/bn254/g1.hpp + */ +export class AffineElement { + constructor(public x: Fq, public y: Fq) {} + + toBuffer() { + return serializeToBuffer(this.x, this.y); + } +} + +/** + * Composer prover type. + */ +export enum ComposerType { + STANDARD = 0, + TURBO = 1, + PLOOKUP = 2, + STANDARD_HONK = 3, +} diff --git a/circuits/ts/src/structs/tx.test.ts b/circuits/ts/src/structs/tx.test.ts new file mode 100644 index 00000000000..9279e619389 --- /dev/null +++ b/circuits/ts/src/structs/tx.test.ts @@ -0,0 +1,12 @@ +import { expectSerializeToMatchSnapshot } from "../tests/expectSerializeToMatchSnapshot.js"; +import { makeTxContext } from "../tests/factories.js"; + +describe("structs/tx", () => { + it(`serializes and prints object`, async () => { + const txContext = makeTxContext(1); + await expectSerializeToMatchSnapshot( + txContext.toBuffer(), + "abis__test_roundtrip_serialize_tx_context" + ); + }); +}); diff --git a/circuits/ts/src/structs/tx.ts b/circuits/ts/src/structs/tx.ts new file mode 100644 index 00000000000..f4086be051a --- /dev/null +++ b/circuits/ts/src/structs/tx.ts @@ -0,0 +1,50 @@ +import { serializeToBuffer } from "../wasm/serialize.js"; +import { EthAddress, Fr } from "./shared.js"; + +/** + * Contract deployment data in a @TxContext. + * cpp/src/aztec3/circuits/abis/contract_deployment_data.hpp + */ +export class ContractDeploymentData { + constructor( + public constructorVkHash: Fr, + public functionTreeRoot: Fr, + public contractAddressSalt: Fr, + public portalContractAddress: EthAddress + ) {} + + toBuffer() { + return serializeToBuffer( + this.constructorVkHash, + this.functionTreeRoot, + this.contractAddressSalt, + this.portalContractAddress + ); + } +} + +/** + * Transaction context. + * @see cpp/src/aztec3/circuits/abis/tx_context.hpp. + */ +export class TxContext { + constructor( + public isFeePaymentTx: false, + public isRebatePaymentTx: false, + public isContractDeployment: true, + public contractDeploymentData: ContractDeploymentData + ) {} + + /** + * Serialize as a buffer. + * @returns The buffer. + */ + toBuffer() { + return serializeToBuffer( + this.isFeePaymentTx, + this.isRebatePaymentTx, + this.isContractDeployment, + this.contractDeploymentData + ); + } +} diff --git a/circuits/ts/src/structs/verification_key.ts b/circuits/ts/src/structs/verification_key.ts new file mode 100644 index 00000000000..7ae8b42b0f5 --- /dev/null +++ b/circuits/ts/src/structs/verification_key.ts @@ -0,0 +1,82 @@ +import { serializeToBuffer } from "../wasm/serialize.js"; +import { ComposerType, Fr } from "./shared.js"; + +/** + * Curve data. + */ +export class G1AffineElement { + constructor(public x: Fr, public y: Fr) {} + /** + * Serialize as a buffer. + * @returns The buffer. + */ + toBuffer() { + return serializeToBuffer(this.x, this.y); + } +} + +/** + * + */ +export class CommitmentMap { + constructor(public record: { [name: string]: G1AffineElement }) {} + /** + * Serialize as a buffer. + * @returns The buffer. + */ + toBuffer() { + const values = Object.entries(this.record); + return serializeToBuffer(values.length, ...values.flat()); + } +} + +/** + * Kate commitment key object for verifying pairing equations. + * @see proof_system/verification_key/verification_key.hpp + */ +export class VerificationKey { + constructor( + /** + * Composer prover type we're using. + */ + public composerType: ComposerType, + /** + * The number of gates in this circuit. + */ + public circuitSize: number, + /** + * The number of public inputs in this circuit. + */ + public numPublicInputs: number, + /** + * The commitments for this circuit. + */ + public commitments: CommitmentMap, + /** + * Contains a recursive proof? + */ + public containsRecursiveProof: boolean, + /** + * Recursion stack. + */ + public recursiveProofPublicInputIndices: number[] + ) {} + + /** + * Serialize as a buffer. + * @returns The buffer. + */ + toBuffer() { + return serializeToBuffer( + this.composerType, + this.circuitSize, + this.numPublicInputs, + this.commitments, + this.containsRecursiveProof, + serializeToBuffer( + this.recursiveProofPublicInputIndices.length, + this.recursiveProofPublicInputIndices + ) + ); + } +} diff --git a/circuits/ts/src/tests/expectSerializeToMatchSnapshot.ts b/circuits/ts/src/tests/expectSerializeToMatchSnapshot.ts new file mode 100644 index 00000000000..dac579b5f0d --- /dev/null +++ b/circuits/ts/src/tests/expectSerializeToMatchSnapshot.ts @@ -0,0 +1,54 @@ +import { CircuitsWasm } from "../wasm/circuits_wasm.js"; +import { uint8ArrayToNum } from "../wasm/serialize.js"; + +/** + * Simplify e.g. 0x0003 into 0x3. + * @param input - The input string, with hex somewhere inside. + * @returns The output string with fixed hex. + */ +function simplifyHexValues(input: string) { + const regex = /0x[\dA-Fa-f]+/g; + const matches = input.match(regex) || []; + const simplifiedMatches = matches.map( + (match) => "0x" + BigInt(match).toString(16) + ); + const result = input.replace(regex, () => simplifiedMatches.shift() || ""); + return result; +} + +/** + * Test utility. Checks a buffer serialize against a snapshot. + * @param inputBuf - Buffer to write. + * @param serializeMethod - Method to use buffer with. + */ +export async function expectSerializeToMatchSnapshot( + inputBuf: Buffer, + serializeMethod: string, + wasm?: CircuitsWasm +) { + wasm = wasm || (await CircuitsWasm.new()); + const inputBufPtr = wasm.call("bbmalloc", inputBuf.length); + wasm.writeMemory(inputBufPtr, inputBuf); + const outputBufSizePtr = wasm.call("bbmalloc", 4); + // Get a string version of our object. As a quick and dirty test, + // we compare a snapshot of its string form to its previous form. + const outputBufPtr = wasm.call( + serializeMethod, + inputBufPtr, + outputBufSizePtr + ); + // Read the size pointer + const outputBufSize = uint8ArrayToNum( + wasm.getMemorySlice(outputBufSizePtr, outputBufSizePtr + 4) + ); + const outputBuf = wasm.getMemorySlice( + outputBufPtr, + outputBufPtr + outputBufSize + ); + const outputStr = simplifyHexValues(Buffer.from(outputBuf).toString("utf-8")); + expect(outputStr).toMatchSnapshot(); + // Free memory + wasm.call("bbfree", outputBufPtr); + wasm.call("bbfree", outputBufSizePtr); + wasm.call("bbfree", inputBufPtr); +} diff --git a/circuits/ts/src/tests/factories.ts b/circuits/ts/src/tests/factories.ts new file mode 100644 index 00000000000..afe6c782a1a --- /dev/null +++ b/circuits/ts/src/tests/factories.ts @@ -0,0 +1,159 @@ +import { + EMITTED_EVENTS_LENGTH, + KERNEL_L1_MSG_STACK_LENGTH, + KERNEL_NEW_COMMITMENTS_LENGTH, + KERNEL_NEW_CONTRACTS_LENGTH, + KERNEL_NEW_NULLIFIERS_LENGTH, + KERNEL_OPTIONALLY_REVEALED_DATA_LENGTH, + KERNEL_PRIVATE_CALL_STACK_LENGTH, + KERNEL_PUBLIC_CALL_STACK_LENGTH, + VK_TREE_HEIGHT, +} from "../structs/constants.js"; +import { FunctionData } from "../structs/function_data.js"; +import { + AccumulatedData, + ConstantData, + NewContractData, + OldTreeRoots, + OptionallyRevealedData, + PreviousKernelData, + PrivateKernelPublicInputs, +} from "../structs/kernel.js"; +import { + AffineElement, + AggregationObject, + ComposerType, + EthAddress, + Fq, + Fr, + MembershipWitness, + UInt8Vector, +} from "../structs/shared.js"; +import { ContractDeploymentData, TxContext } from "../structs/tx.js"; +import { + CommitmentMap, + G1AffineElement, + VerificationKey, +} from "../structs/verification_key.js"; +import { range } from "../utils/jsUtils.js"; +import { numToUInt32BE } from "../wasm/serialize.js"; + +export function makeTxContext(seed: number): TxContext { + const deploymentData = new ContractDeploymentData( + fr(seed), + fr(seed + 1), + fr(seed + 2), + makeEthAddress(seed + 3) + ); + return new TxContext(false, false, true, deploymentData); +} + +export function makeOldTreeRoots(seed: number): OldTreeRoots { + return new OldTreeRoots(fr(seed), fr(seed + 1), fr(seed + 2), fr(seed + 3)); +} + +export function makeConstantData(seed: number = 1): ConstantData { + return new ConstantData(makeOldTreeRoots(seed), makeTxContext(seed + 4)); +} + +export function makeAccumulatedData(seed: number = 1): AccumulatedData { + return new AccumulatedData( + makeAggregationObject(seed), + fr(seed + 12), + range(KERNEL_NEW_COMMITMENTS_LENGTH, seed + 0x100).map(fr), + range(KERNEL_NEW_NULLIFIERS_LENGTH, seed + 0x200).map(fr), + range(KERNEL_PRIVATE_CALL_STACK_LENGTH, seed + 0x300).map(fr), + range(KERNEL_PUBLIC_CALL_STACK_LENGTH, seed + 0x400).map(fr), + range(KERNEL_L1_MSG_STACK_LENGTH, seed + 0x500).map(fr), + range(KERNEL_NEW_CONTRACTS_LENGTH, seed + 0x600).map(makeNewContractData), + range(KERNEL_OPTIONALLY_REVEALED_DATA_LENGTH, seed + 0x700).map( + makeOptionallyRevealedData + ) + ); +} + +export function makeNewContractData(seed: number = 1): NewContractData { + return new NewContractData(fr(seed), makeEthAddress(seed + 1), fr(seed + 2)); +} + +export function makeOptionallyRevealedData( + seed: number = 1 +): OptionallyRevealedData { + return new OptionallyRevealedData( + fr(seed), + new FunctionData(seed + 1, true, true), + range(EMITTED_EVENTS_LENGTH, seed + 0x100).map((x) => fr(x)), + fr(seed + 2), + makeEthAddress(seed + 3), + true, + false, + true, + false + ); +} + +export function makeAggregationObject(seed: number = 1): AggregationObject { + return new AggregationObject( + new AffineElement(new Fq(seed), new Fq(seed + 1)), + new AffineElement(new Fq(seed + 0x100), new Fq(seed + 0x101)), + range(4, seed + 2).map(fr), + range(6, seed + 6) + ); +} + +export function makePrivateKernelPublicInputs( + seed: number = 1 +): PrivateKernelPublicInputs { + return new PrivateKernelPublicInputs( + makeAccumulatedData(seed), + makeConstantData(seed + 0x100), + true + ); +} + +export function makeDynamicSizeBuffer(size: number, fill: number) { + return new UInt8Vector(Buffer.alloc(size, fill)); +} + +export function makeMembershipWitness( + size: number, + start: number +): MembershipWitness { + return new MembershipWitness(size, start, range(size, start).map(fr)); +} + +export function makeVerificationKey(): VerificationKey { + return new VerificationKey( + ComposerType.STANDARD, + 101, // arbitrary + 102, // arbitrary, + new CommitmentMap({ + A: new G1AffineElement(fr(0x200), fr(0x300)), + }), + /* recursive proof */ true, + range(5, 400) + ); +} +export function makePreviousKernelData(seed: number = 1): PreviousKernelData { + return new PreviousKernelData( + makePrivateKernelPublicInputs(seed), + makeDynamicSizeBuffer(16, seed + 0x80), + makeVerificationKey(), + 0x42, + range(VK_TREE_HEIGHT, 0x1000).map(fr) + ); +} + +export function makeEthAddress(seed: number = 1): EthAddress { + return new EthAddress(Buffer.alloc(20, seed)); +} + +/** + * Test only. Easy to identify big endian field serialize. + * @param num - The number. + * @param bufferSize - The buffer size. + * @returns The buffer. + */ +export function fr(n: number) { + return new Fr(numToUInt32BE(n, 32)); +} diff --git a/circuits/ts/src/tests/writeGlobalVerifierReferenceString.ts b/circuits/ts/src/tests/writeGlobalVerifierReferenceString.ts new file mode 100644 index 00000000000..83ecdb505ad --- /dev/null +++ b/circuits/ts/src/tests/writeGlobalVerifierReferenceString.ts @@ -0,0 +1,19 @@ +import { Crs } from "../crs/index.js"; +import { CircuitsWasm } from "../wasm/circuits_wasm.js"; + +/** + * Write to the global VRS in C++. + * @param circuitSize The circuit size. + */ + +export async function writeGlobalVerifierReferenceString( + wasm: CircuitsWasm, + circuitSize: number +) { + const crs: Crs = new Crs(/*example, circuit size = 100*/ 100); + await crs.init(); + const g2DataPtr = wasm.call("bbmalloc", crs.getG2Data().length); + wasm.writeMemory(g2DataPtr, crs.getG2Data()); + wasm.call("abis__set_global_verifier_reference_string", g2DataPtr); + wasm.call("bbfree", g2DataPtr); +} diff --git a/circuits/ts/src/utils/jsUtils.ts b/circuits/ts/src/utils/jsUtils.ts new file mode 100644 index 00000000000..c4256b66238 --- /dev/null +++ b/circuits/ts/src/utils/jsUtils.ts @@ -0,0 +1,56 @@ +/** + * Create an array over an integer range. + * @param n - The number of integers. + * @param offset - The starting number. + * @returns The array of numbers. + */ +export function range(n: number, offset = 0) { + const ret: number[] = []; + for (let i = 0; i < n; i++) { + ret.push(offset + i); + } + return ret; +} + +/** + * Assert a member is a certain length. + * @param obj - An object. + * @param member - A member string. + * @param length - The length. + */ +export function assertLength< + F extends string, + T extends { [f in F]: { length: number } } +>(obj: T, member: F, length: number) { + if (obj[member].length !== length) { + throw new Error( + `Expected ${member} to have length ${length}! Was: ${obj[member].length}` + ); + } +} + +/** + * Asserts a collection has a certain length. + * @param arr Collection to check. + * @param expected Expected length. + * @param label Optional name for the collection to use in the error message. + */ +export function checkLength( + arr: { length: number }, + expected: number, + label: string = "array" +) { + if (arr.length !== expected) { + throw new Error( + `Invalid length for ${label} (got ${arr.length}, expected ${expected})` + ); + } +} + +/** + * Strips methods of a type. + */ +export type FieldsOf = { + // eslint-disable-next-line @typescript-eslint/ban-types + [P in keyof T as T[P] extends Function ? never : P]: T[P]; +}; diff --git a/circuits/ts/src/wasm/aztec3-circuits.wasm b/circuits/ts/src/wasm/aztec3-circuits.wasm new file mode 120000 index 00000000000..c3717f11efa --- /dev/null +++ b/circuits/ts/src/wasm/aztec3-circuits.wasm @@ -0,0 +1 @@ +../../../cpp/build-wasm/bin/aztec3-circuits.wasm \ No newline at end of file diff --git a/circuits/ts/src/wasm/circuits_wasm.test.ts b/circuits/ts/src/wasm/circuits_wasm.test.ts new file mode 100644 index 00000000000..2fb20becf58 --- /dev/null +++ b/circuits/ts/src/wasm/circuits_wasm.test.ts @@ -0,0 +1,30 @@ +import { CircuitsWasm } from "./circuits_wasm.js"; + +describe("basic barretenberg smoke test", () => { + const wasm: CircuitsWasm = new CircuitsWasm(); + + beforeAll(async () => { + await wasm.init(); + }); + + it("should new malloc, transfer and slice mem", () => { + const length = 1024; + const ptr = wasm.call("bbmalloc", length); + const buf = Buffer.alloc(length, 128); + wasm.writeMemory(ptr, buf); + wasm.call("bbfree", ptr); + const result = Buffer.from(wasm.getMemorySlice(ptr, ptr + length)); + expect(result).toStrictEqual(buf); + }); + + it("should use asyncify to do an async callback into js", async () => { + const addr1 = await wasm.asyncCall("test_async_func", 1024 * 1024, 1); + const addr2 = await wasm.asyncCall("test_async_func", 1024 * 1024 * 2, 2); + expect( + wasm.getMemorySlice(addr1, addr1 + 1024 * 1024).every((v) => v === 1) + ).toBe(true); + expect( + wasm.getMemorySlice(addr2, addr2 + 1024 * 1024 * 2).every((v) => v === 2) + ).toBe(true); + }); +}); diff --git a/circuits/ts/src/wasm/circuits_wasm.ts b/circuits/ts/src/wasm/circuits_wasm.ts new file mode 100644 index 00000000000..b3b5c49b43e --- /dev/null +++ b/circuits/ts/src/wasm/circuits_wasm.ts @@ -0,0 +1,176 @@ +import isNode from "detect-node"; + +import { + AsyncCallState, + AsyncFnState, + NodeDataStore, + WasmModule, + WebDataStore, +} from "@aztec/wasm"; +import { readFile } from "fs/promises"; +import { fetch } from "cross-fetch"; +import { dirname } from "path"; +import { fileURLToPath } from "url"; +import { numToUInt32LE } from "./serialize.js"; + +/** + * Get the WASM binary for barretenberg. + * @returns The binary buffer. + */ +export async function fetchCode() { + if (isNode) { + const __dirname = dirname(fileURLToPath(import.meta.url)); + return await readFile(__dirname + "/aztec3-circuits.wasm"); + } else { + const res = await fetch("/aztec3-circuits.wasm"); + return Buffer.from(await res.arrayBuffer()); + } +} + +/** + * A low-level wrapper for an instance of Circuits WASM. + * TODO share code with barretenberg WASM + */ +export class CircuitsWasm { + private store = isNode ? new NodeDataStore() : new WebDataStore(); + private wasm!: WasmModule; + private asyncCallState = new AsyncCallState(); + + /** + * Create and initialize a BarretenbergWasm module. + * @param initial - Initial memory pages. + * @returns The module. + */ + public static async new(initial?: number) { + const barretenberg = new CircuitsWasm(); + await barretenberg.init(initial); + return barretenberg; + } + constructor(private loggerName?: string) {} + + /** + * 20 pages by default. 20*2**16 \> 1mb stack size plus other overheads. + * 8192 maximum by default. 512mb. + * @param initial - Initial memory pages. + * @param maximum - Max memory pages. + */ + public async init(initial = 20, maximum = 8192) { + const { asyncCallState, store } = this; + let wasm: WasmModule; + this.wasm = wasm = new WasmModule( + await fetchCode(), + (module) => ({ + // These are functions implementations for imports we've defined are needed. + // The native C++ build defines these in a module called "env". We must implement TypeScript versions here. + /** + * Log a string from barretenberg. + * @param addr - The string address to log. + */ + logstr(addr: number) { + const str = wasm.getMemoryAsString(addr); + const m = wasm.getMemory(); + const str2 = `${str} (mem: ${(m.length / (1024 * 1024)).toFixed( + 2 + )}MB)`; + wasm.getLogger()(str2); + }, + /** + * Read the data associated with the key located at keyAddr. + * Malloc data within the WASM, copy the data into the WASM, and return the address to the caller. + * The caller is responsible for taking ownership of (and freeing) the memory at the returned address. + */ + // eslint-disable-next-line camelcase + get_data: asyncCallState.wrapImportFn( + (state: AsyncFnState, keyAddr: number, lengthOutAddr: number) => { + const key = wasm.getMemoryAsString(keyAddr); + if (!state.continuation) { + // We are in the initial code path. Start the async fetch of data, return the promise. + wasm.getLogger()(`get_data: key: ${key}`); + return store.get(key); + } else { + const data = state.result as Buffer | undefined; + if (!data) { + wasm.writeMemory(lengthOutAddr, numToUInt32LE(0)); + wasm.getLogger()(`get_data: no data found for: ${key}`); + return 0; + } + const dataAddr = wasm.call("bbmalloc", data.length); + wasm.writeMemory(lengthOutAddr, numToUInt32LE(data.length)); + wasm.writeMemory(dataAddr, data); + wasm.getLogger()( + `get_data: data at ${dataAddr} is ${data.length} bytes.` + ); + return dataAddr; + } + } + ), + // eslint-disable-next-line camelcase + set_data: asyncCallState.wrapImportFn( + ( + state: AsyncFnState, + keyAddr: number, + dataAddr: number, + dataLength: number + ) => { + if (!state.continuation) { + const key = wasm.getMemoryAsString(keyAddr); + wasm.getLogger()( + `set_data: key: ${key} addr: ${dataAddr} length: ${dataLength}` + ); + return store.set( + key, + Buffer.from( + wasm.getMemorySlice(dataAddr, dataAddr + dataLength) + ) + ); + } + } + ), + memory: module.getRawMemory(), + }), + this.loggerName + ); + await wasm.init(initial, maximum); + this.asyncCallState.init(wasm); + } + + /** + * Get a slice of memory between two addresses. + * @param start - The start address. + * @param end - The end address. + * @returns A Uint8Array view of memory. + */ + public getMemorySlice(start: number, end: number) { + return this.wasm.getMemorySlice(start, end); + } + + /** + * Write data into the heap. + * @param arr - The data to write. + * @param offset - The address to write data at. + */ + public writeMemory(offset: number, arr: Uint8Array) { + this.wasm.writeMemory(offset, arr); + } + + /** + * Calls into the WebAssembly. + * @param name - The method name. + * @param args - The arguments to the method. + * @returns The numeric integer or address result. + */ + public call(name: string, ...args: any): number { + return this.wasm.call(name, ...args); + } + + /** + * Uses asyncify to enable async callbacks into js. + * @see https://kripken.github.io/blog/wasm/2019/07/16/asyncify.html + * @param name - The method name. + * @param args - The arguments to the method. + * @returns The numeric integer or address result. + */ + public async asyncCall(name: string, ...args: any): Promise { + return await this.asyncCallState.call(name, ...args); + } +} diff --git a/circuits/ts/src/wasm/index.ts b/circuits/ts/src/wasm/index.ts new file mode 100644 index 00000000000..852760f26c9 --- /dev/null +++ b/circuits/ts/src/wasm/index.ts @@ -0,0 +1 @@ +export { CircuitsWasm } from "./circuits_wasm.js"; diff --git a/circuits/ts/src/wasm/serialize.ts b/circuits/ts/src/wasm/serialize.ts new file mode 100644 index 00000000000..48cbf83b9ee --- /dev/null +++ b/circuits/ts/src/wasm/serialize.ts @@ -0,0 +1,155 @@ +/** + * For serializing an array of fixed length buffers. + * TODO move to foundation pkg. + * @param arr - Array of bufffers. + * @returns The serialized buffers. + */ +export function serializeBufferArrayToVector(arr: Buffer[]) { + const lengthBuf = Buffer.alloc(4); + lengthBuf.writeUInt32BE(arr.length, 0); + return Buffer.concat([lengthBuf, ...arr]); +} + +/** + * Helper function for deserializeArrayFromVector. + */ +type DeserializeFn = ( + buf: Buffer, + offset: number +) => { + /** + * The deserialized type. + */ + elem: T; + /** + * How many bytes to advance by. + */ + adv: number; +}; + +/** + * For deserializing numbers to 32-bit little-endian form. + * TODO move to foundation pkg. + * @param n - The number. + * @returns The endian-corrected number. + */ +export function deserializeArrayFromVector( + deserialize: DeserializeFn, + vector: Buffer, + offset = 0 +) { + let pos = offset; + const size = vector.readUInt32BE(pos); + pos += 4; + const arr = new Array(size); + for (let i = 0; i < size; ++i) { + const { elem, adv } = deserialize(vector, pos); + pos += adv; + arr[i] = elem; + } + return { elem: arr, adv: pos - offset }; +} + +/** + * For serializing numbers to 32 bit little-endian form. + * TODO move to foundation pkg. + * @param n - The number. + * @returns The endian-corrected number. + */ +export function numToUInt32LE(n: number, bufferSize = 4) { + const buf = Buffer.alloc(bufferSize); + buf.writeUInt32LE(n, bufferSize - 4); + return buf; +} + +/** + * For serializing numbers to 32 bit big-endian form. + * TODO move to foundation pkg. + * @param n - The number. + * @returns The endian-corrected number. + */ +export function numToUInt32BE(n: number, bufferSize = 4) { + const buf = Buffer.alloc(bufferSize); + buf.writeUInt32BE(n, bufferSize - 4); + return buf; +} + +/** + * Cast a uint8 array to a number. + * @param array - The uint8 array. + * @returns The number. + */ +export function uint8ArrayToNum(array: Uint8Array) { + const buf = Buffer.from(array); + return buf.readUint32LE(); +} + +/** + * For serializing booleans in structs for calling into wasm. + * @param bool - Value to serialize. + */ +export function boolToBuffer(value: boolean) { + return Buffer.from([value ? 1 : 0]); +} + +/** + * Deserialize the 256-bit number at address `offset`. + * @param buf - The buffer. + * @param offset - The address. + * @returns The derserialized 256-bit field. + */ +export function deserializeField(buf: Buffer, offset = 0) { + const adv = 32; + return { elem: buf.slice(offset, offset + adv), adv }; +} + +/** A type that can be written to a buffer. */ +export type Bufferable = + | boolean + | Buffer + | number + | string + | { + /** + * Serialize to a buffer. + */ + toBuffer: () => Buffer; + } + | Bufferable[]; + +/** + * Serializes a list of objects contiguously for calling into wasm. + * @param objs - Objects to serialize. + * @returns A buffer list with the concatenation of all fields. + */ +export function serializeToBufferArray(...objs: Bufferable[]): Buffer[] { + let ret: Buffer[] = []; + for (const obj of objs) { + if (Array.isArray(obj)) { + // Note: These must match the length of the C++ structs + ret = [...ret, ...serializeToBufferArray(...obj)]; + } else if (Buffer.isBuffer(obj)) { + ret.push(obj); + } else if (typeof obj === "boolean") { + ret.push(boolToBuffer(obj)); + } else if (typeof obj === "number") { + // Note: barretenberg assumes everything is big-endian + ret.push(numToUInt32BE(obj)); // TODO: Are we always passsing numbers as UInt32? + } else if (typeof obj === "string") { + ret.push(numToUInt32BE(obj.length)); + ret.push(Buffer.from(obj)); + } else { + ret.push(obj.toBuffer()); + } + } + return ret; +} + +/** + * Serializes a list of objects contiguously for calling into wasm. + * @param objs - Objects to serialize. + * @returns A single buffer with the concatenation of all fields. + */ +export function serializeToBuffer(...objs: Bufferable[]): Buffer { + return Buffer.concat(serializeToBufferArray(...objs)); +} diff --git a/circuits/ts/tsconfig.dest.json b/circuits/ts/tsconfig.dest.json new file mode 100644 index 00000000000..08a9c1ff256 --- /dev/null +++ b/circuits/ts/tsconfig.dest.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig.json", + "exclude": ["**/*.test.*", "**/fixtures/*"] +} diff --git a/circuits/ts/tsconfig.json b/circuits/ts/tsconfig.json new file mode 100644 index 00000000000..41d839cd823 --- /dev/null +++ b/circuits/ts/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "target": "es2020", + "lib": ["dom", "esnext", "es2017.object"], + "module": "NodeNext", + "strict": true, + "declaration": true, + "noUnusedLocals": true, + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "downlevelIteration": true, + "inlineSourceMap": true, + "declarationMap": true, + "importHelpers": true, + "resolveJsonModule": true, + "composite": true, + "outDir": "dest", + "rootDir": "src", + "tsBuildInfoFile": ".tsbuildinfo" + }, + "include": ["src"] +} diff --git a/circuits/ts/yalc.lock b/circuits/ts/yalc.lock new file mode 100644 index 00000000000..82b8df204c7 --- /dev/null +++ b/circuits/ts/yalc.lock @@ -0,0 +1,22 @@ +{ + "version": "v1", + "packages": { + "@aztec/wasm-worker": { + "signature": "c3f323629c42198a64e1e6969247e19a", + "file": true, + "replaced": "workspace:^" + }, + "@aztec/log": { + "signature": "66820adbe0b16465eb2826f2bc079a5c", + "file": true + }, + "@aztec/eslint-config": { + "signature": "afe1f6648a5208f857a53f99fbc458af", + "file": true + }, + "@aztec/wasm": { + "signature": "49e137843b2fae07ab3c4df8d2229740", + "file": true + } + } +} \ No newline at end of file diff --git a/circuits/ts/yarn.lock b/circuits/ts/yarn.lock new file mode 100644 index 00000000000..1c206c3ef6f --- /dev/null +++ b/circuits/ts/yarn.lock @@ -0,0 +1,3505 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@ampproject/remapping@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d" + integrity sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w== + dependencies: + "@jridgewell/gen-mapping" "^0.1.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@aztec/eslint-config@file:.yalc/@aztec/eslint-config": + version "0.0.0" + dependencies: + "@aztec/eslint-config" "link:../../../.cache/yarn/v6/npm-@aztec-eslint-config-0.0.0-c3fe19f8-d17b-4602-82af-e13372f32c46-1679061380326/yarn-project/eslint-config" + "@aztec/wasm-worker" "link:../../../.cache/yarn/v6/npm-@aztec-eslint-config-0.0.0-c3fe19f8-d17b-4602-82af-e13372f32c46-1679061380326/yarn-project/wasm-worker" + "@typescript-eslint/eslint-plugin" "^5.38.0" + "@typescript-eslint/parser" "^5.38.0" + eslint "^8.21.0" + eslint-config-prettier "^8.5.0" + eslint-plugin-jsdoc "^40.0.0" + eslint-plugin-tsdoc "^0.2.17" + +"@aztec/eslint-config@link:yarn-project/eslint-config": + version "0.0.0" + uid "" + +"@aztec/log@*", "@aztec/log@file:.yalc/@aztec/log": + version "0.0.0" + +"@aztec/wasm-worker@file:.yalc/@aztec/wasm-worker": + version "0.0.0" + dependencies: + "@aztec/log" "*" + "@types/leveldown" "^4.0.3" + detect-node "^2.1.0" + leveldown "^6.1.1" + levelup "^5.1.1" + memdown "^6.1.1" + tslib "^2.4.0" + +"@aztec/wasm-worker@link:yarn-project/wasm-worker": + version "0.0.0" + uid "" + +"@aztec/wasm@file:.yalc/@aztec/wasm": + version "0.0.0" + dependencies: + "@aztec/log" "*" + "@types/leveldown" "^4.0.3" + detect-node "^2.1.0" + leveldown "^6.1.1" + levelup "^5.1.1" + memdown "^6.1.1" + tslib "^2.4.0" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a" + integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== + dependencies: + "@babel/highlight" "^7.18.6" + +"@babel/compat-data@^7.20.5": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.21.0.tgz#c241dc454e5b5917e40d37e525e2f4530c399298" + integrity sha512-gMuZsmsgxk/ENC3O/fRw5QY8A9/uxQbbCEypnLIiYYc/qVJtEV7ouxC3EllIIwNzMqAQee5tanFabWsUOutS7g== + +"@babel/core@^7.11.6", "@babel/core@^7.12.3": + version "7.21.3" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.21.3.tgz#cf1c877284a469da5d1ce1d1e53665253fae712e" + integrity sha512-qIJONzoa/qiHghnm0l1n4i/6IIziDpzqc36FBs4pzMhDUraHqponwJLiAKm1hGLP3OSB/TVNz6rMwVGpwxxySw== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.21.3" + "@babel/helper-compilation-targets" "^7.20.7" + "@babel/helper-module-transforms" "^7.21.2" + "@babel/helpers" "^7.21.0" + "@babel/parser" "^7.21.3" + "@babel/template" "^7.20.7" + "@babel/traverse" "^7.21.3" + "@babel/types" "^7.21.3" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.2" + semver "^6.3.0" + +"@babel/generator@^7.21.3", "@babel/generator@^7.7.2": + version "7.21.3" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.21.3.tgz#232359d0874b392df04045d72ce2fd9bb5045fce" + integrity sha512-QS3iR1GYC/YGUnW7IdggFeN5c1poPUurnGttOV/bZgPGV+izC/D8HnD6DLwod0fsatNyVn1G3EVWMYIF0nHbeA== + dependencies: + "@babel/types" "^7.21.3" + "@jridgewell/gen-mapping" "^0.3.2" + "@jridgewell/trace-mapping" "^0.3.17" + jsesc "^2.5.1" + +"@babel/helper-compilation-targets@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz#a6cd33e93629f5eb473b021aac05df62c4cd09bb" + integrity sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ== + dependencies: + "@babel/compat-data" "^7.20.5" + "@babel/helper-validator-option" "^7.18.6" + browserslist "^4.21.3" + lru-cache "^5.1.1" + semver "^6.3.0" + +"@babel/helper-environment-visitor@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be" + integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg== + +"@babel/helper-function-name@^7.21.0": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz#d552829b10ea9f120969304023cd0645fa00b1b4" + integrity sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg== + dependencies: + "@babel/template" "^7.20.7" + "@babel/types" "^7.21.0" + +"@babel/helper-hoist-variables@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678" + integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-module-imports@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e" + integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-module-transforms@^7.21.2": + version "7.21.2" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz#160caafa4978ac8c00ac66636cb0fa37b024e2d2" + integrity sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ== + dependencies: + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-simple-access" "^7.20.2" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/helper-validator-identifier" "^7.19.1" + "@babel/template" "^7.20.7" + "@babel/traverse" "^7.21.2" + "@babel/types" "^7.21.2" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.19.0", "@babel/helper-plugin-utils@^7.8.0": + version "7.20.2" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz#d1b9000752b18d0877cff85a5c376ce5c3121629" + integrity sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ== + +"@babel/helper-simple-access@^7.20.2": + version "7.20.2" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz#0ab452687fe0c2cfb1e2b9e0015de07fc2d62dd9" + integrity sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA== + dependencies: + "@babel/types" "^7.20.2" + +"@babel/helper-split-export-declaration@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075" + integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-string-parser@^7.19.4": + version "7.19.4" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz#38d3acb654b4701a9b77fb0615a96f775c3a9e63" + integrity sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw== + +"@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1": + version "7.19.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" + integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== + +"@babel/helper-validator-option@^7.18.6": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz#8224c7e13ace4bafdc4004da2cf064ef42673180" + integrity sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ== + +"@babel/helpers@^7.21.0": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.21.0.tgz#9dd184fb5599862037917cdc9eecb84577dc4e7e" + integrity sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA== + dependencies: + "@babel/template" "^7.20.7" + "@babel/traverse" "^7.21.0" + "@babel/types" "^7.21.0" + +"@babel/highlight@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" + integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== + dependencies: + "@babel/helper-validator-identifier" "^7.18.6" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.21.3": + version "7.21.3" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.21.3.tgz#1d285d67a19162ff9daa358d4cb41d50c06220b3" + integrity sha512-lobG0d7aOfQRXh8AyklEAgZGvA4FShxo6xQbUrrT/cNBPUdIDojlokwJsQyCC/eKia7ifqM0yP+2DRZ4WKw2RQ== + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-bigint@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.8.3": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-import-meta@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-jsx@^7.7.2": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz#a8feef63b010150abd97f1649ec296e849943ca0" + integrity sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-syntax-logical-assignment-operators@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-top-level-await@^7.8.3": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.7.2": + version "7.20.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz#4e9a0cfc769c85689b77a2e642d24e9f697fc8c7" + integrity sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.19.0" + +"@babel/template@^7.20.7", "@babel/template@^7.3.3": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.20.7.tgz#a15090c2839a83b02aa996c0b4994005841fd5a8" + integrity sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw== + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + +"@babel/traverse@^7.21.0", "@babel/traverse@^7.21.2", "@babel/traverse@^7.21.3", "@babel/traverse@^7.7.2": + version "7.21.3" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.21.3.tgz#4747c5e7903d224be71f90788b06798331896f67" + integrity sha512-XLyopNeaTancVitYZe2MlUEvgKb6YVVPXzofHgqHijCImG33b/uTurMS488ht/Hbsb2XK3U2BnSTxKVNGV3nGQ== + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.21.3" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-function-name" "^7.21.0" + "@babel/helper-hoist-variables" "^7.18.6" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/parser" "^7.21.3" + "@babel/types" "^7.21.3" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@^7.0.0", "@babel/types@^7.18.6", "@babel/types@^7.20.2", "@babel/types@^7.20.7", "@babel/types@^7.21.0", "@babel/types@^7.21.2", "@babel/types@^7.21.3", "@babel/types@^7.3.0", "@babel/types@^7.3.3": + version "7.21.3" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.21.3.tgz#4865a5357ce40f64e3400b0f3b737dc6d4f64d05" + integrity sha512-sBGdETxC+/M4o/zKC0sl6sjWv62WFR/uzxrJ6uYyMLZOUlPnwzw0tKgVHOXxaAd5l2g8pEDM5RZ495GPQI77kg== + dependencies: + "@babel/helper-string-parser" "^7.19.4" + "@babel/helper-validator-identifier" "^7.19.1" + to-fast-properties "^2.0.0" + +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + +"@cspotcode/source-map-support@^0.8.0": + version "0.8.1" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" + integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== + dependencies: + "@jridgewell/trace-mapping" "0.3.9" + +"@es-joy/jsdoccomment@~0.37.0": + version "0.37.0" + resolved "https://registry.yarnpkg.com/@es-joy/jsdoccomment/-/jsdoccomment-0.37.0.tgz#aaafb4bb6c88288aa7899aef0f3b1b851c36f908" + integrity sha512-hjK0wnsPCYLlF+HHB4R/RbUjOWeLW2SlarB67+Do5WsKILOkmIZvvPJFbtWSmbypxcjpoECLAMzoao0D4Bg5ZQ== + dependencies: + comment-parser "1.3.1" + esquery "^1.4.0" + jsdoc-type-pratt-parser "~4.0.0" + +"@eslint-community/eslint-utils@^4.2.0": + version "4.2.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.2.0.tgz#a831e6e468b4b2b5ae42bf658bea015bf10bc518" + integrity sha512-gB8T4H4DEfX2IV9zGDJPOBgP1e/DbfCPDTtEqUMckpvzS1OYtva8JdFYBqMwYk7xAQ429WGF/UPqn8uQ//h2vQ== + dependencies: + eslint-visitor-keys "^3.3.0" + +"@eslint-community/regexpp@^4.4.0": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.4.0.tgz#3e61c564fcd6b921cb789838631c5ee44df09403" + integrity sha512-A9983Q0LnDGdLPjxyXQ00sbV+K+O+ko2Dr+CZigbHWtX9pNfxlaBkMR8X1CztI73zuEyEBXTVjx7CE+/VSwDiQ== + +"@eslint/eslintrc@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.0.1.tgz#7888fe7ec8f21bc26d646dbd2c11cd776e21192d" + integrity sha512-eFRmABvW2E5Ho6f5fHLqgena46rOj7r7OKHYfLElqcBfGFHHpjBhivyi5+jOEQuSpdc/1phIZJlbC2te+tZNIw== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.5.0" + globals "^13.19.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@eslint/js@8.36.0": + version "8.36.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.36.0.tgz#9837f768c03a1e4a30bd304a64fb8844f0e72efe" + integrity sha512-lxJ9R5ygVm8ZWgYdUweoq5ownDlJ4upvoWmO4eLxBYHdMo+vZ/Rx0EN6MbKWDJOSUGrqJy2Gt+Dyv/VKml0fjg== + +"@humanwhocodes/config-array@^0.11.8": + version "0.11.8" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.8.tgz#03595ac2075a4dc0f191cc2131de14fbd7d410b9" + integrity sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g== + dependencies: + "@humanwhocodes/object-schema" "^1.2.1" + debug "^4.1.1" + minimatch "^3.0.5" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/object-schema@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" + integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== + +"@istanbuljs/load-nyc-config@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== + dependencies: + camelcase "^5.3.1" + find-up "^4.1.0" + get-package-type "^0.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" + +"@istanbuljs/schema@^0.1.2": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jest/console@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-28.1.3.tgz#2030606ec03a18c31803b8a36382762e447655df" + integrity sha512-QPAkP5EwKdK/bxIr6C1I4Vs0rm2nHiANzj/Z5X2JQkrZo6IqvC4ldZ9K95tF0HdidhA8Bo6egxSzUFPYKcEXLw== + dependencies: + "@jest/types" "^28.1.3" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^28.1.3" + jest-util "^28.1.3" + slash "^3.0.0" + +"@jest/core@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-28.1.3.tgz#0ebf2bd39840f1233cd5f2d1e6fc8b71bd5a1ac7" + integrity sha512-CIKBrlaKOzA7YG19BEqCw3SLIsEwjZkeJzf5bdooVnW4bH5cktqe3JX+G2YV1aK5vP8N9na1IGWFzYaTp6k6NA== + dependencies: + "@jest/console" "^28.1.3" + "@jest/reporters" "^28.1.3" + "@jest/test-result" "^28.1.3" + "@jest/transform" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + ci-info "^3.2.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-changed-files "^28.1.3" + jest-config "^28.1.3" + jest-haste-map "^28.1.3" + jest-message-util "^28.1.3" + jest-regex-util "^28.0.2" + jest-resolve "^28.1.3" + jest-resolve-dependencies "^28.1.3" + jest-runner "^28.1.3" + jest-runtime "^28.1.3" + jest-snapshot "^28.1.3" + jest-util "^28.1.3" + jest-validate "^28.1.3" + jest-watcher "^28.1.3" + micromatch "^4.0.4" + pretty-format "^28.1.3" + rimraf "^3.0.0" + slash "^3.0.0" + strip-ansi "^6.0.0" + +"@jest/environment@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-28.1.3.tgz#abed43a6b040a4c24fdcb69eab1f97589b2d663e" + integrity sha512-1bf40cMFTEkKyEf585R9Iz1WayDjHoHqvts0XFYEqyKM3cFWDpeMoqKKTAF9LSYQModPUlh8FKptoM2YcMWAXA== + dependencies: + "@jest/fake-timers" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/node" "*" + jest-mock "^28.1.3" + +"@jest/environment@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.5.0.tgz#9152d56317c1fdb1af389c46640ba74ef0bb4c65" + integrity sha512-5FXw2+wD29YU1d4I2htpRX7jYnAyTRjP2CsXQdo9SAM8g3ifxWPSV0HnClSn71xwctr0U3oZIIH+dtbfmnbXVQ== + dependencies: + "@jest/fake-timers" "^29.5.0" + "@jest/types" "^29.5.0" + "@types/node" "*" + jest-mock "^29.5.0" + +"@jest/expect-utils@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-28.1.3.tgz#58561ce5db7cd253a7edddbc051fb39dda50f525" + integrity sha512-wvbi9LUrHJLn3NlDW6wF2hvIMtd4JUl2QNVrjq+IBSHirgfrR3o9RnVtxzdEGO2n9JyIWwHnLfby5KzqBGg2YA== + dependencies: + jest-get-type "^28.0.2" + +"@jest/expect-utils@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.5.0.tgz#f74fad6b6e20f924582dc8ecbf2cb800fe43a036" + integrity sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg== + dependencies: + jest-get-type "^29.4.3" + +"@jest/expect@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-28.1.3.tgz#9ac57e1d4491baca550f6bdbd232487177ad6a72" + integrity sha512-lzc8CpUbSoE4dqT0U+g1qODQjBRHPpCPXissXD4mS9+sWQdmmpeJ9zSH1rS1HEkrsMN0fb7nKrJ9giAR1d3wBw== + dependencies: + expect "^28.1.3" + jest-snapshot "^28.1.3" + +"@jest/expect@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.5.0.tgz#80952f5316b23c483fbca4363ce822af79c38fba" + integrity sha512-PueDR2HGihN3ciUNGr4uelropW7rqUfTiOn+8u0leg/42UhblPxHkfoh0Ruu3I9Y1962P3u2DY4+h7GVTSVU6g== + dependencies: + expect "^29.5.0" + jest-snapshot "^29.5.0" + +"@jest/fake-timers@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-28.1.3.tgz#230255b3ad0a3d4978f1d06f70685baea91c640e" + integrity sha512-D/wOkL2POHv52h+ok5Oj/1gOG9HSywdoPtFsRCUmlCILXNn5eIWmcnd3DIiWlJnpGvQtmajqBP95Ei0EimxfLw== + dependencies: + "@jest/types" "^28.1.3" + "@sinonjs/fake-timers" "^9.1.2" + "@types/node" "*" + jest-message-util "^28.1.3" + jest-mock "^28.1.3" + jest-util "^28.1.3" + +"@jest/fake-timers@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.5.0.tgz#d4d09ec3286b3d90c60bdcd66ed28d35f1b4dc2c" + integrity sha512-9ARvuAAQcBwDAqOnglWq2zwNIRUDtk/SCkp/ToGEhFv5r86K21l+VEs0qNTaXtyiY0lEePl3kylijSYJQqdbDg== + dependencies: + "@jest/types" "^29.5.0" + "@sinonjs/fake-timers" "^10.0.2" + "@types/node" "*" + jest-message-util "^29.5.0" + jest-mock "^29.5.0" + jest-util "^29.5.0" + +"@jest/globals@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-28.1.3.tgz#a601d78ddc5fdef542728309894895b4a42dc333" + integrity sha512-XFU4P4phyryCXu1pbcqMO0GSQcYe1IsalYCDzRNyhetyeyxMcIxa11qPNDpVNLeretItNqEmYYQn1UYz/5x1NA== + dependencies: + "@jest/environment" "^28.1.3" + "@jest/expect" "^28.1.3" + "@jest/types" "^28.1.3" + +"@jest/globals@^29.4.3": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.5.0.tgz#6166c0bfc374c58268677539d0c181f9c1833298" + integrity sha512-S02y0qMWGihdzNbUiqSAiKSpSozSuHX5UYc7QbnHP+D9Lyw8DgGGCinrN9uSuHPeKgSSzvPom2q1nAtBvUsvPQ== + dependencies: + "@jest/environment" "^29.5.0" + "@jest/expect" "^29.5.0" + "@jest/types" "^29.5.0" + jest-mock "^29.5.0" + +"@jest/reporters@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-28.1.3.tgz#9adf6d265edafc5fc4a434cfb31e2df5a67a369a" + integrity sha512-JuAy7wkxQZVNU/V6g9xKzCGC5LVXx9FDcABKsSXp5MiKPEE2144a/vXTEDoyzjUpZKfVwp08Wqg5A4WfTMAzjg== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^28.1.3" + "@jest/test-result" "^28.1.3" + "@jest/transform" "^28.1.3" + "@jest/types" "^28.1.3" + "@jridgewell/trace-mapping" "^0.3.13" + "@types/node" "*" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^5.1.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.1.3" + jest-message-util "^28.1.3" + jest-util "^28.1.3" + jest-worker "^28.1.3" + slash "^3.0.0" + string-length "^4.0.1" + strip-ansi "^6.0.0" + terminal-link "^2.0.0" + v8-to-istanbul "^9.0.1" + +"@jest/schemas@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-28.1.3.tgz#ad8b86a66f11f33619e3d7e1dcddd7f2d40ff905" + integrity sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg== + dependencies: + "@sinclair/typebox" "^0.24.1" + +"@jest/schemas@^29.4.3": + version "29.4.3" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.4.3.tgz#39cf1b8469afc40b6f5a2baaa146e332c4151788" + integrity sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg== + dependencies: + "@sinclair/typebox" "^0.25.16" + +"@jest/source-map@^28.1.2": + version "28.1.2" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-28.1.2.tgz#7fe832b172b497d6663cdff6c13b0a920e139e24" + integrity sha512-cV8Lx3BeStJb8ipPHnqVw/IM2VCMWO3crWZzYodSIkxXnRcXJipCdx1JCK0K5MsJJouZQTH73mzf4vgxRaH9ww== + dependencies: + "@jridgewell/trace-mapping" "^0.3.13" + callsites "^3.0.0" + graceful-fs "^4.2.9" + +"@jest/test-result@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-28.1.3.tgz#5eae945fd9f4b8fcfce74d239e6f725b6bf076c5" + integrity sha512-kZAkxnSE+FqE8YjW8gNuoVkkC9I7S1qmenl8sGcDOLropASP+BkcGKwhXoyqQuGOGeYY0y/ixjrd/iERpEXHNg== + dependencies: + "@jest/console" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + +"@jest/test-sequencer@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-28.1.3.tgz#9d0c283d906ac599c74bde464bc0d7e6a82886c3" + integrity sha512-NIMPEqqa59MWnDi1kvXXpYbqsfQmSJsIbnd85mdVGkiDfQ9WQQTXOLsvISUfonmnBT+w85WEgneCigEEdHDFxw== + dependencies: + "@jest/test-result" "^28.1.3" + graceful-fs "^4.2.9" + jest-haste-map "^28.1.3" + slash "^3.0.0" + +"@jest/transform@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-28.1.3.tgz#59d8098e50ab07950e0f2fc0fc7ec462371281b0" + integrity sha512-u5dT5di+oFI6hfcLOHGTAfmUxFRrjK+vnaP0kkVow9Md/M7V/MxqQMOz/VV25UZO8pzeA9PjfTpOu6BDuwSPQA== + dependencies: + "@babel/core" "^7.11.6" + "@jest/types" "^28.1.3" + "@jridgewell/trace-mapping" "^0.3.13" + babel-plugin-istanbul "^6.1.1" + chalk "^4.0.0" + convert-source-map "^1.4.0" + fast-json-stable-stringify "^2.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^28.1.3" + jest-regex-util "^28.0.2" + jest-util "^28.1.3" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" + write-file-atomic "^4.0.1" + +"@jest/transform@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.5.0.tgz#cf9c872d0965f0cbd32f1458aa44a2b1988b00f9" + integrity sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw== + dependencies: + "@babel/core" "^7.11.6" + "@jest/types" "^29.5.0" + "@jridgewell/trace-mapping" "^0.3.15" + babel-plugin-istanbul "^6.1.1" + chalk "^4.0.0" + convert-source-map "^2.0.0" + fast-json-stable-stringify "^2.1.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.5.0" + jest-regex-util "^29.4.3" + jest-util "^29.5.0" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" + write-file-atomic "^4.0.2" + +"@jest/types@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-28.1.3.tgz#b05de80996ff12512bc5ceb1d208285a7d11748b" + integrity sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ== + dependencies: + "@jest/schemas" "^28.1.3" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" + +"@jest/types@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.5.0.tgz#f59ef9b031ced83047c67032700d8c807d6e1593" + integrity sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog== + dependencies: + "@jest/schemas" "^29.4.3" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" + +"@jridgewell/gen-mapping@^0.1.0": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz#e5d2e450306a9491e3bd77e323e38d7aff315996" + integrity sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w== + dependencies: + "@jridgewell/set-array" "^1.0.0" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@jridgewell/gen-mapping@^0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" + integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@3.1.0", "@jridgewell/resolve-uri@^3.0.3": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" + integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== + +"@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + +"@jridgewell/sourcemap-codec@1.4.14", "@jridgewell/sourcemap-codec@^1.4.10": + version "1.4.14" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" + integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== + +"@jridgewell/trace-mapping@0.3.9": + version "0.3.9" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" + integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.13", "@jridgewell/trace-mapping@^0.3.15", "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": + version "0.3.17" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz#793041277af9073b0951a7fe0f0d8c4c98c36985" + integrity sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g== + dependencies: + "@jridgewell/resolve-uri" "3.1.0" + "@jridgewell/sourcemap-codec" "1.4.14" + +"@microsoft/tsdoc-config@0.16.2": + version "0.16.2" + resolved "https://registry.yarnpkg.com/@microsoft/tsdoc-config/-/tsdoc-config-0.16.2.tgz#b786bb4ead00d54f53839a458ce626c8548d3adf" + integrity sha512-OGiIzzoBLgWWR0UdRJX98oYO+XKGf7tiK4Zk6tQ/E4IJqGCe7dvkTvgDZV5cFJUzLGDOjeAXrnZoA6QkVySuxw== + dependencies: + "@microsoft/tsdoc" "0.14.2" + ajv "~6.12.6" + jju "~1.4.0" + resolve "~1.19.0" + +"@microsoft/tsdoc@0.14.2": + version "0.14.2" + resolved "https://registry.yarnpkg.com/@microsoft/tsdoc/-/tsdoc-0.14.2.tgz#c3ec604a0b54b9a9b87e9735dfc59e1a5da6a5fb" + integrity sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug== + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@rushstack/eslint-patch@^1.1.4": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz#8be36a1f66f3265389e90b5f9c9962146758f728" + integrity sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg== + +"@sinclair/typebox@^0.24.1": + version "0.24.51" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.24.51.tgz#645f33fe4e02defe26f2f5c0410e1c094eac7f5f" + integrity sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA== + +"@sinclair/typebox@^0.25.16": + version "0.25.24" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.25.24.tgz#8c7688559979f7079aacaf31aa881c3aa410b718" + integrity sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ== + +"@sinonjs/commons@^1.7.0": + version "1.8.6" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.6.tgz#80c516a4dc264c2a69115e7578d62581ff455ed9" + integrity sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ== + dependencies: + type-detect "4.0.8" + +"@sinonjs/commons@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-2.0.0.tgz#fd4ca5b063554307e8327b4564bd56d3b73924a3" + integrity sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^10.0.2": + version "10.0.2" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-10.0.2.tgz#d10549ed1f423d80639c528b6c7f5a1017747d0c" + integrity sha512-SwUDyjWnah1AaNl7kxsa7cfLhlTYoiyhDAIgyh+El30YvXs/o7OLXpYH88Zdhyx9JExKrmHDJ+10bwIcY80Jmw== + dependencies: + "@sinonjs/commons" "^2.0.0" + +"@sinonjs/fake-timers@^9.1.2": + version "9.1.2" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz#4eaab737fab77332ab132d396a3c0d364bd0ea8c" + integrity sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw== + dependencies: + "@sinonjs/commons" "^1.7.0" + +"@tsconfig/node10@^1.0.7": + version "1.0.9" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2" + integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA== + +"@tsconfig/node12@^1.0.7": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" + integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== + +"@tsconfig/node14@^1.0.0": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" + integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== + +"@tsconfig/node16@^1.0.2": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.3.tgz#472eaab5f15c1ffdd7f8628bd4c4f753995ec79e" + integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ== + +"@types/abstract-leveldown@*": + version "7.2.1" + resolved "https://registry.yarnpkg.com/@types/abstract-leveldown/-/abstract-leveldown-7.2.1.tgz#bb16403c17754b0c4d5772d71d03b924a03d4c80" + integrity sha512-YK8irIC+eMrrmtGx0H4ISn9GgzLd9dojZWJaMbjp1YHLl2VqqNFBNrL5Q3KjGf4VE3sf/4hmq6EhQZ7kZp1NoQ== + +"@types/babel__core@^7.1.14": + version "7.20.0" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.0.tgz#61bc5a4cae505ce98e1e36c5445e4bee060d8891" + integrity sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ== + dependencies: + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.4.tgz#1f20ce4c5b1990b37900b63f050182d28c2439b7" + integrity sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.1" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.1.tgz#3d1a48fd9d6c0edfd56f2ff578daed48f36c8969" + integrity sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": + version "7.18.3" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.18.3.tgz#dfc508a85781e5698d5b33443416b6268c4b3e8d" + integrity sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w== + dependencies: + "@babel/types" "^7.3.0" + +"@types/detect-node@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@types/detect-node/-/detect-node-2.0.0.tgz#696e024ddd105c72bbc6a2e3f97902a2886f2c3f" + integrity sha512-+BozjlbPTACYITf1PWf62HLtDV79HbmZosUN1mv1gGrnjDCRwBXkDKka1sf6YQJvspmfPXVcy+X6tFW62KteeQ== + +"@types/graceful-fs@^4.1.3": + version "4.1.6" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.6.tgz#e14b2576a1c25026b7f02ede1de3b84c3a1efeae" + integrity sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw== + dependencies: + "@types/node" "*" + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44" + integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g== + +"@types/istanbul-lib-report@*": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" + integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" + integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/jest@^29.4.0": + version "29.4.4" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.4.4.tgz#ba257bd7b1876dec9e0b4fb82fa60eec5505e5f1" + integrity sha512-qezb65VIH7X1wobSnd6Lvdve7PXSyQRa3dljTkhTtDhi603RvHQCshSlJcuyMLHJpeHgY3NKwvDJWxMOOHxGDQ== + dependencies: + expect "^29.0.0" + pretty-format "^29.0.0" + +"@types/json-schema@^7.0.9": + version "7.0.11" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" + integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== + +"@types/leveldown@^4.0.3": + version "4.0.3" + resolved "https://registry.yarnpkg.com/@types/leveldown/-/leveldown-4.0.3.tgz#4b868fd747808d378df6ffb27de7f889cae46aad" + integrity sha512-fzIXOuUCSZQKkRadWhURwu6mMYbfqi/nRDA+yBwz8kj7AK/L7L//u6A0MqSv0gsilzo7N/5+FlZOx8G6m03EVQ== + dependencies: + "@types/abstract-leveldown" "*" + "@types/node" "*" + +"@types/node@*", "@types/node@^18.7.23": + version "18.15.3" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.3.tgz#f0b991c32cfc6a4e7f3399d6cb4b8cf9a0315014" + integrity sha512-p6ua9zBxz5otCmbpb5D3U4B5Nanw6Pk3PPyX05xnxbB/fRv71N7CPmORg7uAD5P70T0xmx1pzAx/FUfa5X+3cw== + +"@types/prettier@^2.1.5": + version "2.7.2" + resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.2.tgz#6c2324641cc4ba050a8c710b2b251b377581fbf0" + integrity sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg== + +"@types/semver@^7.3.12": + version "7.3.13" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.13.tgz#da4bfd73f49bd541d28920ab0e2bf0ee80f71c91" + integrity sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw== + +"@types/stack-utils@^2.0.0": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" + integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== + +"@types/yargs-parser@*": + version "21.0.0" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" + integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA== + +"@types/yargs@^17.0.8": + version "17.0.22" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.22.tgz#7dd37697691b5f17d020f3c63e7a45971ff71e9a" + integrity sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g== + dependencies: + "@types/yargs-parser" "*" + +"@typescript-eslint/eslint-plugin@^5.38.0", "@typescript-eslint/eslint-plugin@^5.54.1": + version "5.55.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.55.0.tgz#bc2400c3a23305e8c9a9c04aa40933868aaaeb47" + integrity sha512-IZGc50rtbjk+xp5YQoJvmMPmJEYoC53SiKPXyqWfv15XoD2Y5Kju6zN0DwlmaGJp1Iw33JsWJcQ7nw0lGCGjVg== + dependencies: + "@eslint-community/regexpp" "^4.4.0" + "@typescript-eslint/scope-manager" "5.55.0" + "@typescript-eslint/type-utils" "5.55.0" + "@typescript-eslint/utils" "5.55.0" + debug "^4.3.4" + grapheme-splitter "^1.0.4" + ignore "^5.2.0" + natural-compare-lite "^1.4.0" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/parser@^5.38.0", "@typescript-eslint/parser@^5.54.1": + version "5.55.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.55.0.tgz#8c96a0b6529708ace1dcfa60f5e6aec0f5ed2262" + integrity sha512-ppvmeF7hvdhUUZWSd2EEWfzcFkjJzgNQzVST22nzg958CR+sphy8A6K7LXQZd6V75m1VKjp+J4g/PCEfSCmzhw== + dependencies: + "@typescript-eslint/scope-manager" "5.55.0" + "@typescript-eslint/types" "5.55.0" + "@typescript-eslint/typescript-estree" "5.55.0" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@5.55.0": + version "5.55.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.55.0.tgz#e863bab4d4183ddce79967fe10ceb6c829791210" + integrity sha512-OK+cIO1ZGhJYNCL//a3ROpsd83psf4dUJ4j7pdNVzd5DmIk+ffkuUIX2vcZQbEW/IR41DYsfJTB19tpCboxQuw== + dependencies: + "@typescript-eslint/types" "5.55.0" + "@typescript-eslint/visitor-keys" "5.55.0" + +"@typescript-eslint/type-utils@5.55.0": + version "5.55.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.55.0.tgz#74bf0233523f874738677bb73cb58094210e01e9" + integrity sha512-ObqxBgHIXj8rBNm0yh8oORFrICcJuZPZTqtAFh0oZQyr5DnAHZWfyw54RwpEEH+fD8suZaI0YxvWu5tYE/WswA== + dependencies: + "@typescript-eslint/typescript-estree" "5.55.0" + "@typescript-eslint/utils" "5.55.0" + debug "^4.3.4" + tsutils "^3.21.0" + +"@typescript-eslint/types@5.55.0": + version "5.55.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.55.0.tgz#9830f8d3bcbecf59d12f821e5bc6960baaed41fd" + integrity sha512-M4iRh4AG1ChrOL6Y+mETEKGeDnT7Sparn6fhZ5LtVJF1909D5O4uqK+C5NPbLmpfZ0XIIxCdwzKiijpZUOvOug== + +"@typescript-eslint/typescript-estree@5.55.0": + version "5.55.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.55.0.tgz#8db7c8e47ecc03d49b05362b8db6f1345ee7b575" + integrity sha512-I7X4A9ovA8gdpWMpr7b1BN9eEbvlEtWhQvpxp/yogt48fy9Lj3iE3ild/1H3jKBBIYj5YYJmS2+9ystVhC7eaQ== + dependencies: + "@typescript-eslint/types" "5.55.0" + "@typescript-eslint/visitor-keys" "5.55.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/utils@5.55.0": + version "5.55.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.55.0.tgz#34e97322e7ae5b901e7a870aabb01dad90023341" + integrity sha512-FkW+i2pQKcpDC3AY6DU54yl8Lfl14FVGYDgBTyGKB75cCwV3KpkpTMFi9d9j2WAJ4271LR2HeC5SEWF/CZmmfw== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@types/json-schema" "^7.0.9" + "@types/semver" "^7.3.12" + "@typescript-eslint/scope-manager" "5.55.0" + "@typescript-eslint/types" "5.55.0" + "@typescript-eslint/typescript-estree" "5.55.0" + eslint-scope "^5.1.1" + semver "^7.3.7" + +"@typescript-eslint/visitor-keys@5.55.0": + version "5.55.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.55.0.tgz#01ad414fca8367706d76cdb94adf788dc5b664a2" + integrity sha512-q2dlHHwWgirKh1D3acnuApXG+VNXpEY5/AwRxDVuEQpxWaB0jCDe0jFMVMALJ3ebSfuOVE8/rMS+9ZOYGg1GWw== + dependencies: + "@typescript-eslint/types" "5.55.0" + eslint-visitor-keys "^3.3.0" + +abstract-leveldown@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-7.2.0.tgz#08d19d4e26fb5be426f7a57004851b39e1795a2e" + integrity sha512-DnhQwcFEaYsvYDnACLZhMmCWd3rkOeEvglpa4q5i/5Jlm3UIsWaxVzuXvDLFCSCWRO3yy2/+V/G7FusFgejnfQ== + dependencies: + buffer "^6.0.3" + catering "^2.0.0" + is-buffer "^2.0.5" + level-concat-iterator "^3.0.0" + level-supports "^2.0.1" + queue-microtask "^1.2.3" + +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn-walk@^8.1.1: + version "8.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" + integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== + +acorn@^8.4.1, acorn@^8.8.0: + version "8.8.2" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a" + integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== + +ajv@^6.10.0, ajv@^6.12.4, ajv@~6.12.6: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-escapes@^4.2.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + +anymatch@^3.0.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +arg@^4.1.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +babel-jest@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-28.1.3.tgz#c1187258197c099072156a0a121c11ee1e3917d5" + integrity sha512-epUaPOEWMk3cWX0M/sPvCHHCe9fMFAa/9hXEgKP8nFfNl/jlGkE9ucq9NqkZGXLDduCJYS0UvSlPUwC0S+rH6Q== + dependencies: + "@jest/transform" "^28.1.3" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^28.1.3" + chalk "^4.0.0" + graceful-fs "^4.2.9" + slash "^3.0.0" + +babel-plugin-istanbul@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" + integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-instrument "^5.0.4" + test-exclude "^6.0.0" + +babel-plugin-jest-hoist@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-28.1.3.tgz#1952c4d0ea50f2d6d794353762278d1d8cca3fbe" + integrity sha512-Ys3tUKAmfnkRUpPdpa98eYrAR0nV+sSFUZZEGuQ2EbFd1y4SOLtD5QDNHAq+bb9a+bbXvYQC4b+ID/THIMcU6Q== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.1.14" + "@types/babel__traverse" "^7.0.6" + +babel-preset-current-node-syntax@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" + integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== + dependencies: + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-bigint" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.8.3" + "@babel/plugin-syntax-import-meta" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.8.3" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-top-level-await" "^7.8.3" + +babel-preset-jest@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-28.1.3.tgz#5dfc20b99abed5db994406c2b9ab94c73aaa419d" + integrity sha512-L+fupJvlWAHbQfn74coNX3zf60LXMJsezNvvx8eIh7iOR1luJ1poxYgQk1F8PYtNq/6QODDHCqsSnTFSWC491A== + dependencies: + babel-plugin-jest-hoist "^28.1.3" + babel-preset-current-node-syntax "^1.0.0" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +browserslist@^4.21.3: + version "4.21.5" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.5.tgz#75c5dae60063ee641f977e00edd3cfb2fb7af6a7" + integrity sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w== + dependencies: + caniuse-lite "^1.0.30001449" + electron-to-chromium "^1.4.284" + node-releases "^2.0.8" + update-browserslist-db "^1.0.10" + +bs-logger@0.x: + version "0.2.6" + resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" + integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== + dependencies: + fast-json-stable-stringify "2.x" + +bser@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +buffer@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" + integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.2.1" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^6.2.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +caniuse-lite@^1.0.30001449: + version "1.0.30001466" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001466.tgz#c1e6197c540392e09709ecaa9e3e403428c53375" + integrity sha512-ewtFBSfWjEmxUgNBSZItFSmVtvk9zkwkl1OfRZlKA8slltRN+/C/tuGVrF9styXkN36Yu3+SeJ1qkXxDEyNZ5w== + +catering@^2.0.0, catering@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/catering/-/catering-2.1.1.tgz#66acba06ed5ee28d5286133982a927de9a04b510" + integrity sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w== + +chalk@^2.0.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.0.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +char-regex@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" + integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== + +ci-info@^3.2.0: + version "3.8.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.8.0.tgz#81408265a5380c929f0bc665d62256628ce9ef91" + integrity sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw== + +cjs-module-lexer@^1.0.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40" + integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA== + +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== + +collect-v8-coverage@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" + integrity sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg== + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +comment-parser@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/comment-parser/-/comment-parser-1.3.1.tgz#3d7ea3adaf9345594aedee6563f422348f165c1b" + integrity sha512-B52sN2VNghyq5ofvUsqZjmk6YkihBX5vMSChmSK9v4ShjKf3Vk5Xcmgpw4o+iIgtrnM/u5FiMpz9VKb8lpBveA== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" + integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== + +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + +create-require@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" + integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== + +cross-fetch@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f" + integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw== + dependencies: + node-fetch "2.6.7" + +cross-spawn@^7.0.2, cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +dedent@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" + integrity sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA== + +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +deepmerge@^4.2.2: + version "4.3.0" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.0.tgz#65491893ec47756d44719ae520e0e2609233b59b" + integrity sha512-z2wJZXrmeHdvYJp/Ux55wIjqo81G5Bp4c+oELTW+7ar6SogWHajt5a9gO3s3IDaGSAXjDk0vlQKN3rms8ab3og== + +deferred-leveldown@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/deferred-leveldown/-/deferred-leveldown-7.0.0.tgz#39802715fda6ec06d0159a8b28bd1c7e2b1cf0bf" + integrity sha512-QKN8NtuS3BC6m0B8vAnBls44tX1WXAFATUsJlruyAYbZpysWV3siH6o/i3g9DCHauzodksO60bdj5NazNbjCmg== + dependencies: + abstract-leveldown "^7.2.0" + inherits "^2.0.3" + +detect-newline@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" + integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== + +detect-node@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" + integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== + +diff-sequences@^28.1.1: + version "28.1.1" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-28.1.1.tgz#9989dc731266dc2903457a70e996f3a041913ac6" + integrity sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw== + +diff-sequences@^29.4.3: + version "29.4.3" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.4.3.tgz#9314bc1fabe09267ffeca9cbafc457d8499a13f2" + integrity sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA== + +diff@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +electron-to-chromium@^1.4.284: + version "1.4.332" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.332.tgz#b981fcf61587abe03c24b301b2cfbdcc2b70e8a5" + integrity sha512-c1Vbv5tuUlBFp0mb3mCIjw+REEsgthRgNE8BlbEDKmvzb8rxjcVki6OkQP83vLN34s0XCxpSkq7AZNep1a6xhw== + +emittery@^0.10.2: + version "0.10.2" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.10.2.tgz#902eec8aedb8c41938c46e9385e9db7e03182933" + integrity sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint-config-prettier@^8.5.0: + version "8.7.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.7.0.tgz#f1cc58a8afebc50980bd53475451df146c13182d" + integrity sha512-HHVXLSlVUhMSmyW4ZzEuvjpwqamgmlfkutD53cYXLikh4pt/modINRcCIApJ84czDxM4GZInwUrromsDdTImTA== + +eslint-plugin-jsdoc@^40.0.0: + version "40.0.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-40.0.3.tgz#b4d88db43d7b038cad7eee5a78d2b46c5f5d5958" + integrity sha512-4QXkuo4yVFJWsZIvdgFMBs6ZWVGDBZGO06kcgM060/96G8+6Fr7JZWy+Wg0I1C0+qxxfpB+aIepdE29vYxX2kA== + dependencies: + "@es-joy/jsdoccomment" "~0.37.0" + comment-parser "1.3.1" + debug "^4.3.4" + escape-string-regexp "^4.0.0" + esquery "^1.5.0" + semver "^7.3.8" + spdx-expression-parse "^3.0.1" + +eslint-plugin-tsdoc@^0.2.17: + version "0.2.17" + resolved "https://registry.yarnpkg.com/eslint-plugin-tsdoc/-/eslint-plugin-tsdoc-0.2.17.tgz#27789495bbd8778abbf92db1707fec2ed3dfe281" + integrity sha512-xRmVi7Zx44lOBuYqG8vzTXuL6IdGOeF9nHX17bjJ8+VE6fsxpdGem0/SBTmAwgYMKYB1WBkqRJVQ+n8GK041pA== + dependencies: + "@microsoft/tsdoc" "0.14.2" + "@microsoft/tsdoc-config" "0.16.2" + +eslint-scope@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +eslint-scope@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642" + integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-visitor-keys@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" + integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== + +eslint@^8.21.0, eslint@^8.35.0: + version "8.36.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.36.0.tgz#1bd72202200a5492f91803b113fb8a83b11285cf" + integrity sha512-Y956lmS7vDqomxlaaQAHVmeb4tNMp2FWIvU/RnU5BD3IKMD/MJPr76xdyr68P8tV1iNMvN2mRK0yy3c+UjL+bw== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.4.0" + "@eslint/eslintrc" "^2.0.1" + "@eslint/js" "8.36.0" + "@humanwhocodes/config-array" "^0.11.8" + "@humanwhocodes/module-importer" "^1.0.1" + "@nodelib/fs.walk" "^1.2.8" + ajv "^6.10.0" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + doctrine "^3.0.0" + escape-string-regexp "^4.0.0" + eslint-scope "^7.1.1" + eslint-visitor-keys "^3.3.0" + espree "^9.5.0" + esquery "^1.4.2" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + find-up "^5.0.0" + glob-parent "^6.0.2" + globals "^13.19.0" + grapheme-splitter "^1.0.4" + ignore "^5.2.0" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + is-path-inside "^3.0.3" + js-sdsl "^4.1.4" + js-yaml "^4.1.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.1" + strip-ansi "^6.0.1" + strip-json-comments "^3.1.0" + text-table "^0.2.0" + +espree@^9.5.0: + version "9.5.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.5.0.tgz#3646d4e3f58907464edba852fa047e6a27bdf113" + integrity sha512-JPbJGhKc47++oo4JkEoTe2wjy4fmMwvFpgJT9cQzmfXKp22Dr6Hf1tdCteLz1h0P3t+mGvWZ+4Uankvh8+c6zw== + dependencies: + acorn "^8.8.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.3.0" + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esquery@^1.4.0, esquery@^1.4.2, esquery@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" + integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== + +expect@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/expect/-/expect-28.1.3.tgz#90a7c1a124f1824133dd4533cce2d2bdcb6603ec" + integrity sha512-eEh0xn8HlsuOBxFgIss+2mX85VAS4Qy3OSkjV7rlBWljtA4oWH37glVGyOZSZvErDT/yBywZdPGwCXuTvSG85g== + dependencies: + "@jest/expect-utils" "^28.1.3" + jest-get-type "^28.0.2" + jest-matcher-utils "^28.1.3" + jest-message-util "^28.1.3" + jest-util "^28.1.3" + +expect@^29.0.0, expect@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/expect/-/expect-29.5.0.tgz#68c0509156cb2a0adb8865d413b137eeaae682f7" + integrity sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg== + dependencies: + "@jest/expect-utils" "^29.5.0" + jest-get-type "^29.4.3" + jest-matcher-utils "^29.5.0" + jest-message-util "^29.5.0" + jest-util "^29.5.0" + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-glob@^3.2.9: + version "3.2.12" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80" + integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fastq@^1.6.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a" + integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw== + dependencies: + reusify "^1.0.4" + +fb-watchman@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.2.tgz#e9524ee6b5c77e9e5001af0f85f3adbb8623255c" + integrity sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA== + dependencies: + bser "2.1.1" + +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +find-up@^4.0.0, find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat-cache@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" + integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== + dependencies: + flatted "^3.1.0" + rimraf "^3.0.2" + +flatted@^3.1.0: + version "3.2.7" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" + integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + +glob-parent@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +glob@^7.1.3, glob@^7.1.4: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globals@^13.19.0: + version "13.20.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.20.0.tgz#ea276a1e508ffd4f1612888f9d1bad1e2717bf82" + integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ== + dependencies: + type-fest "^0.20.2" + +globby@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + +graceful-fs@^4.2.9: + version "4.2.10" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" + integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== + +grapheme-splitter@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" + integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + +ieee754@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + +ignore@^5.2.0: + version "5.2.4" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" + integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== + +import-fresh@^3.0.0, import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +import-local@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" + integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + +is-buffer@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" + integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== + +is-core-module@^2.1.0, is-core-module@^2.9.0: + version "2.11.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.11.0.tgz#ad4cb3e3863e814523c96f3f58d26cc570ff0144" + integrity sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw== + dependencies: + has "^1.0.3" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-generator-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" + integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-path-inside@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" + integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== + +istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d" + integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^6.3.0" + +istanbul-lib-report@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" + integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^3.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" + integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + source-map "^0.6.1" + +istanbul-reports@^3.1.3: + version "3.1.5" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.5.tgz#cc9a6ab25cb25659810e4785ed9d9fb742578bae" + integrity sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +jest-changed-files@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-28.1.3.tgz#d9aeee6792be3686c47cb988a8eaf82ff4238831" + integrity sha512-esaOfUWJXk2nfZt9SPyC8gA1kNfdKLkQWyzsMlqq8msYSlNKfmZxfRgZn4Cd4MGVUF+7v6dBs0d5TOAKa7iIiA== + dependencies: + execa "^5.0.0" + p-limit "^3.1.0" + +jest-circus@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-28.1.3.tgz#d14bd11cf8ee1a03d69902dc47b6bd4634ee00e4" + integrity sha512-cZ+eS5zc79MBwt+IhQhiEp0OeBddpc1n8MBo1nMB8A7oPMKEO+Sre+wHaLJexQUj9Ya/8NOBY0RESUgYjB6fow== + dependencies: + "@jest/environment" "^28.1.3" + "@jest/expect" "^28.1.3" + "@jest/test-result" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^0.7.0" + is-generator-fn "^2.0.0" + jest-each "^28.1.3" + jest-matcher-utils "^28.1.3" + jest-message-util "^28.1.3" + jest-runtime "^28.1.3" + jest-snapshot "^28.1.3" + jest-util "^28.1.3" + p-limit "^3.1.0" + pretty-format "^28.1.3" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-cli@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-28.1.3.tgz#558b33c577d06de55087b8448d373b9f654e46b2" + integrity sha512-roY3kvrv57Azn1yPgdTebPAXvdR2xfezaKKYzVxZ6It/5NCxzJym6tUI5P1zkdWhfUYkxEI9uZWcQdaFLo8mJQ== + dependencies: + "@jest/core" "^28.1.3" + "@jest/test-result" "^28.1.3" + "@jest/types" "^28.1.3" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + import-local "^3.0.2" + jest-config "^28.1.3" + jest-util "^28.1.3" + jest-validate "^28.1.3" + prompts "^2.0.1" + yargs "^17.3.1" + +jest-config@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-28.1.3.tgz#e315e1f73df3cac31447eed8b8740a477392ec60" + integrity sha512-MG3INjByJ0J4AsNBm7T3hsuxKQqFIiRo/AUqb1q9LRKI5UU6Aar9JHbr9Ivn1TVwfUD9KirRoM/T6u8XlcQPHQ== + dependencies: + "@babel/core" "^7.11.6" + "@jest/test-sequencer" "^28.1.3" + "@jest/types" "^28.1.3" + babel-jest "^28.1.3" + chalk "^4.0.0" + ci-info "^3.2.0" + deepmerge "^4.2.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-circus "^28.1.3" + jest-environment-node "^28.1.3" + jest-get-type "^28.0.2" + jest-regex-util "^28.0.2" + jest-resolve "^28.1.3" + jest-runner "^28.1.3" + jest-util "^28.1.3" + jest-validate "^28.1.3" + micromatch "^4.0.4" + parse-json "^5.2.0" + pretty-format "^28.1.3" + slash "^3.0.0" + strip-json-comments "^3.1.1" + +jest-diff@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-28.1.3.tgz#948a192d86f4e7a64c5264ad4da4877133d8792f" + integrity sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw== + dependencies: + chalk "^4.0.0" + diff-sequences "^28.1.1" + jest-get-type "^28.0.2" + pretty-format "^28.1.3" + +jest-diff@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.5.0.tgz#e0d83a58eb5451dcc1fa61b1c3ee4e8f5a290d63" + integrity sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw== + dependencies: + chalk "^4.0.0" + diff-sequences "^29.4.3" + jest-get-type "^29.4.3" + pretty-format "^29.5.0" + +jest-docblock@^28.1.1: + version "28.1.1" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-28.1.1.tgz#6f515c3bf841516d82ecd57a62eed9204c2f42a8" + integrity sha512-3wayBVNiOYx0cwAbl9rwm5kKFP8yHH3d/fkEaL02NPTkDojPtheGB7HZSFY4wzX+DxyrvhXz0KSCVksmCknCuA== + dependencies: + detect-newline "^3.0.0" + +jest-each@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-28.1.3.tgz#bdd1516edbe2b1f3569cfdad9acd543040028f81" + integrity sha512-arT1z4sg2yABU5uogObVPvSlSMQlDA48owx07BDPAiasW0yYpYHYOo4HHLz9q0BVzDVU4hILFjzJw0So9aCL/g== + dependencies: + "@jest/types" "^28.1.3" + chalk "^4.0.0" + jest-get-type "^28.0.2" + jest-util "^28.1.3" + pretty-format "^28.1.3" + +jest-environment-node@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-28.1.3.tgz#7e74fe40eb645b9d56c0c4b70ca4357faa349be5" + integrity sha512-ugP6XOhEpjAEhGYvp5Xj989ns5cB1K6ZdjBYuS30umT4CQEETaxSiPcZ/E1kFktX4GkrcM4qu07IIlDYX1gp+A== + dependencies: + "@jest/environment" "^28.1.3" + "@jest/fake-timers" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/node" "*" + jest-mock "^28.1.3" + jest-util "^28.1.3" + +jest-get-type@^28.0.2: + version "28.0.2" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-28.0.2.tgz#34622e628e4fdcd793d46db8a242227901fcf203" + integrity sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA== + +jest-get-type@^29.4.3: + version "29.4.3" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.4.3.tgz#1ab7a5207c995161100b5187159ca82dd48b3dd5" + integrity sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg== + +jest-haste-map@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-28.1.3.tgz#abd5451129a38d9841049644f34b034308944e2b" + integrity sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA== + dependencies: + "@jest/types" "^28.1.3" + "@types/graceful-fs" "^4.1.3" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.9" + jest-regex-util "^28.0.2" + jest-util "^28.1.3" + jest-worker "^28.1.3" + micromatch "^4.0.4" + walker "^1.0.8" + optionalDependencies: + fsevents "^2.3.2" + +jest-haste-map@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.5.0.tgz#69bd67dc9012d6e2723f20a945099e972b2e94de" + integrity sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA== + dependencies: + "@jest/types" "^29.5.0" + "@types/graceful-fs" "^4.1.3" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.9" + jest-regex-util "^29.4.3" + jest-util "^29.5.0" + jest-worker "^29.5.0" + micromatch "^4.0.4" + walker "^1.0.8" + optionalDependencies: + fsevents "^2.3.2" + +jest-leak-detector@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-28.1.3.tgz#a6685d9b074be99e3adee816ce84fd30795e654d" + integrity sha512-WFVJhnQsiKtDEo5lG2mM0v40QWnBM+zMdHHyJs8AWZ7J0QZJS59MsyKeJHWhpBZBH32S48FOVvGyOFT1h0DlqA== + dependencies: + jest-get-type "^28.0.2" + pretty-format "^28.1.3" + +jest-matcher-utils@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-28.1.3.tgz#5a77f1c129dd5ba3b4d7fc20728806c78893146e" + integrity sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw== + dependencies: + chalk "^4.0.0" + jest-diff "^28.1.3" + jest-get-type "^28.0.2" + pretty-format "^28.1.3" + +jest-matcher-utils@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz#d957af7f8c0692c5453666705621ad4abc2c59c5" + integrity sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw== + dependencies: + chalk "^4.0.0" + jest-diff "^29.5.0" + jest-get-type "^29.4.3" + pretty-format "^29.5.0" + +jest-message-util@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-28.1.3.tgz#232def7f2e333f1eecc90649b5b94b0055e7c43d" + integrity sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^28.1.3" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^28.1.3" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-message-util@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.5.0.tgz#1f776cac3aca332ab8dd2e3b41625435085c900e" + integrity sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^29.5.0" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^29.5.0" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-mock@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-28.1.3.tgz#d4e9b1fc838bea595c77ab73672ebf513ab249da" + integrity sha512-o3J2jr6dMMWYVH4Lh/NKmDXdosrsJgi4AviS8oXLujcjpCMBb1FMsblDnOXKZKfSiHLxYub1eS0IHuRXsio9eA== + dependencies: + "@jest/types" "^28.1.3" + "@types/node" "*" + +jest-mock@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.5.0.tgz#26e2172bcc71d8b0195081ff1f146ac7e1518aed" + integrity sha512-GqOzvdWDE4fAV2bWQLQCkujxYWL7RxjCnj71b5VhDAGOevB3qj3Ovg26A5NI84ZpODxyzaozXLOh2NCgkbvyaw== + dependencies: + "@jest/types" "^29.5.0" + "@types/node" "*" + jest-util "^29.5.0" + +jest-pnp-resolver@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz#930b1546164d4ad5937d5540e711d4d38d4cad2e" + integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== + +jest-regex-util@^28.0.2: + version "28.0.2" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-28.0.2.tgz#afdc377a3b25fb6e80825adcf76c854e5bf47ead" + integrity sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw== + +jest-regex-util@^29.4.3: + version "29.4.3" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.4.3.tgz#a42616141e0cae052cfa32c169945d00c0aa0bb8" + integrity sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg== + +jest-resolve-dependencies@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-28.1.3.tgz#8c65d7583460df7275c6ea2791901fa975c1fe66" + integrity sha512-qa0QO2Q0XzQoNPouMbCc7Bvtsem8eQgVPNkwn9LnS+R2n8DaVDPL/U1gngC0LTl1RYXJU0uJa2BMC2DbTfFrHA== + dependencies: + jest-regex-util "^28.0.2" + jest-snapshot "^28.1.3" + +jest-resolve@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-28.1.3.tgz#cfb36100341ddbb061ec781426b3c31eb51aa0a8" + integrity sha512-Z1W3tTjE6QaNI90qo/BJpfnvpxtaFTFw5CDgwpyE/Kz8U/06N1Hjf4ia9quUhCh39qIGWF1ZuxFiBiJQwSEYKQ== + dependencies: + chalk "^4.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^28.1.3" + jest-pnp-resolver "^1.2.2" + jest-util "^28.1.3" + jest-validate "^28.1.3" + resolve "^1.20.0" + resolve.exports "^1.1.0" + slash "^3.0.0" + +jest-runner@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-28.1.3.tgz#5eee25febd730b4713a2cdfd76bdd5557840f9a1" + integrity sha512-GkMw4D/0USd62OVO0oEgjn23TM+YJa2U2Wu5zz9xsQB1MxWKDOlrnykPxnMsN0tnJllfLPinHTka61u0QhaxBA== + dependencies: + "@jest/console" "^28.1.3" + "@jest/environment" "^28.1.3" + "@jest/test-result" "^28.1.3" + "@jest/transform" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.10.2" + graceful-fs "^4.2.9" + jest-docblock "^28.1.1" + jest-environment-node "^28.1.3" + jest-haste-map "^28.1.3" + jest-leak-detector "^28.1.3" + jest-message-util "^28.1.3" + jest-resolve "^28.1.3" + jest-runtime "^28.1.3" + jest-util "^28.1.3" + jest-watcher "^28.1.3" + jest-worker "^28.1.3" + p-limit "^3.1.0" + source-map-support "0.5.13" + +jest-runtime@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-28.1.3.tgz#a57643458235aa53e8ec7821949e728960d0605f" + integrity sha512-NU+881ScBQQLc1JHG5eJGU7Ui3kLKrmwCPPtYsJtBykixrM2OhVQlpMmFWJjMyDfdkGgBMNjXCGB/ebzsgNGQw== + dependencies: + "@jest/environment" "^28.1.3" + "@jest/fake-timers" "^28.1.3" + "@jest/globals" "^28.1.3" + "@jest/source-map" "^28.1.2" + "@jest/test-result" "^28.1.3" + "@jest/transform" "^28.1.3" + "@jest/types" "^28.1.3" + chalk "^4.0.0" + cjs-module-lexer "^1.0.0" + collect-v8-coverage "^1.0.0" + execa "^5.0.0" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-haste-map "^28.1.3" + jest-message-util "^28.1.3" + jest-mock "^28.1.3" + jest-regex-util "^28.0.2" + jest-resolve "^28.1.3" + jest-snapshot "^28.1.3" + jest-util "^28.1.3" + slash "^3.0.0" + strip-bom "^4.0.0" + +jest-snapshot@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-28.1.3.tgz#17467b3ab8ddb81e2f605db05583d69388fc0668" + integrity sha512-4lzMgtiNlc3DU/8lZfmqxN3AYD6GGLbl+72rdBpXvcV+whX7mDrREzkPdp2RnmfIiWBg1YbuFSkXduF2JcafJg== + dependencies: + "@babel/core" "^7.11.6" + "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/traverse" "^7.7.2" + "@babel/types" "^7.3.3" + "@jest/expect-utils" "^28.1.3" + "@jest/transform" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/babel__traverse" "^7.0.6" + "@types/prettier" "^2.1.5" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^28.1.3" + graceful-fs "^4.2.9" + jest-diff "^28.1.3" + jest-get-type "^28.0.2" + jest-haste-map "^28.1.3" + jest-matcher-utils "^28.1.3" + jest-message-util "^28.1.3" + jest-util "^28.1.3" + natural-compare "^1.4.0" + pretty-format "^28.1.3" + semver "^7.3.5" + +jest-snapshot@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.5.0.tgz#c9c1ce0331e5b63cd444e2f95a55a73b84b1e8ce" + integrity sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g== + dependencies: + "@babel/core" "^7.11.6" + "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-jsx" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/traverse" "^7.7.2" + "@babel/types" "^7.3.3" + "@jest/expect-utils" "^29.5.0" + "@jest/transform" "^29.5.0" + "@jest/types" "^29.5.0" + "@types/babel__traverse" "^7.0.6" + "@types/prettier" "^2.1.5" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^29.5.0" + graceful-fs "^4.2.9" + jest-diff "^29.5.0" + jest-get-type "^29.4.3" + jest-matcher-utils "^29.5.0" + jest-message-util "^29.5.0" + jest-util "^29.5.0" + natural-compare "^1.4.0" + pretty-format "^29.5.0" + semver "^7.3.5" + +jest-util@^28.0.0, jest-util@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-28.1.3.tgz#f4f932aa0074f0679943220ff9cbba7e497028b0" + integrity sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ== + dependencies: + "@jest/types" "^28.1.3" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + +jest-util@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.5.0.tgz#24a4d3d92fc39ce90425311b23c27a6e0ef16b8f" + integrity sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ== + dependencies: + "@jest/types" "^29.5.0" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + +jest-validate@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-28.1.3.tgz#e322267fd5e7c64cea4629612c357bbda96229df" + integrity sha512-SZbOGBWEsaTxBGCOpsRWlXlvNkvTkY0XxRfh7zYmvd8uL5Qzyg0CHAXiXKROflh801quA6+/DsT4ODDthOC/OA== + dependencies: + "@jest/types" "^28.1.3" + camelcase "^6.2.0" + chalk "^4.0.0" + jest-get-type "^28.0.2" + leven "^3.1.0" + pretty-format "^28.1.3" + +jest-watcher@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-28.1.3.tgz#c6023a59ba2255e3b4c57179fc94164b3e73abd4" + integrity sha512-t4qcqj9hze+jviFPUN3YAtAEeFnr/azITXQEMARf5cMwKY2SMBRnCQTXLixTl20OR6mLh9KLMrgVJgJISym+1g== + dependencies: + "@jest/test-result" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.10.2" + jest-util "^28.1.3" + string-length "^4.0.1" + +jest-worker@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-28.1.3.tgz#7e3c4ce3fa23d1bb6accb169e7f396f98ed4bb98" + integrity sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest-worker@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.5.0.tgz#bdaefb06811bd3384d93f009755014d8acb4615d" + integrity sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA== + dependencies: + "@types/node" "*" + jest-util "^29.5.0" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest/-/jest-28.1.3.tgz#e9c6a7eecdebe3548ca2b18894a50f45b36dfc6b" + integrity sha512-N4GT5on8UkZgH0O5LUavMRV1EDEhNTL0KEfRmDIeZHSV7p2XgLoY9t9VDUgL6o+yfdgYHVxuz81G8oB9VG5uyA== + dependencies: + "@jest/core" "^28.1.3" + "@jest/types" "^28.1.3" + import-local "^3.0.2" + jest-cli "^28.1.3" + +jju@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/jju/-/jju-1.4.0.tgz#a3abe2718af241a2b2904f84a625970f389ae32a" + integrity sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA== + +js-sdsl@^4.1.4: + version "4.3.0" + resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.3.0.tgz#aeefe32a451f7af88425b11fdb5f58c90ae1d711" + integrity sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ== + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +jsdoc-type-pratt-parser@~4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz#136f0571a99c184d84ec84662c45c29ceff71114" + integrity sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ== + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +json5@^2.2.1, json5@^2.2.2: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + +kleur@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== + +level-concat-iterator@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/level-concat-iterator/-/level-concat-iterator-3.1.0.tgz#5235b1f744bc34847ed65a50548aa88d22e881cf" + integrity sha512-BWRCMHBxbIqPxJ8vHOvKUsaO0v1sLYZtjN3K2iZJsRBYtp+ONsY6Jfi6hy9K3+zolgQRryhIn2NRZjZnWJ9NmQ== + dependencies: + catering "^2.1.0" + +level-errors@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/level-errors/-/level-errors-3.0.1.tgz#4bed48a33108cd83b0e39fdf9bbd84e96fbbef9f" + integrity sha512-tqTL2DxzPDzpwl0iV5+rBCv65HWbHp6eutluHNcVIftKZlQN//b6GEnZDM2CvGZvzGYMwyPtYppYnydBQd2SMQ== + +level-iterator-stream@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/level-iterator-stream/-/level-iterator-stream-5.0.0.tgz#85b3438e1b4c54ce5aa8c0eb973cfb628117df9e" + integrity sha512-wnb1+o+CVFUDdiSMR/ZymE2prPs3cjVLlXuDeSq9Zb8o032XrabGEXcTCsBxprAtseO3qvFeGzh6406z9sOTRA== + dependencies: + inherits "^2.0.4" + readable-stream "^3.4.0" + +level-supports@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/level-supports/-/level-supports-2.1.0.tgz#9af908d853597ecd592293b2fad124375be79c5f" + integrity sha512-E486g1NCjW5cF78KGPrMDRBYzPuueMZ6VBXHT6gC7A8UYWGiM14fGgp+s/L1oFfDWSPV/+SFkYCmZ0SiESkRKA== + +leveldown@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/leveldown/-/leveldown-6.1.1.tgz#0f0e480fa88fd807abf94c33cb7e40966ea4b5ce" + integrity sha512-88c+E+Eizn4CkQOBHwqlCJaTNEjGpaEIikn1S+cINc5E9HEvJ77bqY4JY/HxT5u0caWqsc3P3DcFIKBI1vHt+A== + dependencies: + abstract-leveldown "^7.2.0" + napi-macros "~2.0.0" + node-gyp-build "^4.3.0" + +levelup@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/levelup/-/levelup-5.1.1.tgz#9f99699f414ac084a3f8a28fc262a1f49cd7a52c" + integrity sha512-0mFCcHcEebOwsQuk00WJwjLI6oCjbBuEYdh/RaRqhjnyVlzqf41T1NnDtCedumZ56qyIh8euLFDqV1KfzTAVhg== + dependencies: + catering "^2.0.0" + deferred-leveldown "^7.0.0" + level-errors "^3.0.1" + level-iterator-stream "^5.0.0" + level-supports "^2.0.1" + queue-microtask "^1.2.3" + +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash.memoize@4.x: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +ltgt@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ltgt/-/ltgt-2.2.1.tgz#f35ca91c493f7b73da0e07495304f17b31f87ee5" + integrity sha512-AI2r85+4MquTw9ZYqabu4nMwy9Oftlfa/e/52t9IjtfG+mGBbTNdAoZ3RQKLHR6r0wQnwZnPIEh/Ya6XTWAKNA== + +make-dir@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + +make-error@1.x, make-error@^1.1.1: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + +makeerror@1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" + integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== + dependencies: + tmpl "1.0.5" + +memdown@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/memdown/-/memdown-6.1.1.tgz#ab52fae1a029affb40af60fda9d247a5733e4dc3" + integrity sha512-vh2RiuVrn6Vv73088C1KzLwy9+hhRwoZsgddYqIoVuFFrcoc2Rt+lq/KrmkFn6ulko7AtQ0AvqtYid35exb38A== + dependencies: + abstract-leveldown "^7.2.0" + buffer "^6.0.3" + functional-red-black-tree "^1.0.1" + inherits "^2.0.1" + ltgt "^2.2.0" + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +merge2@^1.3.0, merge2@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@^4.0.4: + version "4.0.5" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +napi-macros@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/napi-macros/-/napi-macros-2.0.0.tgz#2b6bae421e7b96eb687aa6c77a7858640670001b" + integrity sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg== + +natural-compare-lite@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4" + integrity sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +node-fetch@2.6.7: + version "2.6.7" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" + integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== + dependencies: + whatwg-url "^5.0.0" + +node-gyp-build@^4.3.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.6.0.tgz#0c52e4cbf54bbd28b709820ef7b6a3c2d6209055" + integrity sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ== + +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== + +node-releases@^2.0.8: + version "2.0.10" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.10.tgz#c311ebae3b6a148c89b1813fd7c4d3c024ef537f" + integrity sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w== + +normalize-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +optionator@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" + integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.3" + +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.0.2, p-limit@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-json@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.6, path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +picomatch@^2.0.4, picomatch@^2.2.3, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pirates@^4.0.4: + version "4.0.5" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.5.tgz#feec352ea5c3268fb23a37c702ab1699f35a5f3b" + integrity sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ== + +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +prettier@^2.8.4: + version "2.8.4" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.4.tgz#34dd2595629bfbb79d344ac4a91ff948694463c3" + integrity sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw== + +pretty-format@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-28.1.3.tgz#c9fba8cedf99ce50963a11b27d982a9ae90970d5" + integrity sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q== + dependencies: + "@jest/schemas" "^28.1.3" + ansi-regex "^5.0.1" + ansi-styles "^5.0.0" + react-is "^18.0.0" + +pretty-format@^29.0.0, pretty-format@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.5.0.tgz#283134e74f70e2e3e7229336de0e4fce94ccde5a" + integrity sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw== + dependencies: + "@jest/schemas" "^29.4.3" + ansi-styles "^5.0.0" + react-is "^18.0.0" + +prompts@^2.0.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" + integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== + dependencies: + kleur "^3.0.3" + sisteransi "^1.0.5" + +punycode@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" + integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== + +queue-microtask@^1.2.2, queue-microtask@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +react-is@^18.0.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" + integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== + +readable-stream@^3.4.0: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve.exports@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.1.tgz#05cfd5b3edf641571fd46fa608b610dda9ead999" + integrity sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ== + +resolve@^1.20.0: + version "1.22.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" + integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== + dependencies: + is-core-module "^2.9.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +resolve@~1.19.0: + version "1.19.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.19.0.tgz#1af5bf630409734a067cae29318aac7fa29a267c" + integrity sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg== + dependencies: + is-core-module "^2.1.0" + path-parse "^1.0.6" + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rimraf@^3.0.0, rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +semver@7.x, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8: + version "7.3.8" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" + integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== + dependencies: + lru-cache "^6.0.0" + +semver@^6.0.0, semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +signal-exit@^3.0.3, signal-exit@^3.0.7: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +sisteransi@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +source-map-support@0.5.13: + version "0.5.13" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" + integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0, source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +spdx-exceptions@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" + integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== + +spdx-expression-parse@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" + integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.13" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz#7189a474c46f8d47c7b0da4b987bb45e908bd2d5" + integrity sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w== + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== + +stack-utils@^2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" + integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== + dependencies: + escape-string-regexp "^2.0.0" + +string-length@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" + integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== + dependencies: + char-regex "^1.0.2" + strip-ansi "^6.0.0" + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-bom@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.0.0, supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-hyperlinks@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz#3943544347c1ff90b15effb03fc14ae45ec10624" + integrity sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA== + dependencies: + has-flag "^4.0.0" + supports-color "^7.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +terminal-link@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" + integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ== + dependencies: + ansi-escapes "^4.2.1" + supports-hyperlinks "^2.0.0" + +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + +tmpl@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + +ts-dedent@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/ts-dedent/-/ts-dedent-2.2.0.tgz#39e4bd297cd036292ae2394eb3412be63f563bb5" + integrity sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ== + +ts-jest@^28.0.7: + version "28.0.8" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-28.0.8.tgz#cd204b8e7a2f78da32cf6c95c9a6165c5b99cc73" + integrity sha512-5FaG0lXmRPzApix8oFG8RKjAz4ehtm8yMKOTy5HX3fY6W8kmvOrmcY0hKDElW52FJov+clhUbrKAqofnj4mXTg== + dependencies: + bs-logger "0.x" + fast-json-stable-stringify "2.x" + jest-util "^28.0.0" + json5 "^2.2.1" + lodash.memoize "4.x" + make-error "1.x" + semver "7.x" + yargs-parser "^21.0.1" + +ts-node@^10.9.1: + version "10.9.1" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b" + integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw== + dependencies: + "@cspotcode/source-map-support" "^0.8.0" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" + arg "^4.1.0" + create-require "^1.1.0" + diff "^4.0.1" + make-error "^1.1.1" + v8-compile-cache-lib "^3.0.1" + yn "3.1.1" + +tslib@^1.8.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tslib@^2.4.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf" + integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg== + +tsutils@^3.21.0: + version "3.21.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" + integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== + dependencies: + tslib "^1.8.1" + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-detect@4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +typescript@^4.9.5: + version "4.9.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" + integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== + +update-browserslist-db@^1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz#0f54b876545726f17d00cd9a2561e6dade943ff3" + integrity sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ== + dependencies: + escalade "^3.1.1" + picocolors "^1.0.0" + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +util-deprecate@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +v8-compile-cache-lib@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" + integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== + +v8-to-istanbul@^9.0.1: + version "9.1.0" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz#1b83ed4e397f58c85c266a570fc2558b5feb9265" + integrity sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA== + dependencies: + "@jridgewell/trace-mapping" "^0.3.12" + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^1.6.0" + +walker@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" + integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== + dependencies: + makeerror "1.0.12" + +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +word-wrap@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +write-file-atomic@^4.0.1, write-file-atomic@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" + integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== + dependencies: + imurmurhash "^0.1.4" + signal-exit "^3.0.7" + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yargs-parser@^21.0.1, yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + +yargs@^17.3.1: + version "17.7.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.1.tgz#34a77645201d1a8fc5213ace787c220eabbd0967" + integrity sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1" + +yn@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== From bdacb63d95a5a3092d8e836fac3a3eb629807b6b Mon Sep 17 00:00:00 2001 From: ludamad Date: Mon, 17 Apr 2023 14:27:46 -0400 Subject: [PATCH 084/166] cbinds for hash_constructor and compute_contract_address (#82) --- .../cpp/src/aztec3/circuits/abis/c_bind.cpp | 112 +++++++++++++++++- .../cpp/src/aztec3/circuits/abis/c_bind.h | 21 +++- .../src/aztec3/circuits/abis/c_bind.test.cpp | 74 ++++++++++++ circuits/cpp/src/aztec3/constants.hpp | 10 +- 4 files changed, 206 insertions(+), 11 deletions(-) diff --git a/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp b/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp index 8299124a94c..fe661aefb8f 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp +++ b/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp @@ -34,21 +34,20 @@ using NT = aztec3::utils::types::NativeTypes; * end of the tree. * * @tparam TREE_HEIGHT height of the tree used to determine max leaves and used when computing root - * @tparam LeafPreimage the preimage type with a `.hash()` function to generate empty/zero-leaves * @param leaves_buf a buffer of bytes representing the leaves of the tree, where each leaf is * assumed to be a field and is interpreted using `NT::fr::serialize_from_buffer(leaf_ptr)` * @param num_leaves the number of leaves in leaves_buf + * @param zero_leaf the leaf value to be used for any empty/unset leaves * @returns a field (`NT::fr`) containing the computed merkle tree root */ -template -NT::fr compute_root_of_partial_left_tree(uint8_t const* leaves_buf, uint8_t num_leaves) +template +NT::fr compute_root_of_partial_left_tree(uint8_t const* leaves_buf, uint8_t num_leaves, NT::fr zero_leaf) { const size_t max_leaves = 2 << (TREE_HEIGHT - 1); // cant exceed max leaves ASSERT(num_leaves <= max_leaves); // initialize the vector of leaves to a complete-tree-sized vector of zero-leaves - NT::fr zero_leaf = LeafPreimage().hash(); // hash of empty/0 preimage std::vector leaves(max_leaves, zero_leaf); // Iterate over the input buffer, extracting each leaf and serializing it from buffer to field @@ -166,6 +165,111 @@ WASM_EXPORT void abis__compute_function_leaf(uint8_t const* function_leaf_preima NT::fr::serialize_to_buffer(leaf_preimage.hash(), output); } +/** + * @brief Compute a function tree root from its leaves. + * This is a WASM-export that can be called from Typescript. + * + * @details given a `uint8_t const*` buffer representing a function tree's leaves, + * compute the corresponding tree's root and return the serialized results + * in the `output` buffer. + * + * @param function_leaves_buf a buffer of bytes representing the leaves of the function tree, + * where each leaf is assumed to be a serialized field + * @param num_leaves the number of leaves in leaves_buf + * @param output buffer that will contain the output. The serialized function tree root. + */ +WASM_EXPORT void abis__compute_function_tree_root(uint8_t const* function_leaves_buf, + uint8_t num_leaves, + uint8_t* output) +{ + NT::fr zero_leaf = FunctionLeafPreimage().hash(); // hash of empty/0 preimage + NT::fr root = + compute_root_of_partial_left_tree(function_leaves_buf, num_leaves, zero_leaf); + + // serialize and return root + NT::fr::serialize_to_buffer(root, output); +} + +/** + * @brief Hash some constructor info. + * This is a WASM-export that can be called from Typescript. + * + * @details Hash constructor info to use later when deriving/generating contract address: + * hash(function_signature_hash, args_hash, constructor_vk_hash) + * Return the serialized results in the `output` buffer. + * + * @param func_sig_hash_buf function signature field but as a buffer of bytes + * @param args_hash_buf constructor args hashed to a field but as a buffer of bytes + * @param constructor_vk_hash_buf constructor vk hashed to a field but as a buffer of bytes + * @param output buffer that will contain the output. The serialized constructor_vk_hash. + */ +WASM_EXPORT void abis__hash_constructor(uint8_t const* func_sig_hash_buf, + uint8_t const* args_hash_buf, + uint8_t const* constructor_vk_hash_buf, + uint8_t* output) +{ + NT::fr func_sig_hash; + NT::fr args_hash; + NT::fr constructor_vk_hash; + + using serialize::read; + read(func_sig_hash_buf, func_sig_hash); + read(args_hash_buf, args_hash); + read(constructor_vk_hash_buf, constructor_vk_hash); + + std::vector inputs = { + func_sig_hash, + args_hash, + constructor_vk_hash, + }; + + NT::fr constructor_hash = NT::compress(inputs, aztec3::GeneratorIndex::CONSTRUCTOR); + NT::fr::serialize_to_buffer(constructor_hash, output); +} + +/** + * @brief Generates a contract address from its components. + * This is a WASM-export that can be called from Typescript. + * + * @details hash the inputs to generate a deterministic contract address: + * hash(contract_address, contract_address_salt, function_tree_root, constructor_hash) + * Return the serialized results in the `output` buffer. + * + * @param contract_address_salt_buf bytes buffer representing a field that lets a deployer have + * some control over contract address + * @param function_tree_root_buf bytes buffer representing a field that is the root of the + * contract's function tree + * @param constructor_hash_buf bytes buffer representing a field that is a hash of constructor info + * @param output buffer that will contain the output contract address. + */ +WASM_EXPORT void abis__compute_contract_address(uint8_t const* deployer_address_buf, + uint8_t const* contract_address_salt_buf, + uint8_t const* function_tree_root_buf, + uint8_t const* constructor_hash_buf, + uint8_t* output) +{ + NT::address deployer_address; + NT::fr contract_address_salt; + NT::fr function_tree_root; + NT::fr constructor_hash; + + using serialize::read; + read(deployer_address_buf, deployer_address); + read(contract_address_salt_buf, contract_address_salt); + read(function_tree_root_buf, function_tree_root); + read(constructor_hash_buf, constructor_hash); + + std::vector inputs = { + deployer_address, + contract_address_salt, + function_tree_root, + constructor_hash, + }; + + NT::address contract_address = NT::fr(NT::compress(inputs, aztec3::GeneratorIndex::CONTRACT_ADDRESS)); + NT::fr::serialize_to_buffer(contract_address, output); +} + // TODO(AD): After Milestone 1, rewrite this with better injection mechanism. WASM_EXPORT void abis__set_global_verifier_reference_string(uint8_t* data) { diff --git a/circuits/cpp/src/aztec3/circuits/abis/c_bind.h b/circuits/cpp/src/aztec3/circuits/abis/c_bind.h index 0cfac00caae..2594d0cb607 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/c_bind.h +++ b/circuits/cpp/src/aztec3/circuits/abis/c_bind.h @@ -5,8 +5,25 @@ extern "C" { WASM_EXPORT void abis__hash_tx_request(uint8_t const* tx_request_buf, uint8_t* output); + WASM_EXPORT void abis__compute_function_selector(char const* func_sig_cstr, uint8_t* output); -WASM_EXPORT void abis__compute_function_leaf(uint8_t const* function_leaf_preimage_buf, uint8_t* output); -WASM_EXPORT void abis__compute_function_tree_root(uint8_t const* function_leaves_buf, uint8_t num_leaves, uint8_t* output); + +WASM_EXPORT void abis__compute_function_leaf(uint8_t const* function_leaf_preimage_buf, + uint8_t* output); + +WASM_EXPORT void abis__compute_function_tree_root(uint8_t const* function_leaves_buf, + uint8_t num_leaves, + uint8_t* output); + +WASM_EXPORT void abis__hash_constructor(uint8_t const* func_sig_hash_buf, + uint8_t const* args_hash_buf, + uint8_t const* constructor_vk_hash_buf, + uint8_t* output); + +WASM_EXPORT void abis__compute_contract_address(uint8_t const* deployer_address_buf, + uint8_t const* contract_address_salt_buf, + uint8_t const* function_tree_root_buf, + uint8_t const* constructor_hash_buf, + uint8_t* output); } \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp b/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp index 47967efd38e..b8725bd70e9 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp @@ -11,6 +11,7 @@ namespace { using NT = aztec3::utils::types::NativeTypes; auto& engine = numeric::random::get_debug_engine(); +constexpr size_t FUNCTION_TREE_NUM_LEAVES = 2 << (aztec3::FUNCTION_TREE_HEIGHT - 1); // leaves = 2 ^ height /** * @brief Convert a bytes array to a hex string. @@ -154,4 +155,77 @@ TEST(abi_tests, compute_function_tree_root) EXPECT_EQ(got_root, plonk::stdlib::merkle_tree::compute_tree_root_native(leaves_frs)); } +TEST(abi_tests, hash_constructor) +{ + // Randomize required values + NT::fr func_sig_hash = NT::fr::random_element(); + NT::fr args_hash = NT::fr::random_element(); + NT::fr constructor_vk_hash = NT::fr::random_element(); + + // Serialize values to buffers + std::array func_sig_hash_buf = { 0 }; + std::array args_hash_buf = { 0 }; + std::array constructor_vk_hash_buf = { 0 }; + NT::fr::serialize_to_buffer(func_sig_hash, func_sig_hash_buf.data()); + NT::fr::serialize_to_buffer(args_hash, args_hash_buf.data()); + NT::fr::serialize_to_buffer(constructor_vk_hash, constructor_vk_hash_buf.data()); + + // create an output buffer for cbind hash results + std::array output = { 0 }; + + // Make the c_bind call to hash the constructor values + abis__hash_constructor( + func_sig_hash_buf.data(), args_hash_buf.data(), constructor_vk_hash_buf.data(), output.data()); + + // Convert buffer to `fr` for comparison to in-test calculated hash + NT::fr got_hash = NT::fr::serialize_from_buffer(output.data()); + + // Calculate the expected hash in-test + NT::fr expected_hash = + NT::compress({ func_sig_hash, args_hash, constructor_vk_hash }, aztec3::GeneratorIndex::CONSTRUCTOR); + + // Confirm cbind output == expected hash + EXPECT_EQ(got_hash, expected_hash); +} + +TEST(abi_tests, compute_contract_address) +{ + // Randomize required values + NT::fr deployer_address = NT::fr::random_element(); + NT::fr contract_address_salt = NT::fr::random_element(); + NT::fr function_tree_root = NT::fr::random_element(); + NT::fr constructor_hash = NT::fr::random_element(); + + // Serialize values to buffers + std::array deployer_address_buf = { 0 }; + std::array contract_address_salt_buf = { 0 }; + std::array function_tree_root_buf = { 0 }; + std::array constructor_hash_buf = { 0 }; + NT::fr::serialize_to_buffer(deployer_address, deployer_address_buf.data()); + NT::fr::serialize_to_buffer(contract_address_salt, contract_address_salt_buf.data()); + NT::fr::serialize_to_buffer(function_tree_root, function_tree_root_buf.data()); + NT::fr::serialize_to_buffer(constructor_hash, constructor_hash_buf.data()); + + // create an output buffer for cbind contract address results + std::array output = { 0 }; + + // Make the c_bind call to compute the contract address + abis__compute_contract_address(deployer_address_buf.data(), + contract_address_salt_buf.data(), + function_tree_root_buf.data(), + constructor_hash_buf.data(), + output.data()); + + // Convert buffer to `fr` for comparison to in-test calculated contract address + NT::fr got_address = NT::fr::serialize_from_buffer(output.data()); + + // Calculate the expected contract address in-test + NT::fr expected_address = + NT::compress({ deployer_address, contract_address_salt, function_tree_root, constructor_hash }, + aztec3::GeneratorIndex::CONTRACT_ADDRESS); + + // Confirm cbind output == expected + EXPECT_EQ(got_address, expected_address); +} + } // namespace aztec3::circuits::abis diff --git a/circuits/cpp/src/aztec3/constants.hpp b/circuits/cpp/src/aztec3/constants.hpp index 956b4b98a26..34cc233f10c 100644 --- a/circuits/cpp/src/aztec3/constants.hpp +++ b/circuits/cpp/src/aztec3/constants.hpp @@ -27,6 +27,7 @@ constexpr size_t KERNEL_L1_MSG_STACK_LENGTH = 4; constexpr size_t KERNEL_OPTIONALLY_REVEALED_DATA_LENGTH = 4; constexpr size_t VK_TREE_HEIGHT = 3; +constexpr size_t FUNCTION_TREE_HEIGHT = 4; constexpr size_t CONTRACT_TREE_HEIGHT = 4; constexpr size_t PRIVATE_DATA_TREE_HEIGHT = 8; constexpr size_t NULLIFIER_TREE_HEIGHT = 8; @@ -35,8 +36,6 @@ constexpr size_t PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT = 8; constexpr size_t CONTRACT_TREE_ROOTS_TREE_HEIGHT = 8; constexpr size_t FUNCTION_SELECTOR_NUM_BYTES = 31; // must be <= 31 -constexpr size_t FUNCTION_TREE_HEIGHT = 8; -constexpr size_t FUNCTION_TREE_NUM_LEAVES = 2 << (FUNCTION_TREE_HEIGHT - 1); // leaves = 2 ^ height // Enumerate the hash_indices which are used for pedersen hashing // Start from 1 to avoid the default generators. @@ -50,18 +49,19 @@ enum GeneratorIndex { OUTER_NULLIFIER, STATE_READ, STATE_TRANSITION, - CONTRACT_ADDRESS, FUNCTION_DATA, + FUNCTION_LEAF, + CONTRACT_DEPLOYMENT_DATA, + CONSTRUCTOR, + CONTRACT_ADDRESS, CALL_CONTEXT, CALL_STACK_ITEM, CALL_STACK_ITEM_2, // see function where it's used for explanation L1_MSG_STACK_ITEM, PRIVATE_CIRCUIT_PUBLIC_INPUTS, PUBLIC_CIRCUIT_PUBLIC_INPUTS, - CONTRACT_DEPLOYMENT_DATA, TX_CONTEXT, TX_REQUEST, - FUNCTION_LEAF, }; enum StorageSlotGeneratorIndex { From 870d4c0e904e2b5b5bbe849c528b5bab363b0e53 Mon Sep 17 00:00:00 2001 From: ludamad Date: Mon, 17 Apr 2023 14:28:38 -0400 Subject: [PATCH 085/166] feat(ts): ABI for base rollup public inputs (#77) * Serialize base rollup public input from ts to cpp * Deserialization for base rollup public inputs * Fix base rollup public inputs serialization * Format and lint --- .../abis/barretenberg/aggregation_object.hpp | 11 ++ .../base_rollup/base_rollup_public_inputs.hpp | 131 ++++++++++++++++++ .../cpp/src/aztec3/circuits/abis/c_bind.cpp | 28 ++++ .../__snapshots__/base_rollup.test.ts.snap | 63 ++++++++- circuits/ts/src/structs/base_rollup.test.ts | 61 ++++---- circuits/ts/src/structs/base_rollup.ts | 48 ++++++- circuits/ts/src/structs/function_data.test.ts | 2 +- circuits/ts/src/structs/kernel.test.ts | 2 +- .../private_circuit_public_inputs.test.ts | 2 +- circuits/ts/src/structs/shared.ts | 44 ++++-- circuits/ts/src/structs/tx.test.ts | 2 +- circuits/ts/src/structs/tx.ts | 2 +- ...eToMatchSnapshot.ts => expectSerialize.ts} | 55 ++++++-- circuits/ts/src/tests/factories.ts | 63 +++++++-- circuits/ts/src/utils/jsUtils.ts | 2 +- circuits/ts/src/wasm/buffer_reader.ts | 64 +++++++++ 16 files changed, 511 insertions(+), 69 deletions(-) create mode 100644 circuits/cpp/src/aztec3/circuits/abis/base_rollup/base_rollup_public_inputs.hpp rename circuits/ts/src/tests/{expectSerializeToMatchSnapshot.ts => expectSerialize.ts} (58%) create mode 100644 circuits/ts/src/wasm/buffer_reader.ts diff --git a/circuits/cpp/src/aztec3/circuits/abis/barretenberg/aggregation_object.hpp b/circuits/cpp/src/aztec3/circuits/abis/barretenberg/aggregation_object.hpp index a591834980b..2377fdb8c43 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/barretenberg/aggregation_object.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/barretenberg/aggregation_object.hpp @@ -15,6 +15,17 @@ inline void read(uint8_t const*& it, aztec3::utils::types::NativeTypes::Aggregat read(it, obj.has_data); }; +inline void write(std::vector& buf, aztec3::utils::types::NativeTypes::AggregationObject const& obj) +{ + using serialize::write; + + write(buf, obj.P0); + write(buf, obj.P1); + write(buf, obj.public_inputs); + write(buf, obj.proof_witness_indices); + write(buf, obj.has_data); +}; + } // namespace serialize namespace std { diff --git a/circuits/cpp/src/aztec3/circuits/abis/base_rollup/base_rollup_public_inputs.hpp b/circuits/cpp/src/aztec3/circuits/abis/base_rollup/base_rollup_public_inputs.hpp new file mode 100644 index 00000000000..207c606b30d --- /dev/null +++ b/circuits/cpp/src/aztec3/circuits/abis/base_rollup/base_rollup_public_inputs.hpp @@ -0,0 +1,131 @@ +#pragma once +#include +#include +#include +#include "../append_only_tree_snapshot.hpp" +#include "../append_only_tree_snapshot.hpp" +#include "../barretenberg/aggregation_object.hpp" +#include "./constant_base_rollup_data.hpp" + +namespace aztec3::circuits::abis { + +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; +using std::is_same; + +const uint32_t BASE_ROLLUP_TYPE = 0; +const uint32_t MERGE_ROLLUP_TYPE = 1; + +template struct BaseRollupPublicInputs { + typedef typename NCT::fr fr; + typedef typename NCT::AggregationObject AggregationObject; + + uint32_t rollup_type; + + AggregationObject end_aggregation_object; + + ConstantBaseRollupData constants; + + // The only tree root actually updated in this circuit is the nullifier tree, because earlier leaves (of + // low_nullifiers) must be updated to point to the new nullifiers in this circuit. + AppendOnlyTreeSnapshot start_nullifier_tree_snapshot; + AppendOnlyTreeSnapshot end_nullifier_tree_snapshots; + + fr new_commitments_subtree_root; + fr new_nullifiers_subtree_root; + fr new_contract_leaves_subtree_root; + + // Hashes (probably sha256) to make public inputs constant-sized (to then be unpacked on-chain) + // UPDATE we should instead just hash all of the below into a single value. See big diagram of sha256 hashing + // bottom-right of here. + // TODO I've put `fr`, but these hash values' types might need to be two fields if we want all 256-bits, for + // security purposes. + fr new_commitments_hash; + fr new_nullifiers_hash; + fr new_l1_msgs_hash; + fr new_contract_data_hash; + fr prover_contributions_hash; + + bool operator==(BaseRollupPublicInputs const&) const = default; +}; + +template void read(uint8_t const*& it, BaseRollupPublicInputs& obj) +{ + using serialize::read; + + read(it, obj.rollup_type); + read(it, obj.end_aggregation_object); + read(it, obj.constants); + read(it, obj.start_nullifier_tree_snapshot); + read(it, obj.end_nullifier_tree_snapshots); + read(it, obj.new_commitments_subtree_root); + read(it, obj.new_nullifiers_subtree_root); + read(it, obj.new_contract_leaves_subtree_root); + read(it, obj.new_commitments_hash); + read(it, obj.new_nullifiers_hash); + read(it, obj.new_l1_msgs_hash); + read(it, obj.new_contract_data_hash); + read(it, obj.prover_contributions_hash); +}; + +template void write(std::vector& buf, BaseRollupPublicInputs const& obj) +{ + using serialize::write; + + write(buf, obj.rollup_type); + write(buf, obj.end_aggregation_object); + write(buf, obj.constants); + write(buf, obj.start_nullifier_tree_snapshot); + write(buf, obj.end_nullifier_tree_snapshots); + write(buf, obj.new_commitments_subtree_root); + write(buf, obj.new_nullifiers_subtree_root); + write(buf, obj.new_contract_leaves_subtree_root); + write(buf, obj.new_commitments_hash); + write(buf, obj.new_nullifiers_hash); + write(buf, obj.new_l1_msgs_hash); + write(buf, obj.new_contract_data_hash); + write(buf, obj.prover_contributions_hash); +}; + +template std::ostream& operator<<(std::ostream& os, BaseRollupPublicInputs const& obj) +{ + return os << "rollup_type: " << obj.rollup_type + << "\n" + "end_aggregation_object:\n" + << obj.end_aggregation_object + << "\n" + "constants:\n" + << obj.constants + << "\n" + "start_nullifier_tree_snapshot:\n" + << obj.start_nullifier_tree_snapshot + << "\n" + "end_nullifier_tree_snapshots:\n" + << obj.end_nullifier_tree_snapshots + << "\n" + "new_commitments_subtree_root: " + << obj.new_commitments_subtree_root + << "\n" + "new_nullifiers_subtree_root: " + << obj.new_nullifiers_subtree_root + << "\n" + "new_contract_leaves_subtree_root: " + << obj.new_contract_leaves_subtree_root + << "\n" + "new_commitments_hash: " + << obj.new_commitments_hash + << "\n" + "new_nullifiers_hash: " + << obj.new_nullifiers_hash + << "\n" + "new_l1_msgs_hash: " + << obj.new_l1_msgs_hash + << "\n" + "new_contract_data_hash: " + << obj.new_contract_data_hash + << "\n" + "prover_contributions_hash: " + << obj.prover_contributions_hash << "\n"; +} + +} // namespace aztec3::circuits::abis \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp b/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp index fe661aefb8f..5ce3a264382 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp +++ b/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp @@ -7,6 +7,7 @@ #include "tx_context.hpp" #include "function_leaf_preimage.hpp" #include "base_rollup/base_rollup_inputs.hpp" +#include "base_rollup/base_rollup_public_inputs.hpp" #include "private_kernel/previous_kernel_data.hpp" #include @@ -97,6 +98,20 @@ template static const char* as_string_output(uint8_t const* input_b return bbmalloc_copy_string(str.c_str(), *size); } +/** + * For testing only. Take this object, serialize it to a buffer, then output it. */ +template static const char* as_serialized_output(uint8_t const* input_buf, uint32_t* size) +{ + T obj; + read(input_buf, obj); + std::vector stream; + write(stream, obj); + *size = (uint32_t)stream.size(); + return bbmalloc_copy_string((char*)stream.data(), *size); +} + +#define WASM_EXPORT __attribute__((visibility("default"))) +// WASM Cbinds extern "C" { /** @@ -318,4 +333,17 @@ WASM_EXPORT const char* abis__test_roundtrip_serialize_previous_kernel_data(uint { return as_string_output>(kernel_data_buf, size); } + +WASM_EXPORT const char* abis__test_roundtrip_serialize_base_rollup_public_inputs(uint8_t const* rollup_inputs_buf, + uint32_t* size) +{ + return as_string_output>(rollup_inputs_buf, size); +} + +WASM_EXPORT const char* abis__test_roundtrip_reserialize_base_rollup_public_inputs(uint8_t const* rollup_inputs_buf, + uint32_t* size) +{ + return as_serialized_output>(rollup_inputs_buf, size); +} + } // extern "C" diff --git a/circuits/ts/src/structs/__snapshots__/base_rollup.test.ts.snap b/circuits/ts/src/structs/__snapshots__/base_rollup.test.ts.snap index 57319e04034..8777462fc2a 100644 --- a/circuits/ts/src/structs/__snapshots__/base_rollup.test.ts.snap +++ b/circuits/ts/src/structs/__snapshots__/base_rollup.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`structs/base_rollup serializes and prints object 1`] = ` +exports[`structs/base_rollup serializes and prints BaseRollupInputs 1`] = ` "kernel_data: [ public_inputs: end: aggregation_object: @@ -478,11 +478,64 @@ tree_of_historic_l1_to_l2_msg_tree_roots_snapshot: root: 0x300 next_available_leaf_index: 768 -private_kernel_vk_tree_root: 0x400 -public_kernel_vk_tree_root: 0x500 -base_rollup_vk_hash: 0x600 -merge_rollup_vk_hash: 0x700 +private_kernel_vk_tree_root: 0x401 +public_kernel_vk_tree_root: 0x402 +base_rollup_vk_hash: 0x403 +merge_rollup_vk_hash: 0x404 prover_id: 0x42 " `; + +exports[`structs/base_rollup serializes and prints BaseRollupPublicInputs 1`] = ` +"rollup_type: 0 +end_aggregation_object: +P0: { 0x100, 0x101 } +P1: { 0x200, 0x201 } +public_inputs: +[ + 0x102 + 0x103 + 0x104 + 0x105 +] +proof_witness_indices: +[ 262 263 264 265 266 267 ] +has_data: 0 + +constants: +start_tree_of_historic_private_data_tree_roots_snapshot: + root: 0x200 +next_available_leaf_index: 512 + +start_tree_of_historic_contract_tree_roots_snapshot: +root: 0x300 +next_available_leaf_index: 768 + +tree_of_historic_l1_to_l2_msg_tree_roots_snapshot: +root: 0x400 +next_available_leaf_index: 1024 + +private_kernel_vk_tree_root: 0x501 +public_kernel_vk_tree_root: 0x502 +base_rollup_vk_hash: 0x503 +merge_rollup_vk_hash: 0x504 + +start_nullifier_tree_snapshot: +root: 0x300 +next_available_leaf_index: 768 + +end_nullifier_tree_snapshots: +root: 0x400 +next_available_leaf_index: 1024 + +new_commitments_subtree_root: 0x501 +new_nullifiers_subtree_root: 0x502 +new_contract_leaves_subtree_root: 0x503 +new_commitments_hash: 0x601 +new_nullifiers_hash: 0x602 +new_l1_msgs_hash: 0x603 +new_contract_data_hash: 0x604 +prover_contributions_hash: 0x605 +" +`; diff --git a/circuits/ts/src/structs/base_rollup.test.ts b/circuits/ts/src/structs/base_rollup.test.ts index c779ec8b03d..61b276c1735 100644 --- a/circuits/ts/src/structs/base_rollup.test.ts +++ b/circuits/ts/src/structs/base_rollup.test.ts @@ -1,12 +1,20 @@ -import { expectSerializeToMatchSnapshot } from "../tests/expectSerializeToMatchSnapshot.js"; -import { fr, makePreviousKernelData } from "../tests/factories.js"; -import { writeGlobalVerifierReferenceString } from "../tests/writeGlobalVerifierReferenceString"; +import { + expectReserializeToMatchObject, + expectSerializeToMatchSnapshot, +} from "../tests/expectSerialize.js"; +import { + fr, + makeAppendOnlyTreeSnapshot, + makeBaseRollupPublicInputs, + makeConstantBaseRollupData, + makePreviousKernelData, +} from "../tests/factories.js"; +import { writeGlobalVerifierReferenceString } from "../tests/writeGlobalVerifierReferenceString.js"; import { range } from "../utils/jsUtils.js"; import { CircuitsWasm } from "../wasm/circuits_wasm.js"; import { - AppendOnlyTreeSnapshot, BaseRollupInputs, - ConstantBaseRollupData, + BaseRollupPublicInputs, NullifierLeafPreimage, } from "./base_rollup.js"; import { @@ -19,16 +27,13 @@ import { PreviousKernelData } from "./kernel.js"; import { MembershipWitness } from "./shared.js"; describe("structs/base_rollup", () => { - it(`serializes and prints object`, async () => { + it(`serializes and prints BaseRollupInputs`, async () => { const kernelData: [PreviousKernelData, PreviousKernelData] = [ makePreviousKernelData(0x100), makePreviousKernelData(0x200), ]; - const startNullifierTreeSnapshot = new AppendOnlyTreeSnapshot( - fr(0x100), - 0x100 - ); + const startNullifierTreeSnapshot = makeAppendOnlyTreeSnapshot(0x100); const lowNullifierLeafPreimages = range( 2 * KERNEL_NEW_NULLIFIERS_LENGTH, @@ -52,22 +57,7 @@ describe("structs/base_rollup", () => { MembershipWitness.mock(CONTRACT_TREE_ROOTS_TREE_HEIGHT, 0x6000), ]; - const constants = ConstantBaseRollupData.from({ - startTreeOfHistoricPrivateDataTreeRootsSnapshot: - new AppendOnlyTreeSnapshot(fr(0x100), 0x100), - startTreeOfHistoricContractTreeRootsSnapshot: new AppendOnlyTreeSnapshot( - fr(0x200), - 0x200 - ), - treeOfHistoricL1ToL2MsgTreeRootsSnapshot: new AppendOnlyTreeSnapshot( - fr(0x300), - 0x300 - ), - privateKernelVkTreeRoot: fr(0x400), - publicKernelVkTreeRoot: fr(0x500), - baseRollupVkHash: fr(0x600), - mergeRollupVkHash: fr(0x700), - }); + const constants = makeConstantBaseRollupData(0x100); const proverId = fr(0x42); @@ -93,4 +83,23 @@ describe("structs/base_rollup", () => { wasm ); }); + + it(`serializes and prints BaseRollupPublicInputs`, async () => { + const baseRollupPublicInputs = makeBaseRollupPublicInputs(); + + await expectSerializeToMatchSnapshot( + baseRollupPublicInputs.toBuffer(), + "abis__test_roundtrip_serialize_base_rollup_public_inputs" + ); + }); + + it(`serializes and deserializes BaseRollupPublicInputs`, async () => { + const baseRollupPublicInputs = makeBaseRollupPublicInputs(); + + await expectReserializeToMatchObject( + baseRollupPublicInputs, + "abis__test_roundtrip_reserialize_base_rollup_public_inputs", + BaseRollupPublicInputs.fromBuffer + ); + }); }); diff --git a/circuits/ts/src/structs/base_rollup.ts b/circuits/ts/src/structs/base_rollup.ts index 1697089ade0..046e0ee4eb2 100644 --- a/circuits/ts/src/structs/base_rollup.ts +++ b/circuits/ts/src/structs/base_rollup.ts @@ -1,3 +1,4 @@ +import { BufferReader } from "../wasm/buffer_reader.js"; import { assertLength, FieldsOf } from "../utils/jsUtils.js"; import { serializeToBuffer } from "../wasm/serialize.js"; import { @@ -27,6 +28,11 @@ export class AppendOnlyTreeSnapshot { toBuffer() { return serializeToBuffer(this.root, this.nextAvailableLeafIndex); } + + static fromBuffer(buffer: Buffer | BufferReader): AppendOnlyTreeSnapshot { + const reader = BufferReader.asReader(buffer); + return new AppendOnlyTreeSnapshot(reader.readFr(), reader.readNumber()); + } } export class ConstantBaseRollupData { @@ -51,6 +57,19 @@ export class ConstantBaseRollupData { ); } + static fromBuffer(buffer: Buffer | BufferReader): ConstantBaseRollupData { + const reader = BufferReader.asReader(buffer); + return new ConstantBaseRollupData( + reader.readObject(AppendOnlyTreeSnapshot), + reader.readObject(AppendOnlyTreeSnapshot), + reader.readObject(AppendOnlyTreeSnapshot), + reader.readFr(), + reader.readFr(), + reader.readFr(), + reader.readFr() + ); + } + static getFields(fields: FieldsOf) { return [ fields.startTreeOfHistoricPrivateDataTreeRootsSnapshot, @@ -128,7 +147,7 @@ export class BaseRollupInputs { } } -enum RollupTypes { +export enum RollupTypes { Base = 0, Rollup = 1, } @@ -138,7 +157,7 @@ enum RollupTypes { */ export class BaseRollupPublicInputs { constructor( - public rollupType: RollupTypes.Base, + public rollupType: RollupTypes, public endAggregationObject: AggregationObject, public constants: ConstantBaseRollupData, @@ -159,8 +178,27 @@ export class BaseRollupPublicInputs { public proverContributionsHash: Fr ) {} - static fromBuffer(buffer: Buffer): BaseRollupPublicInputs { - throw new Error("Not implemented"); + /** + * Deserializes from a buffer or reader, corresponding to a write in cpp. + * @param bufferReader - Buffer to read from. + */ + static fromBuffer(buffer: Buffer | BufferReader): BaseRollupPublicInputs { + const reader = BufferReader.asReader(buffer); + return new BaseRollupPublicInputs( + reader.readNumber(), + reader.readObject(AggregationObject), + reader.readObject(ConstantBaseRollupData), + reader.readObject(AppendOnlyTreeSnapshot), + reader.readObject(AppendOnlyTreeSnapshot), + reader.readFr(), + reader.readFr(), + reader.readFr(), + reader.readFr(), + reader.readFr(), + reader.readFr(), + reader.readFr(), + reader.readFr() + ); } /** @@ -169,7 +207,7 @@ export class BaseRollupPublicInputs { */ toBuffer() { return serializeToBuffer( - this.rollupType.valueOf(), // TODO: Check the size of the enum in cpp land + this.rollupType.valueOf(), this.endAggregationObject, this.constants, diff --git a/circuits/ts/src/structs/function_data.test.ts b/circuits/ts/src/structs/function_data.test.ts index 01e1c0a3955..1ca65c7ed9c 100644 --- a/circuits/ts/src/structs/function_data.test.ts +++ b/circuits/ts/src/structs/function_data.test.ts @@ -1,4 +1,4 @@ -import { expectSerializeToMatchSnapshot } from "../tests/expectSerializeToMatchSnapshot.js"; +import { expectSerializeToMatchSnapshot } from "../tests/expectSerialize.js"; import { FunctionData } from "./function_data.js"; describe("basic FunctionData serialization", () => { diff --git a/circuits/ts/src/structs/kernel.test.ts b/circuits/ts/src/structs/kernel.test.ts index 3eaa77b7a9e..254764bafb9 100644 --- a/circuits/ts/src/structs/kernel.test.ts +++ b/circuits/ts/src/structs/kernel.test.ts @@ -1,4 +1,4 @@ -import { expectSerializeToMatchSnapshot } from "../tests/expectSerializeToMatchSnapshot.js"; +import { expectSerializeToMatchSnapshot } from "../tests/expectSerialize.js"; import { makePreviousKernelData } from "../tests/factories.js"; import { writeGlobalVerifierReferenceString } from "../tests/writeGlobalVerifierReferenceString.js"; import { CircuitsWasm } from "../wasm/circuits_wasm.js"; diff --git a/circuits/ts/src/structs/private_circuit_public_inputs.test.ts b/circuits/ts/src/structs/private_circuit_public_inputs.test.ts index 54e7750d8e1..c69d2e3b51f 100644 --- a/circuits/ts/src/structs/private_circuit_public_inputs.test.ts +++ b/circuits/ts/src/structs/private_circuit_public_inputs.test.ts @@ -1,4 +1,4 @@ -import { expectSerializeToMatchSnapshot } from "../tests/expectSerializeToMatchSnapshot.js"; +import { expectSerializeToMatchSnapshot } from "../tests/expectSerialize.js"; import { fr } from "../tests/factories.js"; import { range } from "../utils/jsUtils.js"; import { numToUInt32BE } from "../wasm/serialize.js"; diff --git a/circuits/ts/src/structs/shared.ts b/circuits/ts/src/structs/shared.ts index 909f130e323..75f65db4415 100644 --- a/circuits/ts/src/structs/shared.ts +++ b/circuits/ts/src/structs/shared.ts @@ -1,3 +1,4 @@ +import { BufferReader } from "../wasm/buffer_reader.js"; import { checkLength, range } from "../utils/jsUtils.js"; import { Bufferable, @@ -6,7 +7,7 @@ import { } from "../wasm/serialize.js"; abstract class Field { - static SIZE_IN_BYTES = 32; + public static SIZE_IN_BYTES = 32; private buffer: Buffer; @@ -28,7 +29,7 @@ abstract class Field { } } - abstract maxValue(): BigInt; + abstract maxValue(): bigint; toString() { return "0x" + this.buffer.toString("hex"); @@ -41,7 +42,7 @@ abstract class Field { export class Fr extends Field { /** - * Maximum represntable value in a field is the curve prime minus one + * Maximum represntable value in a field is the curve prime minus one. * @returns 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000n */ maxValue() { @@ -49,12 +50,17 @@ export class Fr extends Field { 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001n - 1n ); } + + static fromBuffer(buffer: Buffer | BufferReader) { + const reader = BufferReader.asReader(buffer); + return new this(reader.readBytes(this.SIZE_IN_BYTES)); + } } export class Fq extends Field { /** - * Maximum represntable vaue in a field is the curve prime minus one - * TODO: Find out actual max value for Fq + * Maximum represntable vaue in a field is the curve prime minus one. + * TODO: Find out actual max value for Fq. * @returns 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000n */ maxValue() { @@ -62,6 +68,11 @@ export class Fq extends Field { 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001n - 1n ); } + + static fromBuffer(buffer: Buffer | BufferReader) { + const reader = BufferReader.asReader(buffer); + return new this(reader.readBytes(this.SIZE_IN_BYTES)); + } } /** @@ -120,8 +131,6 @@ export class MembershipWitness { } export class AggregationObject { - public hasData: false = false; - public publicInputs: Vector; public proofWitnessIndices: Vector; @@ -129,7 +138,8 @@ export class AggregationObject { public p0: AffineElement, public p1: AffineElement, publicInputsData: Fr[], - proofWitnessIndicesData: UInt32[] + proofWitnessIndicesData: UInt32[], + public hasData = false ) { this.publicInputs = new Vector(publicInputsData); this.proofWitnessIndices = new Vector(proofWitnessIndicesData); @@ -144,6 +154,17 @@ export class AggregationObject { this.hasData ); } + + static fromBuffer(buffer: Buffer | BufferReader): AggregationObject { + const reader = BufferReader.asReader(buffer); + return new AggregationObject( + reader.readObject(AffineElement), + reader.readObject(AffineElement), + reader.readVector(Fr), + reader.readNumberVector(), + reader.readBoolean() + ); + } } export class Vector { @@ -168,7 +189,7 @@ export type UInt32 = number; export type AztecAddress = Fr; /** - * Affine element of a group, composed of two elements in Fq + * Affine element of a group, composed of two elements in Fq. * cpp/barretenberg/cpp/src/aztec/ecc/groups/affine_element.hpp * cpp/barretenberg/cpp/src/aztec/ecc/curves/bn254/g1.hpp */ @@ -178,6 +199,11 @@ export class AffineElement { toBuffer() { return serializeToBuffer(this.x, this.y); } + + static fromBuffer(buffer: Buffer | BufferReader): AffineElement { + const reader = BufferReader.asReader(buffer); + return new AffineElement(reader.readFq(), reader.readFq()); + } } /** diff --git a/circuits/ts/src/structs/tx.test.ts b/circuits/ts/src/structs/tx.test.ts index 9279e619389..bee7d191c21 100644 --- a/circuits/ts/src/structs/tx.test.ts +++ b/circuits/ts/src/structs/tx.test.ts @@ -1,4 +1,4 @@ -import { expectSerializeToMatchSnapshot } from "../tests/expectSerializeToMatchSnapshot.js"; +import { expectSerializeToMatchSnapshot } from "../tests/expectSerialize.js"; import { makeTxContext } from "../tests/factories.js"; describe("structs/tx", () => { diff --git a/circuits/ts/src/structs/tx.ts b/circuits/ts/src/structs/tx.ts index f4086be051a..40f3b67a07f 100644 --- a/circuits/ts/src/structs/tx.ts +++ b/circuits/ts/src/structs/tx.ts @@ -2,7 +2,7 @@ import { serializeToBuffer } from "../wasm/serialize.js"; import { EthAddress, Fr } from "./shared.js"; /** - * Contract deployment data in a @TxContext. + * Contract deployment data in a TxContext * cpp/src/aztec3/circuits/abis/contract_deployment_data.hpp */ export class ContractDeploymentData { diff --git a/circuits/ts/src/tests/expectSerializeToMatchSnapshot.ts b/circuits/ts/src/tests/expectSerialize.ts similarity index 58% rename from circuits/ts/src/tests/expectSerializeToMatchSnapshot.ts rename to circuits/ts/src/tests/expectSerialize.ts index dac579b5f0d..6f370bb26ad 100644 --- a/circuits/ts/src/tests/expectSerializeToMatchSnapshot.ts +++ b/circuits/ts/src/tests/expectSerialize.ts @@ -17,19 +17,21 @@ function simplifyHexValues(input: string) { } /** - * Test utility. Checks a buffer serialize against a snapshot. + * Test utility. Sends a serialized buffer to wasm and gets the result. * @param inputBuf - Buffer to write. * @param serializeMethod - Method to use buffer with. + * @param wasm - Optional circuit wasm. */ -export async function expectSerializeToMatchSnapshot( +async function callWasm( inputBuf: Buffer, serializeMethod: string, wasm?: CircuitsWasm -) { +): Promise { wasm = wasm || (await CircuitsWasm.new()); const inputBufPtr = wasm.call("bbmalloc", inputBuf.length); wasm.writeMemory(inputBufPtr, inputBuf); const outputBufSizePtr = wasm.call("bbmalloc", 4); + // Get a string version of our object. As a quick and dirty test, // we compare a snapshot of its string form to its previous form. const outputBufPtr = wasm.call( @@ -37,18 +39,55 @@ export async function expectSerializeToMatchSnapshot( inputBufPtr, outputBufSizePtr ); + // Read the size pointer const outputBufSize = uint8ArrayToNum( wasm.getMemorySlice(outputBufSizePtr, outputBufSizePtr + 4) ); - const outputBuf = wasm.getMemorySlice( - outputBufPtr, - outputBufPtr + outputBufSize + + // Copy into our own buffer + const outputBuf = Buffer.from( + wasm.getMemorySlice(outputBufPtr, outputBufPtr + outputBufSize) ); - const outputStr = simplifyHexValues(Buffer.from(outputBuf).toString("utf-8")); - expect(outputStr).toMatchSnapshot(); + // Free memory wasm.call("bbfree", outputBufPtr); wasm.call("bbfree", outputBufSizePtr); wasm.call("bbfree", inputBufPtr); + + return outputBuf; +} + +/** + * Test utility. Checks a buffer serialize against a snapshot. + * @param inputBuf - Buffer to write. + * @param serializeMethod - Method to use buffer with. + */ +export async function expectSerializeToMatchSnapshot( + inputBuf: Buffer, + serializeMethod: string, + wasm?: CircuitsWasm +) { + const outputBuf = await callWasm(inputBuf, serializeMethod, wasm); + const outputStr = simplifyHexValues(Buffer.from(outputBuf).toString("utf-8")); + expect(outputStr).toMatchSnapshot(); +} + +/** + * Test utility. Serializes an object, passes it to a wasm reserialize method, + * gets it back, deserializes it, and checks it matches the original. + * @param inputObj - Object to check. + * @param serializeMethod - Wasm method to send and get back the object. + */ +export async function expectReserializeToMatchObject< + T extends { toBuffer: () => Buffer } +>( + inputObj: T, + serializeMethod: string, + deserialize: (buf: Buffer) => T, + wasm?: CircuitsWasm +) { + const outputBuf = await callWasm(inputObj.toBuffer(), serializeMethod, wasm); + const deserializedObj = deserialize(outputBuf); + expect(deserializedObj).toEqual(deserializedObj); } diff --git a/circuits/ts/src/tests/factories.ts b/circuits/ts/src/tests/factories.ts index afe6c782a1a..fbad393734a 100644 --- a/circuits/ts/src/tests/factories.ts +++ b/circuits/ts/src/tests/factories.ts @@ -1,3 +1,9 @@ +import { + AppendOnlyTreeSnapshot, + BaseRollupPublicInputs, + ConstantBaseRollupData, + RollupTypes, +} from "../structs/base_rollup.js"; import { EMITTED_EVENTS_LENGTH, KERNEL_L1_MSG_STACK_LENGTH, @@ -52,11 +58,11 @@ export function makeOldTreeRoots(seed: number): OldTreeRoots { return new OldTreeRoots(fr(seed), fr(seed + 1), fr(seed + 2), fr(seed + 3)); } -export function makeConstantData(seed: number = 1): ConstantData { +export function makeConstantData(seed = 1): ConstantData { return new ConstantData(makeOldTreeRoots(seed), makeTxContext(seed + 4)); } -export function makeAccumulatedData(seed: number = 1): AccumulatedData { +export function makeAccumulatedData(seed = 1): AccumulatedData { return new AccumulatedData( makeAggregationObject(seed), fr(seed + 12), @@ -72,13 +78,11 @@ export function makeAccumulatedData(seed: number = 1): AccumulatedData { ); } -export function makeNewContractData(seed: number = 1): NewContractData { +export function makeNewContractData(seed = 1): NewContractData { return new NewContractData(fr(seed), makeEthAddress(seed + 1), fr(seed + 2)); } -export function makeOptionallyRevealedData( - seed: number = 1 -): OptionallyRevealedData { +export function makeOptionallyRevealedData(seed = 1): OptionallyRevealedData { return new OptionallyRevealedData( fr(seed), new FunctionData(seed + 1, true, true), @@ -92,7 +96,7 @@ export function makeOptionallyRevealedData( ); } -export function makeAggregationObject(seed: number = 1): AggregationObject { +export function makeAggregationObject(seed = 1): AggregationObject { return new AggregationObject( new AffineElement(new Fq(seed), new Fq(seed + 1)), new AffineElement(new Fq(seed + 0x100), new Fq(seed + 0x101)), @@ -102,7 +106,7 @@ export function makeAggregationObject(seed: number = 1): AggregationObject { } export function makePrivateKernelPublicInputs( - seed: number = 1 + seed = 1 ): PrivateKernelPublicInputs { return new PrivateKernelPublicInputs( makeAccumulatedData(seed), @@ -134,7 +138,7 @@ export function makeVerificationKey(): VerificationKey { range(5, 400) ); } -export function makePreviousKernelData(seed: number = 1): PreviousKernelData { +export function makePreviousKernelData(seed = 1): PreviousKernelData { return new PreviousKernelData( makePrivateKernelPublicInputs(seed), makeDynamicSizeBuffer(16, seed + 0x80), @@ -144,10 +148,49 @@ export function makePreviousKernelData(seed: number = 1): PreviousKernelData { ); } -export function makeEthAddress(seed: number = 1): EthAddress { +export function makeConstantBaseRollupData(seed = 1): ConstantBaseRollupData { + return ConstantBaseRollupData.from({ + startTreeOfHistoricPrivateDataTreeRootsSnapshot: + makeAppendOnlyTreeSnapshot(seed), + startTreeOfHistoricContractTreeRootsSnapshot: makeAppendOnlyTreeSnapshot( + seed + 0x100 + ), + treeOfHistoricL1ToL2MsgTreeRootsSnapshot: makeAppendOnlyTreeSnapshot( + seed + 0x200 + ), + privateKernelVkTreeRoot: fr(seed + 0x301), + publicKernelVkTreeRoot: fr(seed + 0x302), + baseRollupVkHash: fr(seed + 0x303), + mergeRollupVkHash: fr(seed + 0x304), + }); +} + +export function makeAppendOnlyTreeSnapshot(seed = 1): AppendOnlyTreeSnapshot { + return new AppendOnlyTreeSnapshot(fr(seed), seed); +} + +export function makeEthAddress(seed = 1): EthAddress { return new EthAddress(Buffer.alloc(20, seed)); } +export function makeBaseRollupPublicInputs(seed = 0) { + return new BaseRollupPublicInputs( + RollupTypes.Base, + makeAggregationObject(seed + 0x100), + makeConstantBaseRollupData(seed + 0x200), + makeAppendOnlyTreeSnapshot(seed + 0x300), + makeAppendOnlyTreeSnapshot(seed + 0x400), + fr(seed + 0x501), + fr(seed + 0x502), + fr(seed + 0x503), + fr(seed + 0x601), + fr(seed + 0x602), + fr(seed + 0x603), + fr(seed + 0x604), + fr(seed + 0x605) + ); +} + /** * Test only. Easy to identify big endian field serialize. * @param num - The number. diff --git a/circuits/ts/src/utils/jsUtils.ts b/circuits/ts/src/utils/jsUtils.ts index c4256b66238..f0e06fe512d 100644 --- a/circuits/ts/src/utils/jsUtils.ts +++ b/circuits/ts/src/utils/jsUtils.ts @@ -38,7 +38,7 @@ export function assertLength< export function checkLength( arr: { length: number }, expected: number, - label: string = "array" + label = "array" ) { if (arr.length !== expected) { throw new Error( diff --git a/circuits/ts/src/wasm/buffer_reader.ts b/circuits/ts/src/wasm/buffer_reader.ts new file mode 100644 index 00000000000..87742da3291 --- /dev/null +++ b/circuits/ts/src/wasm/buffer_reader.ts @@ -0,0 +1,64 @@ +import { Fq, Fr } from "../structs/shared.js"; + +export class BufferReader { + private index: number; + constructor(private buffer: Buffer, offset = 0) { + this.index = offset; + } + + public static asReader(bufferOrReader: Buffer | BufferReader) { + return Buffer.isBuffer(bufferOrReader) + ? new BufferReader(bufferOrReader) + : bufferOrReader; + } + + public readNumber(): number { + this.index += 4; + return this.buffer.readUint32BE(this.index - 4); + } + + public readBoolean(): boolean { + this.index += 1; + return Boolean(this.buffer.at(this.index - 1)); + } + + public readBytes(n: number): Buffer { + this.index += n; + return Buffer.from(this.buffer.subarray(this.index - n, this.index)); + } + + public readFr(): Fr { + return Fr.fromBuffer(this); + } + + public readFq(): Fq { + return Fq.fromBuffer(this); + } + + public readNumberVector(): number[] { + return this.readVector({ + fromBuffer: (reader: BufferReader) => reader.readNumber(), + }); + } + + public readVector(itemDeserializer: { + fromBuffer: (reader: BufferReader) => T; + }): T[] { + const size = this.readNumber(); + const result = new Array(size); + for (let i = 0; i < size; i++) { + result[i] = itemDeserializer.fromBuffer(this); + } + return result; + } + + public readObject(deserializer: { + fromBuffer: (reader: BufferReader) => T; + }): T { + return deserializer.fromBuffer(this); + } + + public peekBytes(n?: number): Buffer { + return this.buffer.subarray(this.index, n ? this.index + n : undefined); + } +} From 7b17f07eafb607cd2fe1ce191f548dcf40e4e8a6 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Thu, 23 Mar 2023 10:51:50 -0300 Subject: [PATCH 086/166] Ts structs for root and merge rollups (#81) --- circuits/ts/src/structs/base_rollup.ts | 13 +-- circuits/ts/src/structs/index.ts | 11 +++ circuits/ts/src/structs/merge_rollup.ts | 114 +++++++++++++++++++++++ circuits/ts/src/structs/root_rollup.ts | 119 ++++++++++++++++++++++++ circuits/ts/src/structs/shared.ts | 9 ++ circuits/ts/src/tests/factories.ts | 2 +- 6 files changed, 261 insertions(+), 7 deletions(-) create mode 100644 circuits/ts/src/structs/index.ts create mode 100644 circuits/ts/src/structs/merge_rollup.ts create mode 100644 circuits/ts/src/structs/root_rollup.ts diff --git a/circuits/ts/src/structs/base_rollup.ts b/circuits/ts/src/structs/base_rollup.ts index 046e0ee4eb2..df9dd522e25 100644 --- a/circuits/ts/src/structs/base_rollup.ts +++ b/circuits/ts/src/structs/base_rollup.ts @@ -8,7 +8,13 @@ import { PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT, } from "./constants.js"; import { PreviousKernelData } from "./kernel.js"; -import { AggregationObject, Fr, MembershipWitness, UInt32 } from "./shared.js"; +import { + AggregationObject, + Fr, + MembershipWitness, + RollupTypes, + UInt32, +} from "./shared.js"; export class NullifierLeafPreimage { constructor( @@ -147,11 +153,6 @@ export class BaseRollupInputs { } } -export enum RollupTypes { - Base = 0, - Rollup = 1, -} - /** * Output of the base rollup circuit */ diff --git a/circuits/ts/src/structs/index.ts b/circuits/ts/src/structs/index.ts new file mode 100644 index 00000000000..987b106ef33 --- /dev/null +++ b/circuits/ts/src/structs/index.ts @@ -0,0 +1,11 @@ +export * from "./base_rollup.js"; +export * from "./call_context.js"; +export * from "./constants.js"; +export * from "./function_data.js"; +export * from "./kernel.js"; +export * from "./merge_rollup.js"; +export * from "./private_circuit_public_inputs.js"; +export * from "./root_rollup.js"; +export * from "./shared.js"; +export * from "./tx.js"; +export * from "./verification_key.js"; diff --git a/circuits/ts/src/structs/merge_rollup.ts b/circuits/ts/src/structs/merge_rollup.ts new file mode 100644 index 00000000000..bdb7dcfd855 --- /dev/null +++ b/circuits/ts/src/structs/merge_rollup.ts @@ -0,0 +1,114 @@ +import { assertLength, FieldsOf } from "../utils/jsUtils.js"; +import { serializeToBuffer } from "../wasm/serialize.js"; +import { + AppendOnlyTreeSnapshot, + BaseRollupPublicInputs, + ConstantBaseRollupData, +} from "./base_rollup.js"; +import { VK_TREE_HEIGHT } from "./constants.js"; +import { + AggregationObject, + Fr, + UInt32, + UInt8Vector, + RollupTypes, +} from "./shared.js"; +import { VerificationKey } from "./verification_key.js"; + +export class PreviousRollupData { + constructor( + public publicInputs: BaseRollupPublicInputs | MergeRollupPublicInputs, + public proof: UInt8Vector, + public vk: VerificationKey, + /** + * The index of the rollup circuit's vk in a big tree of rollup circuit vks. + */ + public vkIndex: UInt32, + public vkSiblingPath: Fr[] + ) { + assertLength(this, "vkSiblingPath", VK_TREE_HEIGHT); + } + + toBuffer() { + return serializeToBuffer( + this.publicInputs, + this.proof, + this.vk, + this.vkIndex, + this.vkSiblingPath + ); + } +} + +export class MergeRollupInputs { + constructor( + public previousRollupData: [PreviousRollupData, PreviousRollupData], + public proverId: Fr + ) {} + + toBuffer() { + return serializeToBuffer(this.previousRollupData, this.proverId); + } +} + +export class MergeRollupPublicInputs { + public rollupType: RollupTypes = RollupTypes.Merge; + + constructor( + /** + * Tells us how many layers of recursion we've done, to help with subtree insertion in the root rollup circuit. + */ + public rollupSubtreeHeight: Fr, + + public endAggregationObject: AggregationObject, + + public constants: ConstantBaseRollupData, + + // The only tree root actually updated in this circuit is the nullifier tree, because earlier leaves (of low_nullifiers) must be updated to point to the new nullifiers in this circuit. + public startNullifierTreeSnapshot: AppendOnlyTreeSnapshot, + public endNullifierTreeSnapshot: AppendOnlyTreeSnapshot, + + public newCommitmentsSubtreeRoot: Fr, + public newNullifiersSubtreeRoot: Fr, + public newContractLeavesSubtreeRoot: Fr, + + // Hashes (probably sha256) to make public inputs constant-sized (to then be unpacked on-chain) + // UPDATE: we should instead just hash all of the below into a single value. See big diagram of sha256 hashing bottom-right of here. + // TODO: I've put `fr`, but these hash values' types might need to be two fields if we want all 256-bits, for security purposes. + public newCommitmentsHash: Fr, + public newNullifiersHash: Fr, + public newL1MsgsHash: Fr, + public newContractDataHash: Fr, + public proverContributionsHash: Fr + ) {} + + static getFields(fields: FieldsOf) { + return [ + fields.rollupSubtreeHeight, + fields.endAggregationObject, + fields.constants, + fields.startNullifierTreeSnapshot, + fields.endNullifierTreeSnapshot, + fields.newCommitmentsSubtreeRoot, + fields.newNullifiersSubtreeRoot, + fields.newContractLeavesSubtreeRoot, + fields.newCommitmentsHash, + fields.newNullifiersHash, + fields.newL1MsgsHash, + fields.newContractDataHash, + fields.proverContributionsHash, + ] as const; + } + + toBuffer() { + return serializeToBuffer(...MergeRollupPublicInputs.getFields(this)); + } + + static from( + fields: FieldsOf + ): MergeRollupPublicInputs { + return new MergeRollupPublicInputs( + ...MergeRollupPublicInputs.getFields(fields) + ); + } +} diff --git a/circuits/ts/src/structs/root_rollup.ts b/circuits/ts/src/structs/root_rollup.ts new file mode 100644 index 00000000000..9308e8eae5b --- /dev/null +++ b/circuits/ts/src/structs/root_rollup.ts @@ -0,0 +1,119 @@ +import { assertLength, FieldsOf } from "../utils/jsUtils.js"; +import { serializeToBuffer } from "../wasm/serialize.js"; +import { AppendOnlyTreeSnapshot } from "./base_rollup.js"; +import { + CONTRACT_TREE_HEIGHT, + NULLIFIER_TREE_HEIGHT, + PRIVATE_DATA_TREE_HEIGHT, +} from "./constants.js"; +import { PreviousRollupData } from "./merge_rollup.js"; +import { AggregationObject, Fr } from "./shared.js"; + +export class RootRollupInputs { + constructor( + public previousRollupData: [PreviousRollupData, PreviousRollupData], + + public startPrivateDataTreeSnapshot: AppendOnlyTreeSnapshot, + // Note: the start_nullifier_tree_snapshot is contained within previous_rollup_data[0].public_inputs.start_nullifier_tree_snapshot. + public startContractTreeSnapshot: AppendOnlyTreeSnapshot, + + // For inserting the new subtrees into their respective trees: + // Note: the insertion leaf index can be derived from the above snapshots' `next_available_leaf_index` values. + public newCommitmentsSubtreeSiblingPath: Fr[], + public newNullifiersSubtreeSiblingPath: Fr[], + public newContractsSubtreeSiblingPath: Fr[], + + public proverId: Fr + ) { + assertLength( + this, + "newCommitmentsSubtreeSiblingPath", + PRIVATE_DATA_TREE_HEIGHT + ); + assertLength( + this, + "newNullifiersSubtreeSiblingPath", + NULLIFIER_TREE_HEIGHT + ); + assertLength(this, "newContractsSubtreeSiblingPath", CONTRACT_TREE_HEIGHT); + } + + toBuffer() { + return serializeToBuffer( + this.previousRollupData, + this.startPrivateDataTreeSnapshot, + this.startContractTreeSnapshot, + this.newCommitmentsSubtreeSiblingPath, + this.newNullifiersSubtreeSiblingPath, + this.newContractsSubtreeSiblingPath, + this.proverId + ); + } +} + +export class RootRollupPublicInputs { + constructor( + // NOTE: in practice, we'll hash all of this up into a single public input, for cheap on-chain verification. + public endAggregationObject: AggregationObject, + + // constants: ConstantRollupData // TODO maybe don't include this + + public startPrivateDataTreeSnapshot: AppendOnlyTreeSnapshot, + public endPrivateDataTreeSnapshot: AppendOnlyTreeSnapshot, + + public startNullifierTreeSnapshot: AppendOnlyTreeSnapshot, + public endNullifierTreeSnapshot: AppendOnlyTreeSnapshot, + + public startContractTreeSnapshot: AppendOnlyTreeSnapshot, + public endContractTreeSnapshot: AppendOnlyTreeSnapshot, + + public startTreeOfHistoricPrivateDataTreeRootsSnapshot: AppendOnlyTreeSnapshot, + public endTreeOfHistoricPrivateDataTreeRootsSnapshot: AppendOnlyTreeSnapshot, + + public startTreeOfHistoricContractTreeRootsSnapshot: AppendOnlyTreeSnapshot, + public endTreeOfHistoricContractTreeRootsSnapshot: AppendOnlyTreeSnapshot, + + // Hashes (probably sha256) to make public inputs constant-sized + // (to then be unpacked on-chain) + // UPDATE: we should instead just hash all of the below into a single value. See big diagram of sha256 hashing bottom-right of here. + // TODO: I've put `fr`, but these hash values' types might need to be two fields if we want all 256-bits, for security purposes. + public newCommitmentsHash: Fr, + public newNullifiersHash: Fr, + public newL1MsgsHash: Fr, + public newContractDataHash: Fr, + public proverContributionsHash: Fr // TODO: spec how funds are distributed to provers. + ) {} + + static getFields(fields: FieldsOf) { + return [ + fields.endAggregationObject, + fields.startPrivateDataTreeSnapshot, + fields.endPrivateDataTreeSnapshot, + fields.startNullifierTreeSnapshot, + fields.endNullifierTreeSnapshot, + fields.startContractTreeSnapshot, + fields.endContractTreeSnapshot, + fields.startTreeOfHistoricPrivateDataTreeRootsSnapshot, + fields.endTreeOfHistoricPrivateDataTreeRootsSnapshot, + fields.startTreeOfHistoricContractTreeRootsSnapshot, + fields.endTreeOfHistoricContractTreeRootsSnapshot, + fields.newCommitmentsHash, + fields.newNullifiersHash, + fields.newL1MsgsHash, + fields.newContractDataHash, + fields.proverContributionsHash, + ] as const; + } + + toBuffer() { + return serializeToBuffer(...RootRollupPublicInputs.getFields(this)); + } + + static from( + fields: FieldsOf + ): RootRollupPublicInputs { + return new RootRollupPublicInputs( + ...RootRollupPublicInputs.getFields(fields) + ); + } +} diff --git a/circuits/ts/src/structs/shared.ts b/circuits/ts/src/structs/shared.ts index 75f65db4415..cc6feda0446 100644 --- a/circuits/ts/src/structs/shared.ts +++ b/circuits/ts/src/structs/shared.ts @@ -215,3 +215,12 @@ export enum ComposerType { PLOOKUP = 2, STANDARD_HONK = 3, } + +/** + * Rollup types. + */ +export enum RollupTypes { + Base = 0, + Rollup = 1, + Merge = 2, +} diff --git a/circuits/ts/src/tests/factories.ts b/circuits/ts/src/tests/factories.ts index fbad393734a..fe1aa47b40d 100644 --- a/circuits/ts/src/tests/factories.ts +++ b/circuits/ts/src/tests/factories.ts @@ -2,7 +2,6 @@ import { AppendOnlyTreeSnapshot, BaseRollupPublicInputs, ConstantBaseRollupData, - RollupTypes, } from "../structs/base_rollup.js"; import { EMITTED_EVENTS_LENGTH, @@ -34,6 +33,7 @@ import { Fr, MembershipWitness, UInt8Vector, + RollupTypes, } from "../structs/shared.js"; import { ContractDeploymentData, TxContext } from "../structs/tx.js"; import { From 276aaf725bbac6384693301b7b8e25b540d359cd Mon Sep 17 00:00:00 2001 From: David Banks <47112877+dbanks12@users.noreply.github.com> Date: Thu, 23 Mar 2023 10:19:18 -0400 Subject: [PATCH 087/166] feat(cpp): cbind for contract leaf (#83) * cbind for contract leaf --- .../cpp/src/aztec3/circuits/abis/c_bind.cpp | 22 ++++++++++++++++ .../cpp/src/aztec3/circuits/abis/c_bind.h | 3 +++ .../src/aztec3/circuits/abis/c_bind.test.cpp | 26 ++++++++++++++++++- .../abis/private_kernel/new_contract_data.hpp | 11 ++++++++ circuits/cpp/src/aztec3/constants.hpp | 1 + 5 files changed, 62 insertions(+), 1 deletion(-) diff --git a/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp b/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp index 5ce3a264382..284d39ee15c 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp +++ b/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp @@ -1,6 +1,7 @@ #include "c_bind.h" #include "barretenberg/srs/reference_string/mem_reference_string.hpp" #include "aztec3/circuits/abis/function_data.hpp" +#include "aztec3/circuits/abis/private_kernel/new_contract_data.hpp" #include "aztec3/circuits/abis/barretenberg/verifier_reference_string.hpp" #include "private_circuit_public_inputs.hpp" #include "tx_request.hpp" @@ -22,6 +23,7 @@ namespace { using aztec3::circuits::abis::FunctionLeafPreimage; using aztec3::circuits::abis::TxContext; using aztec3::circuits::abis::TxRequest; +using aztec3::circuits::abis::private_kernel::NewContractData; using NT = aztec3::utils::types::NativeTypes; // Cbind helper functions @@ -285,6 +287,26 @@ WASM_EXPORT void abis__compute_contract_address(uint8_t const* deployer_address_ NT::fr::serialize_to_buffer(contract_address, output); } +/** + * @brief Generates a function tree leaf from its preimage. + * This is a WASM-export that can be called from Typescript. + * + * @details given a `uint8_t const*` buffer representing a function leaf's prieimage, + * construct a NewContractData instance, hash, and return the serialized results + * in the `output` buffer. + * + * @param contract_leaf_preimage_buf a buffer of bytes representing the contract leaf's preimage + * contents (`contract_address`, `portal_contract_address`, `function_tree_root`) + * @param output buffer that will contain the output. The hashed and serialized contract leaf. + */ +WASM_EXPORT void abis__compute_contract_leaf(uint8_t const* contract_leaf_preimage_buf, uint8_t* output) +{ + NewContractData leaf_preimage; + read(contract_leaf_preimage_buf, leaf_preimage); + leaf_preimage.hash(); + NT::fr::serialize_to_buffer(leaf_preimage.hash(), output); +} + // TODO(AD): After Milestone 1, rewrite this with better injection mechanism. WASM_EXPORT void abis__set_global_verifier_reference_string(uint8_t* data) { diff --git a/circuits/cpp/src/aztec3/circuits/abis/c_bind.h b/circuits/cpp/src/aztec3/circuits/abis/c_bind.h index 2594d0cb607..dec7efbade0 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/c_bind.h +++ b/circuits/cpp/src/aztec3/circuits/abis/c_bind.h @@ -26,4 +26,7 @@ WASM_EXPORT void abis__compute_contract_address(uint8_t const* deployer_address_ uint8_t const* constructor_hash_buf, uint8_t* output); +WASM_EXPORT void abis__compute_contract_leaf(uint8_t const* contract_leaf_preimage_buf, + uint8_t* output); + } \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp b/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp index b8725bd70e9..3b7bd182580 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp @@ -2,6 +2,7 @@ #include "tx_request.hpp" #include "function_leaf_preimage.hpp" +#include "aztec3/circuits/abis/private_kernel/new_contract_data.hpp" #include #include @@ -10,8 +11,9 @@ namespace { using NT = aztec3::utils::types::NativeTypes; +using aztec3::circuits::abis::private_kernel::NewContractData; + auto& engine = numeric::random::get_debug_engine(); -constexpr size_t FUNCTION_TREE_NUM_LEAVES = 2 << (aztec3::FUNCTION_TREE_HEIGHT - 1); // leaves = 2 ^ height /** * @brief Convert a bytes array to a hex string. @@ -124,6 +126,8 @@ TEST(abi_tests, compute_function_leaf) TEST(abi_tests, compute_function_tree_root) { + constexpr size_t FUNCTION_TREE_NUM_LEAVES = 2 << (aztec3::FUNCTION_TREE_HEIGHT - 1); // leaves = 2 ^ height + NT::fr zero_leaf = FunctionLeafPreimage().hash(); // hash of empty/0 preimage // these frs will be used to compute the root directly (without cbind) // all empty slots will have the zero-leaf to ensure full tree @@ -228,4 +232,24 @@ TEST(abi_tests, compute_contract_address) EXPECT_EQ(got_address, expected_address); } +TEST(abi_tests, compute_contract_leaf) +{ + // Construct ContractLeafPreimage with some randomized fields + NewContractData preimage = NewContractData{ + .contract_address = NT::fr::random_element(), + .portal_contract_address = NT::fr::random_element(), + .function_tree_root = NT::fr::random_element(), + }; + + // Write the leaf preimage to a buffer + std::vector preimage_buf; + write(preimage_buf, preimage); + + std::array output = { 0 }; + abis__compute_contract_leaf(preimage_buf.data(), output.data()); + + NT::fr got_leaf = NT::fr::serialize_from_buffer(output.data()); + EXPECT_EQ(got_leaf, preimage.hash()); +} + } // namespace aztec3::circuits::abis diff --git a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/new_contract_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/new_contract_data.hpp index 0653901aa26..fc3797e8727 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/new_contract_data.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/new_contract_data.hpp @@ -52,6 +52,17 @@ template struct NewContractData { portal_contract_address.to_field().set_public(); function_tree_root.set_public(); } + + fr hash() const + { + std::vector inputs = { + fr(contract_address), + fr(portal_contract_address), + fr(function_tree_root), + }; + + return NCT::compress(inputs, GeneratorIndex::CONTRACT_LEAF); + } }; template void read(uint8_t const*& it, NewContractData& new_contract_data) diff --git a/circuits/cpp/src/aztec3/constants.hpp b/circuits/cpp/src/aztec3/constants.hpp index 34cc233f10c..92b22f488a1 100644 --- a/circuits/cpp/src/aztec3/constants.hpp +++ b/circuits/cpp/src/aztec3/constants.hpp @@ -54,6 +54,7 @@ enum GeneratorIndex { CONTRACT_DEPLOYMENT_DATA, CONSTRUCTOR, CONTRACT_ADDRESS, + CONTRACT_LEAF, CALL_CONTEXT, CALL_STACK_ITEM, CALL_STACK_ITEM_2, // see function where it's used for explanation From 1185781f307b7f03a25bcad808109c3a8a2530f6 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Thu, 23 Mar 2023 11:25:28 -0300 Subject: [PATCH 088/166] fix(ts): Changes for inclusion in aztec3-packages (#85) * Add tsc out folder to gitignore * Add index entrypoint * Expose factories for building mocks * Fix for ts compilation issue * Format * Revert to ts 4.9.5 --- circuits/ts/.gitignore | 1 + circuits/ts/package.json | 5 ++++- circuits/ts/src/index.ts | 1 + circuits/ts/yarn.lock | 4 ++-- 4 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 circuits/ts/src/index.ts diff --git a/circuits/ts/.gitignore b/circuits/ts/.gitignore index 3c3629e647f..ddf1772a082 100644 --- a/circuits/ts/.gitignore +++ b/circuits/ts/.gitignore @@ -1 +1,2 @@ node_modules +/dest \ No newline at end of file diff --git a/circuits/ts/package.json b/circuits/ts/package.json index e1128bd3edb..8e1b10fbdac 100644 --- a/circuits/ts/package.json +++ b/circuits/ts/package.json @@ -2,7 +2,10 @@ "name": "@aztec/circuits.js", "version": "0.0.0", "type": "module", - "exports": "./dest/index.js", + "exports": { + ".": "./dest/index.js", + "./factories": "./dest/tests/factories.js" + }, "typedoc": { "entryPoint": "./src/index.ts", "displayName": "Circuits.js", diff --git a/circuits/ts/src/index.ts b/circuits/ts/src/index.ts new file mode 100644 index 00000000000..7cc1b8550e0 --- /dev/null +++ b/circuits/ts/src/index.ts @@ -0,0 +1 @@ +export * from "./structs/index.js"; diff --git a/circuits/ts/yarn.lock b/circuits/ts/yarn.lock index 1c206c3ef6f..bb43b0a60ad 100644 --- a/circuits/ts/yarn.lock +++ b/circuits/ts/yarn.lock @@ -13,8 +13,8 @@ "@aztec/eslint-config@file:.yalc/@aztec/eslint-config": version "0.0.0" dependencies: - "@aztec/eslint-config" "link:../../../.cache/yarn/v6/npm-@aztec-eslint-config-0.0.0-c3fe19f8-d17b-4602-82af-e13372f32c46-1679061380326/yarn-project/eslint-config" - "@aztec/wasm-worker" "link:../../../.cache/yarn/v6/npm-@aztec-eslint-config-0.0.0-c3fe19f8-d17b-4602-82af-e13372f32c46-1679061380326/yarn-project/wasm-worker" + "@aztec/eslint-config" "link:../../../../.cache/yarn/v6/npm-@aztec-eslint-config-0.0.0-f0ad3e77-4a59-480a-abd1-8333a7ce82c8-1679580896853/yarn-project/eslint-config" + "@aztec/wasm-worker" "link:../../../../.cache/yarn/v6/npm-@aztec-eslint-config-0.0.0-f0ad3e77-4a59-480a-abd1-8333a7ce82c8-1679580896853/yarn-project/wasm-worker" "@typescript-eslint/eslint-plugin" "^5.38.0" "@typescript-eslint/parser" "^5.38.0" eslint "^8.21.0" From da1beff1ed387e72c078a9928aa89a505d7b4a68 Mon Sep 17 00:00:00 2001 From: Suyash Bagad Date: Thu, 23 Mar 2023 22:32:00 +0000 Subject: [PATCH 089/166] update bb. (#90) --- circuits/cpp/barretenberg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circuits/cpp/barretenberg b/circuits/cpp/barretenberg index 85e07cace6d..ce0673fd8af 160000 --- a/circuits/cpp/barretenberg +++ b/circuits/cpp/barretenberg @@ -1 +1 @@ -Subproject commit 85e07cace6d98ab8e6e018646e1eaea39721148b +Subproject commit ce0673fd8afea498aa58018288e68d130f3624b7 From 6c9bccedc88e30f58cae74528b248f51779921c6 Mon Sep 17 00:00:00 2001 From: David Banks <47112877+dbanks12@users.noreply.github.com> Date: Thu, 23 Mar 2023 18:48:31 -0400 Subject: [PATCH 090/166] feat(cpp): cbind for hash_vk (#84) * cbinds for contract leaf and contract tree root * cbind to compress vk data * update bb --------- Co-authored-by: Suyash Bagad --- .../cpp/src/aztec3/circuits/abis/c_bind.cpp | 18 +++++++++++ .../cpp/src/aztec3/circuits/abis/c_bind.h | 2 ++ .../src/aztec3/circuits/abis/c_bind.test.cpp | 31 +++++++++++++++++++ circuits/cpp/src/aztec3/constants.hpp | 1 + 4 files changed, 52 insertions(+) diff --git a/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp b/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp index 284d39ee15c..afa1b824d5c 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp +++ b/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp @@ -162,6 +162,24 @@ WASM_EXPORT void abis__compute_function_selector(char const* func_sig_cstr, uint std::copy_n(hash_bytes, aztec3::FUNCTION_SELECTOR_NUM_BYTES, output); } +/** + * @brief Hash/compress verification key data. + * This is a WASM-export that can be called from Typescript. + * + * @details Pedersen compress VK to use later when computing function leaf + * or constructor hash. Return the serialized results in the `output` buffer. + * + * @param vk_data_buf buffer of bytes representing serialized verification_key_data + * @param output buffer that will contain the output. The serialized vk_hash. + */ +WASM_EXPORT void abis__hash_vk(uint8_t const* vk_data_buf, uint8_t* output) +{ + NT::VKData vk_data; + read(vk_data_buf, vk_data); + + NT::fr::serialize_to_buffer(vk_data.compress_native(aztec3::GeneratorIndex::VK), output); +} + /** * @brief Generates a function tree leaf from its preimage. * This is a WASM-export that can be called from Typescript. diff --git a/circuits/cpp/src/aztec3/circuits/abis/c_bind.h b/circuits/cpp/src/aztec3/circuits/abis/c_bind.h index dec7efbade0..b8827f33a35 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/c_bind.h +++ b/circuits/cpp/src/aztec3/circuits/abis/c_bind.h @@ -15,6 +15,8 @@ WASM_EXPORT void abis__compute_function_tree_root(uint8_t const* function_leaves uint8_t num_leaves, uint8_t* output); +WASM_EXPORT void abis__hash_vk(uint8_t const* vk_data_buf, uint8_t* output); + WASM_EXPORT void abis__hash_constructor(uint8_t const* func_sig_hash_buf, uint8_t const* args_hash_buf, uint8_t const* constructor_vk_hash_buf, diff --git a/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp b/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp index 3b7bd182580..2be2cff1908 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp @@ -103,6 +103,37 @@ TEST(abi_tests, compute_function_selector_transferFrom) EXPECT_EQ(bytes_to_hex_str(output), full_selector.substr(0, FUNCTION_SELECTOR_NUM_BYTES * 2)); } +TEST(abi_tests, hash_vk) +{ + // Initialize some random VK data + NT::VKData vk_data; + vk_data.composer_type = engine.get_random_uint32(); + vk_data.circuit_size = engine.get_random_uint32(); + vk_data.num_public_inputs = engine.get_random_uint32(); + vk_data.commitments["test1"] = g1::element::random_element(); + vk_data.commitments["test2"] = g1::element::random_element(); + vk_data.commitments["foo1"] = g1::element::random_element(); + vk_data.commitments["foo2"] = g1::element::random_element(); + // Write the vk data to a bytes vector + std::vector vk_data_vec; + write(vk_data_vec, vk_data); + + // create an output buffer for cbind hash results + std::array output = { 0 }; + + // Make the c_bind call to hash the vk + abis__hash_vk(vk_data_vec.data(), output.data()); + + // Convert buffer to `fr` for comparison to in-test calculated hash + NT::fr got_hash = NT::fr::serialize_from_buffer(output.data()); + + // Calculate the expected hash in-test + NT::fr expected_hash = vk_data.compress_native(aztec3::GeneratorIndex::VK); + + // Confirm cbind output == expected hash + EXPECT_EQ(got_hash, expected_hash); +} + TEST(abi_tests, compute_function_leaf) { // Construct FunctionLeafPreimage with some randomized fields diff --git a/circuits/cpp/src/aztec3/constants.hpp b/circuits/cpp/src/aztec3/constants.hpp index 92b22f488a1..5cf78a4f799 100644 --- a/circuits/cpp/src/aztec3/constants.hpp +++ b/circuits/cpp/src/aztec3/constants.hpp @@ -49,6 +49,7 @@ enum GeneratorIndex { OUTER_NULLIFIER, STATE_READ, STATE_TRANSITION, + VK, FUNCTION_DATA, FUNCTION_LEAF, CONTRACT_DEPLOYMENT_DATA, From cf783a85c1a678f3c042a779a8c23b19c20842e4 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Fri, 24 Mar 2023 20:24:43 -0300 Subject: [PATCH 091/166] Expose serialization utils (#89) --- circuits/ts/package.json | 3 ++- circuits/ts/src/structs/base_rollup.ts | 4 ++-- circuits/ts/src/structs/call_context.ts | 2 +- circuits/ts/src/structs/function_data.ts | 2 +- circuits/ts/src/structs/kernel.ts | 2 +- circuits/ts/src/structs/merge_rollup.ts | 2 +- .../structs/private_circuit_public_inputs.test.ts | 2 +- .../ts/src/structs/private_circuit_public_inputs.ts | 2 +- circuits/ts/src/structs/root_rollup.ts | 2 +- circuits/ts/src/structs/shared.ts | 6 +++--- circuits/ts/src/structs/tx.ts | 2 +- circuits/ts/src/structs/verification_key.ts | 2 +- circuits/ts/src/tests/expectSerialize.ts | 2 +- circuits/ts/src/tests/factories.ts | 2 +- circuits/ts/src/{wasm => utils}/buffer_reader.ts | 13 +++++++++++++ circuits/ts/src/utils/index.ts | 2 ++ circuits/ts/src/{wasm => utils}/serialize.ts | 0 circuits/ts/src/wasm/circuits_wasm.ts | 2 +- 18 files changed, 34 insertions(+), 18 deletions(-) rename circuits/ts/src/{wasm => utils}/buffer_reader.ts (84%) create mode 100644 circuits/ts/src/utils/index.ts rename circuits/ts/src/{wasm => utils}/serialize.ts (100%) diff --git a/circuits/ts/package.json b/circuits/ts/package.json index 8e1b10fbdac..5655c80bc48 100644 --- a/circuits/ts/package.json +++ b/circuits/ts/package.json @@ -4,7 +4,8 @@ "type": "module", "exports": { ".": "./dest/index.js", - "./factories": "./dest/tests/factories.js" + "./factories": "./dest/tests/factories.js", + "./utils": "./dest/utils/index.js" }, "typedoc": { "entryPoint": "./src/index.ts", diff --git a/circuits/ts/src/structs/base_rollup.ts b/circuits/ts/src/structs/base_rollup.ts index df9dd522e25..4d212059e17 100644 --- a/circuits/ts/src/structs/base_rollup.ts +++ b/circuits/ts/src/structs/base_rollup.ts @@ -1,6 +1,6 @@ -import { BufferReader } from "../wasm/buffer_reader.js"; +import { BufferReader } from "../utils/buffer_reader.js"; import { assertLength, FieldsOf } from "../utils/jsUtils.js"; -import { serializeToBuffer } from "../wasm/serialize.js"; +import { serializeToBuffer } from "../utils/serialize.js"; import { CONTRACT_TREE_ROOTS_TREE_HEIGHT, KERNEL_NEW_NULLIFIERS_LENGTH, diff --git a/circuits/ts/src/structs/call_context.ts b/circuits/ts/src/structs/call_context.ts index 14bdb89400f..fd76623009f 100644 --- a/circuits/ts/src/structs/call_context.ts +++ b/circuits/ts/src/structs/call_context.ts @@ -1,4 +1,4 @@ -import { serializeToBuffer } from "../wasm/serialize.js"; +import { serializeToBuffer } from "../utils/serialize.js"; import { AztecAddress, EthAddress } from "./shared.js"; /** diff --git a/circuits/ts/src/structs/function_data.ts b/circuits/ts/src/structs/function_data.ts index 7db5d1c8da5..90702799061 100644 --- a/circuits/ts/src/structs/function_data.ts +++ b/circuits/ts/src/structs/function_data.ts @@ -1,4 +1,4 @@ -import { serializeToBuffer } from "../wasm/serialize.js"; +import { serializeToBuffer } from "../utils/serialize.js"; /** * Function description for circuit. diff --git a/circuits/ts/src/structs/kernel.ts b/circuits/ts/src/structs/kernel.ts index 1529ba75ba5..1b4cd799b22 100644 --- a/circuits/ts/src/structs/kernel.ts +++ b/circuits/ts/src/structs/kernel.ts @@ -1,5 +1,5 @@ import { assertLength, checkLength } from "../utils/jsUtils.js"; -import { serializeToBuffer } from "../wasm/serialize.js"; +import { serializeToBuffer } from "../utils/serialize.js"; import { KERNEL_L1_MSG_STACK_LENGTH, KERNEL_NEW_COMMITMENTS_LENGTH, diff --git a/circuits/ts/src/structs/merge_rollup.ts b/circuits/ts/src/structs/merge_rollup.ts index bdb7dcfd855..f344a26b59d 100644 --- a/circuits/ts/src/structs/merge_rollup.ts +++ b/circuits/ts/src/structs/merge_rollup.ts @@ -1,5 +1,5 @@ import { assertLength, FieldsOf } from "../utils/jsUtils.js"; -import { serializeToBuffer } from "../wasm/serialize.js"; +import { serializeToBuffer } from "../utils/serialize.js"; import { AppendOnlyTreeSnapshot, BaseRollupPublicInputs, diff --git a/circuits/ts/src/structs/private_circuit_public_inputs.test.ts b/circuits/ts/src/structs/private_circuit_public_inputs.test.ts index c69d2e3b51f..4e14e395a95 100644 --- a/circuits/ts/src/structs/private_circuit_public_inputs.test.ts +++ b/circuits/ts/src/structs/private_circuit_public_inputs.test.ts @@ -1,7 +1,7 @@ import { expectSerializeToMatchSnapshot } from "../tests/expectSerialize.js"; import { fr } from "../tests/factories.js"; import { range } from "../utils/jsUtils.js"; -import { numToUInt32BE } from "../wasm/serialize.js"; +import { numToUInt32BE } from "../utils/serialize.js"; import { CallContext } from "./call_context.js"; import { ARGS_LENGTH, diff --git a/circuits/ts/src/structs/private_circuit_public_inputs.ts b/circuits/ts/src/structs/private_circuit_public_inputs.ts index b1e73898397..863780ce080 100644 --- a/circuits/ts/src/structs/private_circuit_public_inputs.ts +++ b/circuits/ts/src/structs/private_circuit_public_inputs.ts @@ -1,5 +1,5 @@ import { assertLength, FieldsOf } from "../utils/jsUtils.js"; -import { serializeToBuffer } from "../wasm/serialize.js"; +import { serializeToBuffer } from "../utils/serialize.js"; import { CallContext } from "./call_context.js"; import { ARGS_LENGTH, diff --git a/circuits/ts/src/structs/root_rollup.ts b/circuits/ts/src/structs/root_rollup.ts index 9308e8eae5b..c2f921f95eb 100644 --- a/circuits/ts/src/structs/root_rollup.ts +++ b/circuits/ts/src/structs/root_rollup.ts @@ -1,5 +1,5 @@ import { assertLength, FieldsOf } from "../utils/jsUtils.js"; -import { serializeToBuffer } from "../wasm/serialize.js"; +import { serializeToBuffer } from "../utils/serialize.js"; import { AppendOnlyTreeSnapshot } from "./base_rollup.js"; import { CONTRACT_TREE_HEIGHT, diff --git a/circuits/ts/src/structs/shared.ts b/circuits/ts/src/structs/shared.ts index cc6feda0446..753248be068 100644 --- a/circuits/ts/src/structs/shared.ts +++ b/circuits/ts/src/structs/shared.ts @@ -1,10 +1,10 @@ -import { BufferReader } from "../wasm/buffer_reader.js"; +import { BufferReader } from "../utils/buffer_reader.js"; import { checkLength, range } from "../utils/jsUtils.js"; import { Bufferable, numToUInt32BE, serializeToBuffer, -} from "../wasm/serialize.js"; +} from "../utils/serialize.js"; abstract class Field { public static SIZE_IN_BYTES = 32; @@ -95,7 +95,7 @@ function pad32(buffer: Buffer) { export class EthAddress { static SIZE_IN_BYTES = 20; - constructor(private buffer: Buffer) { + constructor(public readonly buffer: Buffer) { if (buffer.length != EthAddress.SIZE_IN_BYTES) { throw new Error( `Unexpected buffer size ${buffer.length} (expected ${EthAddress.SIZE_IN_BYTES} bytes)` diff --git a/circuits/ts/src/structs/tx.ts b/circuits/ts/src/structs/tx.ts index 40f3b67a07f..23a7e4a51f7 100644 --- a/circuits/ts/src/structs/tx.ts +++ b/circuits/ts/src/structs/tx.ts @@ -1,4 +1,4 @@ -import { serializeToBuffer } from "../wasm/serialize.js"; +import { serializeToBuffer } from "../utils/serialize.js"; import { EthAddress, Fr } from "./shared.js"; /** diff --git a/circuits/ts/src/structs/verification_key.ts b/circuits/ts/src/structs/verification_key.ts index 7ae8b42b0f5..953b72937cb 100644 --- a/circuits/ts/src/structs/verification_key.ts +++ b/circuits/ts/src/structs/verification_key.ts @@ -1,4 +1,4 @@ -import { serializeToBuffer } from "../wasm/serialize.js"; +import { serializeToBuffer } from "../utils/serialize.js"; import { ComposerType, Fr } from "./shared.js"; /** diff --git a/circuits/ts/src/tests/expectSerialize.ts b/circuits/ts/src/tests/expectSerialize.ts index 6f370bb26ad..6b646bd5830 100644 --- a/circuits/ts/src/tests/expectSerialize.ts +++ b/circuits/ts/src/tests/expectSerialize.ts @@ -1,5 +1,5 @@ import { CircuitsWasm } from "../wasm/circuits_wasm.js"; -import { uint8ArrayToNum } from "../wasm/serialize.js"; +import { uint8ArrayToNum } from "../utils/serialize.js"; /** * Simplify e.g. 0x0003 into 0x3. diff --git a/circuits/ts/src/tests/factories.ts b/circuits/ts/src/tests/factories.ts index fe1aa47b40d..70be9f4978b 100644 --- a/circuits/ts/src/tests/factories.ts +++ b/circuits/ts/src/tests/factories.ts @@ -42,7 +42,7 @@ import { VerificationKey, } from "../structs/verification_key.js"; import { range } from "../utils/jsUtils.js"; -import { numToUInt32BE } from "../wasm/serialize.js"; +import { numToUInt32BE } from "../utils/serialize.js"; export function makeTxContext(seed: number): TxContext { const deploymentData = new ContractDeploymentData( diff --git a/circuits/ts/src/wasm/buffer_reader.ts b/circuits/ts/src/utils/buffer_reader.ts similarity index 84% rename from circuits/ts/src/wasm/buffer_reader.ts rename to circuits/ts/src/utils/buffer_reader.ts index 87742da3291..2c39e757bbb 100644 --- a/circuits/ts/src/wasm/buffer_reader.ts +++ b/circuits/ts/src/utils/buffer_reader.ts @@ -52,6 +52,19 @@ export class BufferReader { return result; } + public readArray( + size: number, + itemDeserializer: { + fromBuffer: (reader: BufferReader) => T; + } + ): T[] { + const result = new Array(size); + for (let i = 0; i < size; i++) { + result[i] = itemDeserializer.fromBuffer(this); + } + return result; + } + public readObject(deserializer: { fromBuffer: (reader: BufferReader) => T; }): T { diff --git a/circuits/ts/src/utils/index.ts b/circuits/ts/src/utils/index.ts new file mode 100644 index 00000000000..2d11454111d --- /dev/null +++ b/circuits/ts/src/utils/index.ts @@ -0,0 +1,2 @@ +export * from "./buffer_reader.js"; +export * from "./serialize.js"; diff --git a/circuits/ts/src/wasm/serialize.ts b/circuits/ts/src/utils/serialize.ts similarity index 100% rename from circuits/ts/src/wasm/serialize.ts rename to circuits/ts/src/utils/serialize.ts diff --git a/circuits/ts/src/wasm/circuits_wasm.ts b/circuits/ts/src/wasm/circuits_wasm.ts index b3b5c49b43e..bdeb2bc0fac 100644 --- a/circuits/ts/src/wasm/circuits_wasm.ts +++ b/circuits/ts/src/wasm/circuits_wasm.ts @@ -11,7 +11,7 @@ import { readFile } from "fs/promises"; import { fetch } from "cross-fetch"; import { dirname } from "path"; import { fileURLToPath } from "url"; -import { numToUInt32LE } from "./serialize.js"; +import { numToUInt32LE } from "../utils/serialize.js"; /** * Get the WASM binary for barretenberg. From 07d29621be2ad5c806b3c81f712d939f34bc41ba Mon Sep 17 00:00:00 2001 From: ludamad Date: Sun, 26 Mar 2023 08:18:02 -0400 Subject: [PATCH 092/166] feat: refactor .yalc usage (#92) * Expose serialization utils * fix: yarn version alignment * fix: rework as workspace package * fix: rework as workspace package * fix: .gitignore * fix: remove .yalc refs from package.json * Revert bb --------- Co-authored-by: Santiago Palladino Co-authored-by: Adam Domurad --- circuits/.gitignore | 6 +- .../@aztec/foundation/.circleci/config.yml | 73 + .../.yalc/@aztec/foundation/.dockerignore | 4 + .../.yalc/@aztec/foundation/.editorconfig | 10 + .../.yalc/@aztec/foundation/.eslintrc.cjs | 44 + .../.yalc/@aztec/foundation/.gitattributes | 1 + .../.github/pull_request_template.md | 12 + circuits/.yalc/@aztec/foundation/.gitmodules | 3 + circuits/.yalc/@aztec/foundation/.nvmrc | 1 + .../.yalc/@aztec/foundation/.prettierignore | 5 + .../.yalc/@aztec/foundation/.prettierrc.json | 6 + circuits/.yalc/@aztec/foundation/.tsbuildinfo | 1 + .../@aztec/foundation/.vscode/extensions.json | 8 + .../@aztec/foundation/.vscode/launch.json | 18 + .../@aztec/foundation/.vscode/settings.json | 11 + .../@aztec/foundation}/Dockerfile | 10 +- circuits/.yalc/@aztec/foundation/LICENSE | 201 + circuits/.yalc/@aztec/foundation/PROJECT | 1 + circuits/.yalc/@aztec/foundation/README.md | 17 + circuits/.yalc/@aztec/foundation/VERSION | 1 + circuits/.yalc/@aztec/foundation/bootstrap.sh | 38 + .../@aztec/foundation/build_manifest.json | 7 + .../foundation/dest/async-map/index.d.ts | 2 + .../foundation/dest/async-map/index.d.ts.map | 1 + .../@aztec/foundation/dest/async-map/index.js | 8 + .../foundation/dest/bigint-buffer/index.d.ts | 28 + .../dest/bigint-buffer/index.d.ts.map | 1 + .../foundation/dest/bigint-buffer/index.js | 49 + .../@aztec/foundation/dest/crypto/index.d.ts | 2 + .../foundation/dest/crypto}/index.d.ts.map | 2 +- .../@aztec/foundation/dest/crypto/index.js | 2 + .../foundation/dest/crypto/random/index.d.ts | 3 + .../dest/crypto/random/index.d.ts.map | 1 + .../foundation/dest/crypto/random/index.js | 36 + .../@aztec/foundation/dest/errors/index.d.ts | 3 + .../foundation/dest/errors/index.d.ts.map | 1 + .../@aztec/foundation/dest/errors/index.js | 3 + .../dest/fifo/bounded_serial_queue.d.ts | 24 + .../dest/fifo/bounded_serial_queue.d.ts.map | 1 + .../dest/fifo/bounded_serial_queue.js | 62 + .../@aztec/foundation/dest/fifo/index.d.ts | 5 + .../foundation/dest/fifo/index.d.ts.map | 1 + .../@aztec/foundation/dest/fifo/index.js | 5 + .../foundation/dest/fifo}/memory_fifo.d.ts | 8 - .../foundation/dest/fifo/memory_fifo.d.ts.map | 1 + .../foundation/dest/fifo}/memory_fifo.js | 11 +- .../foundation/dest/fifo/semaphore.d.ts | 10 + .../foundation/dest/fifo/semaphore.d.ts.map | 1 + .../@aztec/foundation/dest/fifo/semaphore.js | 17 + .../foundation/dest/fifo/serial_queue.d.ts | 18 + .../dest/fifo/serial_queue.d.ts.map | 1 + .../foundation/dest/fifo/serial_queue.js | 45 + .../.yalc/@aztec/foundation/dest/index.d.ts | 15 + .../@aztec/foundation/dest/index.d.ts.map | 1 + .../.yalc/@aztec/foundation/dest/index.js | 15 + .../foundation/dest/iso-fetch}/index.d.ts | 2 +- .../foundation/dest/iso-fetch/index.d.ts.map | 1 + .../@aztec/foundation/dest/iso-fetch/index.js | 3 + .../@aztec/foundation/dest/log/console.d.ts | 3 + .../foundation/dest/log/console.d.ts.map | 1 + .../@aztec/foundation/dest/log/console.js | 17 + .../@aztec/foundation/dest/log/debug.d.ts | 6 + .../@aztec/foundation/dest/log/debug.d.ts.map | 1 + .../.yalc/@aztec/foundation/dest/log/debug.js | 32 + .../@aztec/foundation/dest/log/index.d.ts | 4 + .../@aztec/foundation/dest/log/index.d.ts.map | 1 + .../.yalc/@aztec/foundation/dest/log/index.js | 4 + .../foundation/dest/log/log_history.d.ts | 8 + .../foundation/dest/log/log_history.d.ts.map | 1 + .../@aztec/foundation/dest/log/log_history.js | 19 + .../@aztec/foundation/dest/mutex/index.d.ts | 16 + .../foundation/dest/mutex/index.d.ts.map | 1 + .../@aztec/foundation/dest/mutex/index.js | 37 + .../foundation/dest/mutex/mutex_database.d.ts | 6 + .../dest/mutex/mutex_database.d.ts.map | 1 + .../foundation/dest/mutex/mutex_database.js | 2 + .../@aztec/foundation/dest/retry/index.d.ts | 4 + .../foundation/dest/retry/index.d.ts.map | 1 + .../@aztec/foundation/dest/retry/index.js | 42 + .../dest/running-promise/index.d.ts | 17 + .../dest/running-promise/index.d.ts.map | 1 + .../foundation/dest/running-promise/index.js | 41 + .../dest/serialize/deserializer.d.ts | 22 + .../dest/serialize/deserializer.d.ts.map | 1 + .../foundation/dest/serialize/deserializer.js | 45 + .../foundation/dest/serialize/free_funcs.d.ts | 42 + .../dest/serialize/free_funcs.d.ts.map | 1 + .../foundation/dest/serialize/free_funcs.js | 87 + .../foundation/dest/serialize/index.d.ts | 4 + .../foundation/dest/serialize/index.d.ts.map | 1 + .../@aztec/foundation/dest/serialize/index.js | 4 + .../foundation/dest/serialize/serializer.d.ts | 25 + .../dest/serialize/serializer.d.ts.map | 1 + .../foundation/dest/serialize/serializer.js | 48 + .../@aztec/foundation/dest/sleep/index.d.ts | 9 + .../foundation/dest/sleep/index.d.ts.map | 1 + .../@aztec/foundation/dest/sleep/index.js | 27 + .../@aztec/foundation/dest/timer/index.d.ts | 3 + .../foundation/dest/timer/index.d.ts.map | 1 + .../@aztec/foundation/dest/timer/index.js | 3 + .../@aztec/foundation/dest/timer/timeout.d.ts | 13 + .../foundation/dest/timer/timeout.d.ts.map | 1 + .../@aztec/foundation/dest/timer/timeout.js | 34 + .../@aztec/foundation/dest/timer/timer.d.ts | 7 + .../foundation/dest/timer/timer.d.ts.map | 1 + .../@aztec/foundation/dest/timer/timer.js | 12 + .../dest/transport/browser/index.d.ts | 0 .../dest/transport/browser/index.d.ts.map | 0 .../dest/transport/browser/index.js | 0 .../browser/message_port_socket.d.ts | 16 - .../browser/message_port_socket.d.ts.map | 1 + .../transport/browser/message_port_socket.js | 21 + .../browser/shared_worker_connector.d.ts | 11 - .../browser/shared_worker_connector.d.ts.map | 2 +- .../browser/shared_worker_connector.js | 13 +- .../browser/shared_worker_listener.d.ts | 25 +- .../browser/shared_worker_listener.d.ts.map | 1 + .../browser/shared_worker_listener.js | 22 + .../transport/browser/worker_connector.d.ts | 10 - .../browser/worker_connector.d.ts.map | 2 +- .../transport/browser/worker_connector.js | 12 +- .../transport/browser/worker_listener.d.ts | 25 +- .../browser/worker_listener.d.ts.map | 1 + .../dest/transport/browser/worker_listener.js | 22 + .../dispatch/create_dispatch_fn.d.ts | 12 - .../dispatch/create_dispatch_fn.d.ts.map | 1 + .../transport/dispatch/create_dispatch_fn.js | 8 + .../dispatch/create_dispatch_proxy.d.ts | 19 +- .../dispatch/create_dispatch_proxy.d.ts.map | 1 + .../dispatch/create_dispatch_proxy.js | 8 +- .../dest/transport/dispatch/messages.d.ts | 14 + .../dest/transport/dispatch/messages.d.ts.map | 1 + .../dest/transport/dispatch/messages.js | 6 +- .../foundation}/dest/transport/index.d.ts | 0 .../foundation}/dest/transport/index.d.ts.map | 0 .../foundation}/dest/transport/index.js | 0 .../dest/transport/interface/connector.d.ts | 0 .../transport/interface/connector.d.ts.map | 0 .../dest/transport/interface/connector.js | 0 .../dest/transport/interface/listener.d.ts | 0 .../transport/interface/listener.d.ts.map | 0 .../dest/transport/interface/listener.js | 0 .../dest/transport/interface/socket.d.ts | 0 .../dest/transport/interface/socket.d.ts.map | 0 .../dest/transport/interface/socket.js | 0 .../transport/interface/transferable.d.ts | 24 +- .../transport/interface/transferable.d.ts.map | 1 + .../dest/transport/interface/transferable.js | 23 + .../dest/transport/node/index.d.ts | 0 .../dest/transport/node/index.d.ts.map | 0 .../foundation}/dest/transport/node/index.js | 0 .../dest/transport/node/node_connector.d.ts | 7 - .../transport/node/node_connector.d.ts.map | 2 +- .../dest/transport/node/node_connector.js | 9 +- .../transport/node/node_connector_socket.d.ts | 16 - .../node/node_connector_socket.d.ts.map | 1 + .../transport/node/node_connector_socket.js | 17 + .../dest/transport/node/node_listener.d.ts | 9 - .../transport/node/node_listener.d.ts.map | 2 +- .../dest/transport/node/node_listener.js | 11 +- .../transport/node/node_listener_socket.d.ts | 13 - .../node/node_listener_socket.d.ts.map | 2 +- .../transport/node/node_listener_socket.js | 21 + .../dest/transport/transport_client.d.ts | 19 - .../dest/transport/transport_client.d.ts.map | 1 + .../dest/transport/transport_client.js | 63 + .../dest/transport/transport_server.d.ts | 19 - .../dest/transport/transport_server.d.ts.map | 2 +- .../dest/transport/transport_server.js | 21 +- circuits/.yalc/@aztec/foundation/package.json | 39 + .../src/async-map/async_map.test.ts | 9 + .../@aztec/foundation/src/async-map/index.ts | 7 + .../foundation/src/bigint-buffer/index.ts | 51 + .../@aztec/foundation/src/crypto/index.ts | 1 + .../src/crypto/random/index.test.ts | 13 + .../foundation/src/crypto/random/index.ts | 38 + .../@aztec/foundation/src/errors/index.ts | 1 + .../foundation/src}/eslint-config/index.js | 15 +- .../src}/eslint-config/package.json | 11 +- .../src/fifo/bounded_serial_queue.ts | 69 + .../.yalc/@aztec/foundation/src/fifo/index.ts | 4 + .../foundation/src/fifo}/memory_fifo.ts | 9 - .../@aztec/foundation/src/fifo/semaphore.ts | 20 + .../foundation/src/fifo/serial_queue.ts | 49 + circuits/.yalc/@aztec/foundation/src/index.ts | 14 + .../@aztec/foundation/src/iso-fetch/index.ts | 2 + .../@aztec/foundation/src/log/console.ts | 17 + .../.yalc/@aztec/foundation/src/log/debug.ts | 38 + .../.yalc/@aztec/foundation/src/log/index.ts | 3 + .../foundation/src/log/log_history.test.ts | 87 + .../@aztec/foundation/src/log/log_history.ts | 21 + .../@aztec/foundation/src/mutex/index.ts | 46 + .../@aztec/foundation/src/mutex/mutex.test.ts | 64 + .../foundation/src/mutex/mutex_database.ts | 5 + .../foundation/src/prettier-config/index.js | 6 + .../src/prettier-config/package.json | 8 + .../@aztec/foundation/src/retry/index.ts | 45 + .../foundation/src/running-promise/index.ts | 42 + .../foundation/src/serialize/deserializer.ts | 62 + .../foundation/src/serialize/free_funcs.ts | 106 + .../@aztec/foundation/src/serialize/index.ts | 3 + .../src/serialize/serialize.test.ts | 88 + .../foundation/src/serialize/serializer.ts | 66 + .../@aztec/foundation/src/sleep/index.ts | 28 + .../@aztec/foundation/src/timer/index.ts | 2 + .../@aztec/foundation/src/timer/timeout.ts | 36 + .../@aztec/foundation/src/timer/timer.ts | 15 + .../src/transport/browser/index.ts | 0 .../transport/browser/message_port_socket.ts | 16 - .../browser/shared_worker_connector.ts | 11 - .../browser/shared_worker_listener.ts | 25 +- .../src/transport/browser/worker_connector.ts | 10 - .../src/transport/browser/worker_listener.ts | 25 +- .../transport/dispatch/create_dispatch_fn.ts | 12 - .../dispatch/create_dispatch_proxy.ts | 19 +- .../src/transport/dispatch/messages.ts | 31 - .../@aztec/foundation}/src/transport/index.ts | 0 .../src/transport/interface/connector.ts | 0 .../src/transport/interface/listener.ts | 0 .../src/transport/interface/socket.ts | 0 .../src/transport/interface/transferable.ts | 33 +- .../foundation}/src/transport/node/index.ts | 0 .../src/transport/node/node_connector.ts | 7 - .../transport/node/node_connector_socket.ts | 16 - .../src/transport/node/node_listener.ts | 9 - .../transport/node/node_listener_socket.ts | 13 - .../src/transport/transport_client.ts | 27 +- .../src/transport/transport_server.ts | 19 - .../@aztec/foundation}/tsconfig.dest.json | 0 .../.yalc/@aztec/foundation/tsconfig.json | 22 + circuits/.yalc/@aztec/foundation/yalc.sig | 1 + .../log => .yalc/@aztec/wasm}/.eslintrc.cjs | 0 .../{ts => }/.yalc/@aztec/wasm/.tsbuildinfo | 0 .../{ts => }/.yalc/@aztec/wasm/Dockerfile | 0 circuits/{ts => }/.yalc/@aztec/wasm/README.md | 0 .../.yalc/@aztec/wasm/dest/index.d.ts | 0 .../.yalc/@aztec/wasm/dest/index.d.ts.map | 0 .../{ts => }/.yalc/@aztec/wasm/dest/index.js | 0 .../@aztec/wasm}/dest/memory_fifo.d.ts | 0 .../@aztec/wasm}/dest/memory_fifo.d.ts.map | 0 .../@aztec/wasm}/dest/memory_fifo.js | 0 .../wasm/dest/transport/browser/index.d.ts | 0 .../dest/transport/browser/index.d.ts.map | 0 .../wasm/dest/transport/browser/index.js | 0 .../browser/message_port_socket.d.ts | 0 .../browser/message_port_socket.d.ts.map | 0 .../transport/browser/message_port_socket.js | 0 .../browser/shared_worker_connector.d.ts | 0 .../browser/shared_worker_connector.d.ts.map | 0 .../browser/shared_worker_connector.js | 0 .../browser/shared_worker_listener.d.ts | 0 .../browser/shared_worker_listener.d.ts.map | 0 .../browser/shared_worker_listener.js | 0 .../transport/browser/worker_connector.d.ts | 0 .../browser/worker_connector.d.ts.map | 0 .../transport/browser/worker_connector.js | 0 .../transport/browser/worker_listener.d.ts | 0 .../browser/worker_listener.d.ts.map | 0 .../dest/transport/browser/worker_listener.js | 0 .../dispatch/create_dispatch_fn.d.ts | 0 .../dispatch/create_dispatch_fn.d.ts.map | 0 .../transport/dispatch/create_dispatch_fn.js | 0 .../dispatch/create_dispatch_proxy.d.ts | 0 .../dispatch/create_dispatch_proxy.d.ts.map | 0 .../dispatch/create_dispatch_proxy.js | 0 .../dest/transport/dispatch/messages.d.ts | 0 .../dest/transport/dispatch/messages.d.ts.map | 0 .../wasm}/dest/transport/dispatch/messages.js | 0 .../@aztec/wasm/dest/transport/index.d.ts | 0 .../@aztec/wasm/dest/transport/index.d.ts.map | 0 .../.yalc/@aztec/wasm/dest/transport/index.js | 0 .../dest/transport/interface/connector.d.ts | 0 .../transport/interface/connector.d.ts.map | 0 .../dest/transport/interface/connector.js | 0 .../dest/transport/interface/listener.d.ts | 0 .../transport/interface/listener.d.ts.map | 0 .../wasm/dest/transport/interface/listener.js | 0 .../wasm/dest/transport/interface/socket.d.ts | 0 .../dest/transport/interface/socket.d.ts.map | 0 .../wasm/dest/transport/interface/socket.js | 0 .../transport/interface/transferable.d.ts | 0 .../transport/interface/transferable.d.ts.map | 0 .../dest/transport/interface/transferable.js | 0 .../wasm/dest/transport/node/index.d.ts | 0 .../wasm/dest/transport/node/index.d.ts.map | 0 .../@aztec/wasm/dest/transport/node/index.js | 0 .../dest/transport/node/node_connector.d.ts | 0 .../transport/node/node_connector.d.ts.map | 0 .../dest/transport/node/node_connector.js | 0 .../transport/node/node_connector_socket.d.ts | 0 .../node/node_connector_socket.d.ts.map | 0 .../transport/node/node_connector_socket.js | 0 .../dest/transport/node/node_listener.d.ts | 0 .../transport/node/node_listener.d.ts.map | 0 .../dest/transport/node/node_listener.js | 0 .../transport/node/node_listener_socket.d.ts | 0 .../node/node_listener_socket.d.ts.map | 0 .../transport/node/node_listener_socket.js | 0 .../dest/transport/transport_client.d.ts | 0 .../dest/transport/transport_client.d.ts.map | 0 .../wasm}/dest/transport/transport_client.js | 133 +- .../dest/transport/transport_server.d.ts | 0 .../dest/transport/transport_server.d.ts.map | 0 .../wasm}/dest/transport/transport_server.js | 0 .../wasm/dest/wasm/async_call_state.d.ts | 74 + .../wasm}/dest/wasm/async_call_state.d.ts.map | 0 .../wasm}/dest/wasm/async_call_state.js | 0 .../@aztec/wasm/dest/wasm/empty_wasi_sdk.d.ts | 26 + .../wasm}/dest/wasm/empty_wasi_sdk.d.ts.map | 0 .../@aztec/wasm/dest/wasm/empty_wasi_sdk.js | 106 +- .../@aztec/wasm}/dest/wasm/index.d.ts | 0 .../@aztec/wasm}/dest/wasm/index.d.ts.map | 0 .../@aztec/wasm}/dest/wasm/index.js | 0 .../@aztec/wasm/dest/wasm/wasm_module.d.ts | 110 + .../wasm/dest/wasm/wasm_module.d.ts.map | 0 .../@aztec/wasm/dest/wasm/wasm_module.js | 206 + .../wasm}/dest/worker/browser/index.d.ts | 0 .../wasm}/dest/worker/browser/index.d.ts.map | 0 .../@aztec/wasm}/dest/worker/browser/index.js | 0 .../dest/worker/browser/start_web_module.d.ts | 0 .../worker/browser/start_web_module.d.ts.map | 0 .../dest/worker/browser/start_web_module.js | 0 .../dest/worker/browser/web_data_store.d.ts | 0 .../worker/browser/web_data_store.d.ts.map | 0 .../dest/worker/browser/web_data_store.js | 0 .../wasm/dest/worker/browser/web_worker.d.ts | 0 .../dest/worker/browser/web_worker.d.ts.map | 0 .../wasm/dest/worker/browser/web_worker.js | 0 .../@aztec/wasm}/dest/worker/data_store.d.ts | 0 .../wasm}/dest/worker/data_store.d.ts.map | 0 .../@aztec/wasm}/dest/worker/data_store.js | 0 .../.yalc/@aztec/wasm/dest/worker/index.d.ts | 0 .../@aztec/wasm/dest/worker/index.d.ts.map | 0 .../.yalc/@aztec/wasm/dest/worker/index.js | 0 .../@aztec/wasm}/dest/worker/node/index.d.ts | 0 .../wasm}/dest/worker/node/index.d.ts.map | 0 .../@aztec/wasm}/dest/worker/node/index.js | 0 .../dest/worker/node/node_data_store.d.ts | 0 .../dest/worker/node/node_data_store.d.ts.map | 0 .../wasm}/dest/worker/node/node_data_store.js | 0 .../wasm}/dest/worker/node/node_worker.d.ts | 0 .../dest/worker/node/node_worker.d.ts.map | 0 .../wasm}/dest/worker/node/node_worker.js | 0 .../dest/worker/node/start_node_module.d.ts | 0 .../worker/node/start_node_module.d.ts.map | 0 .../dest/worker/node/start_node_module.js | 0 .../@aztec/wasm}/dest/worker/wasm_worker.d.ts | 0 .../wasm}/dest/worker/wasm_worker.d.ts.map | 0 .../@aztec/wasm}/dest/worker/wasm_worker.js | 0 .../@aztec/wasm}/dest/worker/worker_pool.d.ts | 0 .../wasm}/dest/worker/worker_pool.d.ts.map | 0 .../@aztec/wasm/dest/worker/worker_pool.js | 84 +- .../{ts => }/.yalc/@aztec/wasm/package.json | 2 +- .../{ts => }/.yalc/@aztec/wasm/src/index.ts | 0 .../@aztec/wasm}/src/memory_fifo.ts | 0 .../@aztec/wasm}/src/test/gcd.wasm | Bin .../@aztec/wasm}/src/test/gcd.wat | 0 .../wasm/src/transport/browser/index.ts | 0 .../transport/browser/message_port_socket.ts | 0 .../browser/shared_worker_connector.ts | 0 .../browser/shared_worker_listener.ts | 0 .../src/transport/browser/worker_connector.ts | 0 .../src/transport/browser/worker_listener.ts | 0 .../transport/dispatch/create_dispatch_fn.ts | 0 .../dispatch/create_dispatch_proxy.ts | 0 .../wasm}/src/transport/dispatch/messages.ts | 0 .../.yalc/@aztec/wasm/src/transport/index.ts | 0 .../wasm/src/transport/interface/connector.ts | 0 .../wasm/src/transport/interface/listener.ts | 0 .../wasm/src/transport/interface/socket.ts | 0 .../src/transport/interface/transferable.ts | 0 .../@aztec/wasm/src/transport/node/index.ts | 0 .../src/transport/node/node_connector.ts | 0 .../transport/node/node_connector_socket.ts | 0 .../wasm}/src/transport/node/node_listener.ts | 0 .../transport/node/node_listener_socket.ts | 0 .../wasm}/src/transport/transport_client.ts | 34 +- .../wasm}/src/transport/transport_server.ts | 0 .../@aztec/wasm}/src/wasm/async_call_state.ts | 0 .../@aztec/wasm/src/wasm/empty_wasi_sdk.ts | 36 +- .../@aztec/wasm}/src/wasm/index.ts | 0 .../@aztec/wasm/src/wasm/wasm_module.test.ts | 0 .../.yalc/@aztec/wasm/src/wasm/wasm_module.ts | 29 +- .../@aztec/wasm}/src/worker/browser/index.ts | 0 .../src/worker/browser/start_web_module.ts | 0 .../src/worker/browser/web_data_store.ts | 0 .../wasm/src/worker/browser/web_worker.ts | 0 .../@aztec/wasm}/src/worker/data_store.ts | 0 .../.yalc/@aztec/wasm/src/worker/index.ts | 0 .../@aztec/wasm}/src/worker/node/index.ts | 0 .../wasm}/src/worker/node/node_data_store.ts | 0 .../wasm}/src/worker/node/node_worker.ts | 0 .../src/worker/node/start_node_module.ts | 0 .../@aztec/wasm}/src/worker/wasm_worker.ts | 0 .../@aztec/wasm/src/worker/worker_pool.ts | 28 +- .../@aztec/wasm}/tsconfig.dest.json | 0 .../log => .yalc/@aztec/wasm}/tsconfig.json | 0 circuits/{ts => }/.yalc/@aztec/wasm/yalc.sig | 0 circuits/.yarn/install-state.gz | Bin 0 -> 509645 bytes .../@yarnpkg/plugin-workspace-tools.cjs | 28 + circuits/.yarn/releases/yarn-3.4.1.cjs | 873 +++ circuits/.yarnrc.yml | 7 + circuits/package.json | 27 + circuits/ts/.eslintrc.cjs | 7 +- circuits/ts/.gitignore | 2 - .../ts/.yalc/@aztec/eslint-config/yalc.sig | 1 - circuits/ts/.yalc/@aztec/log/.tsbuildinfo | 1 - circuits/ts/.yalc/@aztec/log/Dockerfile | 16 - circuits/ts/.yalc/@aztec/log/README.md | 1 - circuits/ts/.yalc/@aztec/log/dest/index.d.ts | 11 - .../ts/.yalc/@aztec/log/dest/index.d.ts.map | 1 - circuits/ts/.yalc/@aztec/log/dest/index.js | 9 - circuits/ts/.yalc/@aztec/log/package.json | 18 - circuits/ts/.yalc/@aztec/log/src/index.ts | 12 - circuits/ts/.yalc/@aztec/log/yalc.sig | 1 - .../ts/.yalc/@aztec/wasm-worker/.eslintrc.cjs | 6 - .../ts/.yalc/@aztec/wasm-worker/.tsbuildinfo | 1 - .../ts/.yalc/@aztec/wasm-worker/README.md | 10 - .../.yalc/@aztec/wasm-worker/dest/index.d.ts | 5 - .../@aztec/wasm-worker/dest/index.d.ts.map | 1 - .../ts/.yalc/@aztec/wasm-worker/dest/index.js | 5 - .../dest/wasm/async_call_state.d.ts | 72 - .../wasm-worker/dest/wasm/empty_wasi_sdk.d.ts | 24 - .../wasm-worker/dest/wasm/empty_wasi_sdk.js | 61 - .../wasm-worker/dest/wasm/wasm_module.d.ts | 96 - .../dest/wasm/wasm_module.d.ts.map | 1 - .../wasm-worker/dest/wasm/wasm_module.js | 181 - .../dest/worker/browser/web_worker.d.ts | 6 - .../dest/worker/browser/web_worker.d.ts.map | 1 - .../dest/worker/browser/web_worker.js | 19 - .../@aztec/wasm-worker/dest/worker/index.js | 2 - .../wasm-worker/dest/worker/worker_pool.js | 62 - .../ts/.yalc/@aztec/wasm-worker/package.json | 42 - .../ts/.yalc/@aztec/wasm-worker/src/index.ts | 5 - .../wasm-worker/src/wasm/empty_wasi_sdk.ts | 61 - .../wasm-worker/src/wasm/wasm_module.test.ts | 27 - .../wasm-worker/src/wasm/wasm_module.ts | 203 - .../src/worker/browser/web_worker.ts | 20 - .../@aztec/wasm-worker/src/worker/index.ts | 1 - .../wasm-worker/src/worker/worker_pool.ts | 73 - .../ts/.yalc/@aztec/wasm-worker/tsconfig.json | 9 - circuits/ts/.yalc/@aztec/wasm-worker/yalc.sig | 1 - circuits/ts/.yalc/@aztec/wasm/.eslintrc.cjs | 6 - .../@aztec/wasm/dest/memory_fifo.d.ts.map | 1 - .../browser/message_port_socket.d.ts.map | 1 - .../transport/browser/message_port_socket.js | 37 - .../browser/shared_worker_listener.d.ts.map | 1 - .../browser/shared_worker_listener.js | 39 - .../browser/worker_listener.d.ts.map | 1 - .../dest/transport/browser/worker_listener.js | 39 - .../dispatch/create_dispatch_fn.d.ts.map | 1 - .../transport/dispatch/create_dispatch_fn.js | 11 - .../dispatch/create_dispatch_proxy.d.ts.map | 1 - .../dest/transport/dispatch/messages.d.ts | 45 - .../dest/transport/dispatch/messages.d.ts.map | 1 - .../transport/interface/transferable.d.ts.map | 1 - .../dest/transport/interface/transferable.js | 35 - .../node/node_connector_socket.d.ts.map | 1 - .../transport/node/node_connector_socket.js | 33 - .../transport/node/node_listener_socket.js | 34 - .../dest/transport/transport_client.d.ts.map | 1 - .../wasm/dest/transport/transport_client.js | 79 - .../wasm/dest/wasm/async_call_state.d.ts | 72 - .../wasm/dest/wasm/async_call_state.d.ts.map | 1 - .../@aztec/wasm/dest/wasm/async_call_state.js | 111 - .../@aztec/wasm/dest/wasm/empty_wasi_sdk.d.ts | 24 - .../wasm/dest/wasm/empty_wasi_sdk.d.ts.map | 1 - .../ts/.yalc/@aztec/wasm/dest/wasm/index.d.ts | 3 - .../@aztec/wasm/dest/wasm/index.d.ts.map | 1 - .../ts/.yalc/@aztec/wasm/dest/wasm/index.js | 3 - .../@aztec/wasm/dest/wasm/wasm_module.d.ts | 107 - .../@aztec/wasm/dest/wasm/wasm_module.js | 202 - .../wasm/dest/worker/browser/index.d.ts | 3 - .../wasm/dest/worker/browser/index.d.ts.map | 1 - .../@aztec/wasm/dest/worker/browser/index.js | 3 - .../dest/worker/browser/start_web_module.d.ts | 7 - .../worker/browser/start_web_module.d.ts.map | 1 - .../dest/worker/browser/start_web_module.js | 22 - .../dest/worker/browser/web_data_store.d.ts | 23 - .../worker/browser/web_data_store.d.ts.map | 1 - .../dest/worker/browser/web_data_store.js | 32 - .../@aztec/wasm/dest/worker/data_store.d.ts | 9 - .../wasm/dest/worker/data_store.d.ts.map | 1 - .../@aztec/wasm/dest/worker/data_store.js | 2 - .../@aztec/wasm/dest/worker/node/index.d.ts | 3 - .../wasm/dest/worker/node/index.d.ts.map | 1 - .../@aztec/wasm/dest/worker/node/index.js | 3 - .../dest/worker/node/node_data_store.d.ts | 22 - .../dest/worker/node/node_data_store.d.ts.map | 1 - .../wasm/dest/worker/node/node_data_store.js | 31 - .../wasm/dest/worker/node/node_worker.d.ts | 6 - .../dest/worker/node/node_worker.d.ts.map | 1 - .../wasm/dest/worker/node/node_worker.js | 21 - .../dest/worker/node/start_node_module.d.ts | 7 - .../worker/node/start_node_module.d.ts.map | 1 - .../dest/worker/node/start_node_module.js | 26 - .../@aztec/wasm/dest/worker/wasm_worker.d.ts | 9 - .../wasm/dest/worker/wasm_worker.d.ts.map | 1 - .../@aztec/wasm/dest/worker/wasm_worker.js | 2 - .../@aztec/wasm/dest/worker/worker_pool.d.ts | 40 - .../wasm/dest/worker/worker_pool.d.ts.map | 1 - .../ts/.yalc/@aztec/wasm/src/test/gcd.wasm | Bin 76 -> 0 bytes .../ts/.yalc/@aztec/wasm/src/test/gcd.wat | 27 - .../@aztec/wasm/src/wasm/async_call_state.ts | 136 - .../ts/.yalc/@aztec/wasm/src/wasm/index.ts | 2 - .../@aztec/wasm/src/worker/browser/index.ts | 2 - .../src/worker/browser/start_web_module.ts | 23 - .../wasm/src/worker/browser/web_data_store.ts | 37 - .../@aztec/wasm/src/worker/data_store.ts | 7 - .../@aztec/wasm/src/worker/node/index.ts | 2 - .../wasm/src/worker/node/node_data_store.ts | 36 - .../wasm/src/worker/node/node_worker.ts | 22 - .../wasm/src/worker/node/start_node_module.ts | 28 - .../@aztec/wasm/src/worker/wasm_worker.ts | 7 - .../ts/.yalc/@aztec/wasm/tsconfig.dest.json | 4 - circuits/ts/.yalc/@aztec/wasm/tsconfig.json | 9 - circuits/ts/package.json | 14 +- circuits/ts/src/crs/index.ts | 47 +- circuits/ts/src/index.ts | 2 +- circuits/ts/src/structs/base_rollup.test.ts | 60 +- circuits/ts/src/structs/base_rollup.ts | 64 +- circuits/ts/src/structs/call_context.ts | 8 +- circuits/ts/src/structs/function_data.test.ts | 8 +- circuits/ts/src/structs/function_data.ts | 14 +- circuits/ts/src/structs/index.ts | 22 +- circuits/ts/src/structs/kernel.test.ts | 19 +- circuits/ts/src/structs/kernel.ts | 79 +- circuits/ts/src/structs/merge_rollup.ts | 49 +- .../private_circuit_public_inputs.test.ts | 26 +- .../structs/private_circuit_public_inputs.ts | 38 +- circuits/ts/src/structs/root_rollup.ts | 44 +- circuits/ts/src/structs/shared.ts | 50 +- circuits/ts/src/structs/tx.test.ts | 11 +- circuits/ts/src/structs/tx.ts | 12 +- circuits/ts/src/structs/verification_key.ts | 11 +- circuits/ts/src/tests/expectSerialize.ts | 54 +- circuits/ts/src/tests/factories.ts | 75 +- .../writeGlobalVerifierReferenceString.ts | 15 +- circuits/ts/src/utils/buffer_reader.ts | 16 +- circuits/ts/src/utils/index.ts | 4 +- circuits/ts/src/utils/jsUtils.ts | 23 +- circuits/ts/src/utils/serialize.ts | 14 +- circuits/ts/src/wasm/circuits_wasm.test.ts | 24 +- circuits/ts/src/wasm/circuits_wasm.ts | 92 +- circuits/ts/src/wasm/index.ts | 2 +- circuits/ts/yalc.lock | 22 - circuits/ts/yarn.lock | 3505 ----------- circuits/yarn.lock | 5243 +++++++++++++++++ 548 files changed, 10049 insertions(+), 7511 deletions(-) create mode 100644 circuits/.yalc/@aztec/foundation/.circleci/config.yml create mode 100644 circuits/.yalc/@aztec/foundation/.dockerignore create mode 100644 circuits/.yalc/@aztec/foundation/.editorconfig create mode 100644 circuits/.yalc/@aztec/foundation/.eslintrc.cjs create mode 100644 circuits/.yalc/@aztec/foundation/.gitattributes create mode 100644 circuits/.yalc/@aztec/foundation/.github/pull_request_template.md create mode 100644 circuits/.yalc/@aztec/foundation/.gitmodules create mode 100644 circuits/.yalc/@aztec/foundation/.nvmrc create mode 100644 circuits/.yalc/@aztec/foundation/.prettierignore create mode 100644 circuits/.yalc/@aztec/foundation/.prettierrc.json create mode 100644 circuits/.yalc/@aztec/foundation/.tsbuildinfo create mode 100644 circuits/.yalc/@aztec/foundation/.vscode/extensions.json create mode 100644 circuits/.yalc/@aztec/foundation/.vscode/launch.json create mode 100644 circuits/.yalc/@aztec/foundation/.vscode/settings.json rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/foundation}/Dockerfile (55%) create mode 100644 circuits/.yalc/@aztec/foundation/LICENSE create mode 100644 circuits/.yalc/@aztec/foundation/PROJECT create mode 100644 circuits/.yalc/@aztec/foundation/README.md create mode 100644 circuits/.yalc/@aztec/foundation/VERSION create mode 100755 circuits/.yalc/@aztec/foundation/bootstrap.sh create mode 100644 circuits/.yalc/@aztec/foundation/build_manifest.json create mode 100644 circuits/.yalc/@aztec/foundation/dest/async-map/index.d.ts create mode 100644 circuits/.yalc/@aztec/foundation/dest/async-map/index.d.ts.map create mode 100644 circuits/.yalc/@aztec/foundation/dest/async-map/index.js create mode 100644 circuits/.yalc/@aztec/foundation/dest/bigint-buffer/index.d.ts create mode 100644 circuits/.yalc/@aztec/foundation/dest/bigint-buffer/index.d.ts.map create mode 100644 circuits/.yalc/@aztec/foundation/dest/bigint-buffer/index.js create mode 100644 circuits/.yalc/@aztec/foundation/dest/crypto/index.d.ts rename circuits/{ts/.yalc/@aztec/wasm-worker/dest/worker => .yalc/@aztec/foundation/dest/crypto}/index.d.ts.map (52%) create mode 100644 circuits/.yalc/@aztec/foundation/dest/crypto/index.js create mode 100644 circuits/.yalc/@aztec/foundation/dest/crypto/random/index.d.ts create mode 100644 circuits/.yalc/@aztec/foundation/dest/crypto/random/index.d.ts.map create mode 100644 circuits/.yalc/@aztec/foundation/dest/crypto/random/index.js create mode 100644 circuits/.yalc/@aztec/foundation/dest/errors/index.d.ts create mode 100644 circuits/.yalc/@aztec/foundation/dest/errors/index.d.ts.map create mode 100644 circuits/.yalc/@aztec/foundation/dest/errors/index.js create mode 100644 circuits/.yalc/@aztec/foundation/dest/fifo/bounded_serial_queue.d.ts create mode 100644 circuits/.yalc/@aztec/foundation/dest/fifo/bounded_serial_queue.d.ts.map create mode 100644 circuits/.yalc/@aztec/foundation/dest/fifo/bounded_serial_queue.js create mode 100644 circuits/.yalc/@aztec/foundation/dest/fifo/index.d.ts create mode 100644 circuits/.yalc/@aztec/foundation/dest/fifo/index.d.ts.map create mode 100644 circuits/.yalc/@aztec/foundation/dest/fifo/index.js rename circuits/{ts/.yalc/@aztec/wasm/dest => .yalc/@aztec/foundation/dest/fifo}/memory_fifo.d.ts (86%) create mode 100644 circuits/.yalc/@aztec/foundation/dest/fifo/memory_fifo.d.ts.map rename circuits/{ts/.yalc/@aztec/wasm/dest => .yalc/@aztec/foundation/dest/fifo}/memory_fifo.js (51%) create mode 100644 circuits/.yalc/@aztec/foundation/dest/fifo/semaphore.d.ts create mode 100644 circuits/.yalc/@aztec/foundation/dest/fifo/semaphore.d.ts.map create mode 100644 circuits/.yalc/@aztec/foundation/dest/fifo/semaphore.js create mode 100644 circuits/.yalc/@aztec/foundation/dest/fifo/serial_queue.d.ts create mode 100644 circuits/.yalc/@aztec/foundation/dest/fifo/serial_queue.d.ts.map create mode 100644 circuits/.yalc/@aztec/foundation/dest/fifo/serial_queue.js create mode 100644 circuits/.yalc/@aztec/foundation/dest/index.d.ts create mode 100644 circuits/.yalc/@aztec/foundation/dest/index.d.ts.map create mode 100644 circuits/.yalc/@aztec/foundation/dest/index.js rename circuits/{ts/.yalc/@aztec/wasm-worker/dest/worker => .yalc/@aztec/foundation/dest/iso-fetch}/index.d.ts (50%) create mode 100644 circuits/.yalc/@aztec/foundation/dest/iso-fetch/index.d.ts.map create mode 100644 circuits/.yalc/@aztec/foundation/dest/iso-fetch/index.js create mode 100644 circuits/.yalc/@aztec/foundation/dest/log/console.d.ts create mode 100644 circuits/.yalc/@aztec/foundation/dest/log/console.d.ts.map create mode 100644 circuits/.yalc/@aztec/foundation/dest/log/console.js create mode 100644 circuits/.yalc/@aztec/foundation/dest/log/debug.d.ts create mode 100644 circuits/.yalc/@aztec/foundation/dest/log/debug.d.ts.map create mode 100644 circuits/.yalc/@aztec/foundation/dest/log/debug.js create mode 100644 circuits/.yalc/@aztec/foundation/dest/log/index.d.ts create mode 100644 circuits/.yalc/@aztec/foundation/dest/log/index.d.ts.map create mode 100644 circuits/.yalc/@aztec/foundation/dest/log/index.js create mode 100644 circuits/.yalc/@aztec/foundation/dest/log/log_history.d.ts create mode 100644 circuits/.yalc/@aztec/foundation/dest/log/log_history.d.ts.map create mode 100644 circuits/.yalc/@aztec/foundation/dest/log/log_history.js create mode 100644 circuits/.yalc/@aztec/foundation/dest/mutex/index.d.ts create mode 100644 circuits/.yalc/@aztec/foundation/dest/mutex/index.d.ts.map create mode 100644 circuits/.yalc/@aztec/foundation/dest/mutex/index.js create mode 100644 circuits/.yalc/@aztec/foundation/dest/mutex/mutex_database.d.ts create mode 100644 circuits/.yalc/@aztec/foundation/dest/mutex/mutex_database.d.ts.map create mode 100644 circuits/.yalc/@aztec/foundation/dest/mutex/mutex_database.js create mode 100644 circuits/.yalc/@aztec/foundation/dest/retry/index.d.ts create mode 100644 circuits/.yalc/@aztec/foundation/dest/retry/index.d.ts.map create mode 100644 circuits/.yalc/@aztec/foundation/dest/retry/index.js create mode 100644 circuits/.yalc/@aztec/foundation/dest/running-promise/index.d.ts create mode 100644 circuits/.yalc/@aztec/foundation/dest/running-promise/index.d.ts.map create mode 100644 circuits/.yalc/@aztec/foundation/dest/running-promise/index.js create mode 100644 circuits/.yalc/@aztec/foundation/dest/serialize/deserializer.d.ts create mode 100644 circuits/.yalc/@aztec/foundation/dest/serialize/deserializer.d.ts.map create mode 100644 circuits/.yalc/@aztec/foundation/dest/serialize/deserializer.js create mode 100644 circuits/.yalc/@aztec/foundation/dest/serialize/free_funcs.d.ts create mode 100644 circuits/.yalc/@aztec/foundation/dest/serialize/free_funcs.d.ts.map create mode 100644 circuits/.yalc/@aztec/foundation/dest/serialize/free_funcs.js create mode 100644 circuits/.yalc/@aztec/foundation/dest/serialize/index.d.ts create mode 100644 circuits/.yalc/@aztec/foundation/dest/serialize/index.d.ts.map create mode 100644 circuits/.yalc/@aztec/foundation/dest/serialize/index.js create mode 100644 circuits/.yalc/@aztec/foundation/dest/serialize/serializer.d.ts create mode 100644 circuits/.yalc/@aztec/foundation/dest/serialize/serializer.d.ts.map create mode 100644 circuits/.yalc/@aztec/foundation/dest/serialize/serializer.js create mode 100644 circuits/.yalc/@aztec/foundation/dest/sleep/index.d.ts create mode 100644 circuits/.yalc/@aztec/foundation/dest/sleep/index.d.ts.map create mode 100644 circuits/.yalc/@aztec/foundation/dest/sleep/index.js create mode 100644 circuits/.yalc/@aztec/foundation/dest/timer/index.d.ts create mode 100644 circuits/.yalc/@aztec/foundation/dest/timer/index.d.ts.map create mode 100644 circuits/.yalc/@aztec/foundation/dest/timer/index.js create mode 100644 circuits/.yalc/@aztec/foundation/dest/timer/timeout.d.ts create mode 100644 circuits/.yalc/@aztec/foundation/dest/timer/timeout.d.ts.map create mode 100644 circuits/.yalc/@aztec/foundation/dest/timer/timeout.js create mode 100644 circuits/.yalc/@aztec/foundation/dest/timer/timer.d.ts create mode 100644 circuits/.yalc/@aztec/foundation/dest/timer/timer.d.ts.map create mode 100644 circuits/.yalc/@aztec/foundation/dest/timer/timer.js rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/foundation}/dest/transport/browser/index.d.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/foundation}/dest/transport/browser/index.d.ts.map (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/foundation}/dest/transport/browser/index.js (100%) rename circuits/{ts/.yalc/@aztec/wasm => .yalc/@aztec/foundation}/dest/transport/browser/message_port_socket.d.ts (52%) create mode 100644 circuits/.yalc/@aztec/foundation/dest/transport/browser/message_port_socket.d.ts.map create mode 100644 circuits/.yalc/@aztec/foundation/dest/transport/browser/message_port_socket.js rename circuits/{ts/.yalc/@aztec/wasm => .yalc/@aztec/foundation}/dest/transport/browser/shared_worker_connector.d.ts (56%) rename circuits/{ts/.yalc/@aztec/wasm => .yalc/@aztec/foundation}/dest/transport/browser/shared_worker_connector.d.ts.map (51%) rename circuits/{ts/.yalc/@aztec/wasm => .yalc/@aztec/foundation}/dest/transport/browser/shared_worker_connector.js (50%) rename circuits/{ts/.yalc/@aztec/wasm => .yalc/@aztec/foundation}/dest/transport/browser/shared_worker_listener.d.ts (56%) create mode 100644 circuits/.yalc/@aztec/foundation/dest/transport/browser/shared_worker_listener.d.ts.map create mode 100644 circuits/.yalc/@aztec/foundation/dest/transport/browser/shared_worker_listener.js rename circuits/{ts/.yalc/@aztec/wasm => .yalc/@aztec/foundation}/dest/transport/browser/worker_connector.d.ts (80%) rename circuits/{ts/.yalc/@aztec/wasm => .yalc/@aztec/foundation}/dest/transport/browser/worker_connector.d.ts.map (53%) rename circuits/{ts/.yalc/@aztec/wasm => .yalc/@aztec/foundation}/dest/transport/browser/worker_connector.js (51%) rename circuits/{ts/.yalc/@aztec/wasm => .yalc/@aztec/foundation}/dest/transport/browser/worker_listener.d.ts (70%) create mode 100644 circuits/.yalc/@aztec/foundation/dest/transport/browser/worker_listener.d.ts.map create mode 100644 circuits/.yalc/@aztec/foundation/dest/transport/browser/worker_listener.js rename circuits/{ts/.yalc/@aztec/wasm => .yalc/@aztec/foundation}/dest/transport/dispatch/create_dispatch_fn.d.ts (82%) create mode 100644 circuits/.yalc/@aztec/foundation/dest/transport/dispatch/create_dispatch_fn.d.ts.map create mode 100644 circuits/.yalc/@aztec/foundation/dest/transport/dispatch/create_dispatch_fn.js rename circuits/{ts/.yalc/@aztec/wasm => .yalc/@aztec/foundation}/dest/transport/dispatch/create_dispatch_proxy.d.ts (77%) create mode 100644 circuits/.yalc/@aztec/foundation/dest/transport/dispatch/create_dispatch_proxy.d.ts.map rename circuits/{ts/.yalc/@aztec/wasm => .yalc/@aztec/foundation}/dest/transport/dispatch/create_dispatch_proxy.js (57%) create mode 100644 circuits/.yalc/@aztec/foundation/dest/transport/dispatch/messages.d.ts create mode 100644 circuits/.yalc/@aztec/foundation/dest/transport/dispatch/messages.d.ts.map rename circuits/{ts/.yalc/@aztec/wasm => .yalc/@aztec/foundation}/dest/transport/dispatch/messages.js (52%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/foundation}/dest/transport/index.d.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/foundation}/dest/transport/index.d.ts.map (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/foundation}/dest/transport/index.js (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/foundation}/dest/transport/interface/connector.d.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/foundation}/dest/transport/interface/connector.d.ts.map (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/foundation}/dest/transport/interface/connector.js (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/foundation}/dest/transport/interface/listener.d.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/foundation}/dest/transport/interface/listener.d.ts.map (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/foundation}/dest/transport/interface/listener.js (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/foundation}/dest/transport/interface/socket.d.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/foundation}/dest/transport/interface/socket.d.ts.map (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/foundation}/dest/transport/interface/socket.js (100%) rename circuits/{ts/.yalc/@aztec/wasm => .yalc/@aztec/foundation}/dest/transport/interface/transferable.d.ts (70%) create mode 100644 circuits/.yalc/@aztec/foundation/dest/transport/interface/transferable.d.ts.map create mode 100644 circuits/.yalc/@aztec/foundation/dest/transport/interface/transferable.js rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/foundation}/dest/transport/node/index.d.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/foundation}/dest/transport/node/index.d.ts.map (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/foundation}/dest/transport/node/index.js (100%) rename circuits/{ts/.yalc/@aztec/wasm => .yalc/@aztec/foundation}/dest/transport/node/node_connector.d.ts (74%) rename circuits/{ts/.yalc/@aztec/wasm => .yalc/@aztec/foundation}/dest/transport/node/node_connector.d.ts.map (67%) rename circuits/{ts/.yalc/@aztec/wasm => .yalc/@aztec/foundation}/dest/transport/node/node_connector.js (53%) rename circuits/{ts/.yalc/@aztec/wasm => .yalc/@aztec/foundation}/dest/transport/node/node_connector_socket.d.ts (54%) create mode 100644 circuits/.yalc/@aztec/foundation/dest/transport/node/node_connector_socket.d.ts.map create mode 100644 circuits/.yalc/@aztec/foundation/dest/transport/node/node_connector_socket.js rename circuits/{ts/.yalc/@aztec/wasm => .yalc/@aztec/foundation}/dest/transport/node/node_listener.d.ts (70%) rename circuits/{ts/.yalc/@aztec/wasm => .yalc/@aztec/foundation}/dest/transport/node/node_listener.d.ts.map (61%) rename circuits/{ts/.yalc/@aztec/wasm => .yalc/@aztec/foundation}/dest/transport/node/node_listener.js (62%) rename circuits/{ts/.yalc/@aztec/wasm => .yalc/@aztec/foundation}/dest/transport/node/node_listener_socket.d.ts (63%) rename circuits/{ts/.yalc/@aztec/wasm => .yalc/@aztec/foundation}/dest/transport/node/node_listener_socket.d.ts.map (61%) create mode 100644 circuits/.yalc/@aztec/foundation/dest/transport/node/node_listener_socket.js rename circuits/{ts/.yalc/@aztec/wasm => .yalc/@aztec/foundation}/dest/transport/transport_client.d.ts (68%) create mode 100644 circuits/.yalc/@aztec/foundation/dest/transport/transport_client.d.ts.map create mode 100644 circuits/.yalc/@aztec/foundation/dest/transport/transport_client.js rename circuits/{ts/.yalc/@aztec/wasm => .yalc/@aztec/foundation}/dest/transport/transport_server.d.ts (64%) rename circuits/{ts/.yalc/@aztec/wasm => .yalc/@aztec/foundation}/dest/transport/transport_server.d.ts.map (57%) rename circuits/{ts/.yalc/@aztec/wasm => .yalc/@aztec/foundation}/dest/transport/transport_server.js (50%) create mode 100644 circuits/.yalc/@aztec/foundation/package.json create mode 100644 circuits/.yalc/@aztec/foundation/src/async-map/async_map.test.ts create mode 100644 circuits/.yalc/@aztec/foundation/src/async-map/index.ts create mode 100644 circuits/.yalc/@aztec/foundation/src/bigint-buffer/index.ts create mode 100644 circuits/.yalc/@aztec/foundation/src/crypto/index.ts create mode 100644 circuits/.yalc/@aztec/foundation/src/crypto/random/index.test.ts create mode 100644 circuits/.yalc/@aztec/foundation/src/crypto/random/index.ts create mode 100644 circuits/.yalc/@aztec/foundation/src/errors/index.ts rename circuits/{ts/.yalc/@aztec => .yalc/@aztec/foundation/src}/eslint-config/index.js (83%) rename circuits/{ts/.yalc/@aztec => .yalc/@aztec/foundation/src}/eslint-config/package.json (55%) create mode 100644 circuits/.yalc/@aztec/foundation/src/fifo/bounded_serial_queue.ts create mode 100644 circuits/.yalc/@aztec/foundation/src/fifo/index.ts rename circuits/{ts/.yalc/@aztec/wasm/src => .yalc/@aztec/foundation/src/fifo}/memory_fifo.ts (91%) create mode 100644 circuits/.yalc/@aztec/foundation/src/fifo/semaphore.ts create mode 100644 circuits/.yalc/@aztec/foundation/src/fifo/serial_queue.ts create mode 100644 circuits/.yalc/@aztec/foundation/src/index.ts create mode 100644 circuits/.yalc/@aztec/foundation/src/iso-fetch/index.ts create mode 100644 circuits/.yalc/@aztec/foundation/src/log/console.ts create mode 100644 circuits/.yalc/@aztec/foundation/src/log/debug.ts create mode 100644 circuits/.yalc/@aztec/foundation/src/log/index.ts create mode 100644 circuits/.yalc/@aztec/foundation/src/log/log_history.test.ts create mode 100644 circuits/.yalc/@aztec/foundation/src/log/log_history.ts create mode 100644 circuits/.yalc/@aztec/foundation/src/mutex/index.ts create mode 100644 circuits/.yalc/@aztec/foundation/src/mutex/mutex.test.ts create mode 100644 circuits/.yalc/@aztec/foundation/src/mutex/mutex_database.ts create mode 100644 circuits/.yalc/@aztec/foundation/src/prettier-config/index.js create mode 100644 circuits/.yalc/@aztec/foundation/src/prettier-config/package.json create mode 100644 circuits/.yalc/@aztec/foundation/src/retry/index.ts create mode 100644 circuits/.yalc/@aztec/foundation/src/running-promise/index.ts create mode 100644 circuits/.yalc/@aztec/foundation/src/serialize/deserializer.ts create mode 100644 circuits/.yalc/@aztec/foundation/src/serialize/free_funcs.ts create mode 100644 circuits/.yalc/@aztec/foundation/src/serialize/index.ts create mode 100644 circuits/.yalc/@aztec/foundation/src/serialize/serialize.test.ts create mode 100644 circuits/.yalc/@aztec/foundation/src/serialize/serializer.ts create mode 100644 circuits/.yalc/@aztec/foundation/src/sleep/index.ts create mode 100644 circuits/.yalc/@aztec/foundation/src/timer/index.ts create mode 100644 circuits/.yalc/@aztec/foundation/src/timer/timeout.ts create mode 100644 circuits/.yalc/@aztec/foundation/src/timer/timer.ts rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/foundation}/src/transport/browser/index.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm => .yalc/@aztec/foundation}/src/transport/browser/message_port_socket.ts (62%) rename circuits/{ts/.yalc/@aztec/wasm => .yalc/@aztec/foundation}/src/transport/browser/shared_worker_connector.ts (56%) rename circuits/{ts/.yalc/@aztec/wasm => .yalc/@aztec/foundation}/src/transport/browser/shared_worker_listener.ts (66%) rename circuits/{ts/.yalc/@aztec/wasm => .yalc/@aztec/foundation}/src/transport/browser/worker_connector.ts (86%) rename circuits/{ts/.yalc/@aztec/wasm => .yalc/@aztec/foundation}/src/transport/browser/worker_listener.ts (80%) rename circuits/{ts/.yalc/@aztec/wasm => .yalc/@aztec/foundation}/src/transport/dispatch/create_dispatch_fn.ts (85%) rename circuits/{ts/.yalc/@aztec/wasm => .yalc/@aztec/foundation}/src/transport/dispatch/create_dispatch_proxy.ts (82%) rename circuits/{ts/.yalc/@aztec/wasm => .yalc/@aztec/foundation}/src/transport/dispatch/messages.ts (52%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/foundation}/src/transport/index.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/foundation}/src/transport/interface/connector.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/foundation}/src/transport/interface/listener.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/foundation}/src/transport/interface/socket.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm => .yalc/@aztec/foundation}/src/transport/interface/transferable.ts (71%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/foundation}/src/transport/node/index.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm => .yalc/@aztec/foundation}/src/transport/node/node_connector.ts (71%) rename circuits/{ts/.yalc/@aztec/wasm => .yalc/@aztec/foundation}/src/transport/node/node_connector_socket.ts (61%) rename circuits/{ts/.yalc/@aztec/wasm => .yalc/@aztec/foundation}/src/transport/node/node_listener.ts (76%) rename circuits/{ts/.yalc/@aztec/wasm => .yalc/@aztec/foundation}/src/transport/node/node_listener_socket.ts (70%) rename circuits/{ts/.yalc/@aztec/wasm => .yalc/@aztec/foundation}/src/transport/transport_client.ts (80%) rename circuits/{ts/.yalc/@aztec/wasm => .yalc/@aztec/foundation}/src/transport/transport_server.ts (86%) rename circuits/{ts/.yalc/@aztec/log => .yalc/@aztec/foundation}/tsconfig.dest.json (100%) create mode 100644 circuits/.yalc/@aztec/foundation/tsconfig.json create mode 100644 circuits/.yalc/@aztec/foundation/yalc.sig rename circuits/{ts/.yalc/@aztec/log => .yalc/@aztec/wasm}/.eslintrc.cjs (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/.tsbuildinfo (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/Dockerfile (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/README.md (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/dest/index.d.ts (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/dest/index.d.ts.map (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/dest/index.js (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/memory_fifo.d.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/memory_fifo.d.ts.map (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/memory_fifo.js (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/dest/transport/browser/index.d.ts (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/dest/transport/browser/index.d.ts.map (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/dest/transport/browser/index.js (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/browser/message_port_socket.d.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/browser/message_port_socket.d.ts.map (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/browser/message_port_socket.js (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/browser/shared_worker_connector.d.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/browser/shared_worker_connector.d.ts.map (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/browser/shared_worker_connector.js (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/browser/shared_worker_listener.d.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/browser/shared_worker_listener.d.ts.map (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/browser/shared_worker_listener.js (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/browser/worker_connector.d.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/browser/worker_connector.d.ts.map (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/browser/worker_connector.js (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/browser/worker_listener.d.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/browser/worker_listener.d.ts.map (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/browser/worker_listener.js (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/dispatch/create_dispatch_fn.d.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/dispatch/create_dispatch_fn.d.ts.map (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/dispatch/create_dispatch_fn.js (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/dispatch/create_dispatch_proxy.d.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/dispatch/create_dispatch_proxy.d.ts.map (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/dispatch/create_dispatch_proxy.js (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/dispatch/messages.d.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/dispatch/messages.d.ts.map (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/dispatch/messages.js (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/dest/transport/index.d.ts (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/dest/transport/index.d.ts.map (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/dest/transport/index.js (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/dest/transport/interface/connector.d.ts (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/dest/transport/interface/connector.d.ts.map (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/dest/transport/interface/connector.js (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/dest/transport/interface/listener.d.ts (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/dest/transport/interface/listener.d.ts.map (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/dest/transport/interface/listener.js (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/dest/transport/interface/socket.d.ts (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/dest/transport/interface/socket.d.ts.map (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/dest/transport/interface/socket.js (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/interface/transferable.d.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/interface/transferable.d.ts.map (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/interface/transferable.js (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/dest/transport/node/index.d.ts (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/dest/transport/node/index.d.ts.map (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/dest/transport/node/index.js (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/node/node_connector.d.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/node/node_connector.d.ts.map (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/node/node_connector.js (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/node/node_connector_socket.d.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/node/node_connector_socket.d.ts.map (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/node/node_connector_socket.js (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/node/node_listener.d.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/node/node_listener.d.ts.map (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/node/node_listener.js (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/node/node_listener_socket.d.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/node/node_listener_socket.d.ts.map (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/node/node_listener_socket.js (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/transport_client.d.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/transport_client.d.ts.map (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/transport_client.js (59%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/transport_server.d.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/transport_server.d.ts.map (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/transport/transport_server.js (100%) create mode 100644 circuits/.yalc/@aztec/wasm/dest/wasm/async_call_state.d.ts rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/wasm/async_call_state.d.ts.map (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/wasm/async_call_state.js (100%) create mode 100644 circuits/.yalc/@aztec/wasm/dest/wasm/empty_wasi_sdk.d.ts rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/wasm/empty_wasi_sdk.d.ts.map (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/dest/wasm/empty_wasi_sdk.js (63%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/wasm/index.d.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/wasm/index.d.ts.map (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/wasm/index.js (100%) create mode 100644 circuits/.yalc/@aztec/wasm/dest/wasm/wasm_module.d.ts rename circuits/{ts => }/.yalc/@aztec/wasm/dest/wasm/wasm_module.d.ts.map (100%) create mode 100644 circuits/.yalc/@aztec/wasm/dest/wasm/wasm_module.js rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/worker/browser/index.d.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/worker/browser/index.d.ts.map (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/worker/browser/index.js (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/worker/browser/start_web_module.d.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/worker/browser/start_web_module.d.ts.map (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/worker/browser/start_web_module.js (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/worker/browser/web_data_store.d.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/worker/browser/web_data_store.d.ts.map (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/worker/browser/web_data_store.js (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/dest/worker/browser/web_worker.d.ts (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/dest/worker/browser/web_worker.d.ts.map (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/dest/worker/browser/web_worker.js (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/worker/data_store.d.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/worker/data_store.d.ts.map (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/worker/data_store.js (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/dest/worker/index.d.ts (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/dest/worker/index.d.ts.map (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/dest/worker/index.js (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/worker/node/index.d.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/worker/node/index.d.ts.map (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/worker/node/index.js (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/worker/node/node_data_store.d.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/worker/node/node_data_store.d.ts.map (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/worker/node/node_data_store.js (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/worker/node/node_worker.d.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/worker/node/node_worker.d.ts.map (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/worker/node/node_worker.js (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/worker/node/start_node_module.d.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/worker/node/start_node_module.d.ts.map (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/worker/node/start_node_module.js (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/worker/wasm_worker.d.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/worker/wasm_worker.d.ts.map (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/worker/wasm_worker.js (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/worker/worker_pool.d.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/dest/worker/worker_pool.d.ts.map (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/dest/worker/worker_pool.js (70%) rename circuits/{ts => }/.yalc/@aztec/wasm/package.json (96%) rename circuits/{ts => }/.yalc/@aztec/wasm/src/index.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/src/memory_fifo.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/src/test/gcd.wasm (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/src/test/gcd.wat (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/src/transport/browser/index.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/src/transport/browser/message_port_socket.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/src/transport/browser/shared_worker_connector.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/src/transport/browser/shared_worker_listener.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/src/transport/browser/worker_connector.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/src/transport/browser/worker_listener.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/src/transport/dispatch/create_dispatch_fn.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/src/transport/dispatch/create_dispatch_proxy.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/src/transport/dispatch/messages.ts (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/src/transport/index.ts (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/src/transport/interface/connector.ts (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/src/transport/interface/listener.ts (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/src/transport/interface/socket.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/src/transport/interface/transferable.ts (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/src/transport/node/index.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/src/transport/node/node_connector.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/src/transport/node/node_connector_socket.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/src/transport/node/node_listener.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/src/transport/node/node_listener_socket.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/src/transport/transport_client.ts (73%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/src/transport/transport_server.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/src/wasm/async_call_state.ts (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/src/wasm/empty_wasi_sdk.ts (57%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/src/wasm/index.ts (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/src/wasm/wasm_module.test.ts (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/src/wasm/wasm_module.ts (89%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/src/worker/browser/index.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/src/worker/browser/start_web_module.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/src/worker/browser/web_data_store.ts (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/src/worker/browser/web_worker.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/src/worker/data_store.ts (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/src/worker/index.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/src/worker/node/index.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/src/worker/node/node_data_store.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/src/worker/node/node_worker.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/src/worker/node/start_node_module.ts (100%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/src/worker/wasm_worker.ts (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/src/worker/worker_pool.ts (79%) rename circuits/{ts/.yalc/@aztec/wasm-worker => .yalc/@aztec/wasm}/tsconfig.dest.json (100%) rename circuits/{ts/.yalc/@aztec/log => .yalc/@aztec/wasm}/tsconfig.json (100%) rename circuits/{ts => }/.yalc/@aztec/wasm/yalc.sig (100%) create mode 100644 circuits/.yarn/install-state.gz create mode 100644 circuits/.yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs create mode 100755 circuits/.yarn/releases/yarn-3.4.1.cjs create mode 100644 circuits/.yarnrc.yml create mode 100644 circuits/package.json delete mode 100644 circuits/ts/.gitignore delete mode 100644 circuits/ts/.yalc/@aztec/eslint-config/yalc.sig delete mode 100644 circuits/ts/.yalc/@aztec/log/.tsbuildinfo delete mode 100644 circuits/ts/.yalc/@aztec/log/Dockerfile delete mode 100644 circuits/ts/.yalc/@aztec/log/README.md delete mode 100644 circuits/ts/.yalc/@aztec/log/dest/index.d.ts delete mode 100644 circuits/ts/.yalc/@aztec/log/dest/index.d.ts.map delete mode 100644 circuits/ts/.yalc/@aztec/log/dest/index.js delete mode 100644 circuits/ts/.yalc/@aztec/log/package.json delete mode 100644 circuits/ts/.yalc/@aztec/log/src/index.ts delete mode 100644 circuits/ts/.yalc/@aztec/log/yalc.sig delete mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/.eslintrc.cjs delete mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/.tsbuildinfo delete mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/README.md delete mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/index.d.ts delete mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/index.d.ts.map delete mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/index.js delete mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/async_call_state.d.ts delete mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/empty_wasi_sdk.d.ts delete mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/empty_wasi_sdk.js delete mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/wasm_module.d.ts delete mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/wasm_module.d.ts.map delete mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/wasm_module.js delete mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/web_worker.d.ts delete mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/web_worker.d.ts.map delete mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/web_worker.js delete mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/index.js delete mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/worker_pool.js delete mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/package.json delete mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/index.ts delete mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/wasm/empty_wasi_sdk.ts delete mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/wasm/wasm_module.test.ts delete mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/wasm/wasm_module.ts delete mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/worker/browser/web_worker.ts delete mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/worker/index.ts delete mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/src/worker/worker_pool.ts delete mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/tsconfig.json delete mode 100644 circuits/ts/.yalc/@aztec/wasm-worker/yalc.sig delete mode 100644 circuits/ts/.yalc/@aztec/wasm/.eslintrc.cjs delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/memory_fifo.d.ts.map delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/message_port_socket.d.ts.map delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/message_port_socket.js delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_listener.d.ts.map delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_listener.js delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/worker_listener.d.ts.map delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/worker_listener.js delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_fn.d.ts.map delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_fn.js delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_proxy.d.ts.map delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/messages.d.ts delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/messages.d.ts.map delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/transferable.d.ts.map delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/transferable.js delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_connector_socket.d.ts.map delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_connector_socket.js delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_listener_socket.js delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/transport_client.d.ts.map delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/transport/transport_client.js delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/wasm/async_call_state.d.ts delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/wasm/async_call_state.d.ts.map delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/wasm/async_call_state.js delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/wasm/empty_wasi_sdk.d.ts delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/wasm/empty_wasi_sdk.d.ts.map delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/wasm/index.d.ts delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/wasm/index.d.ts.map delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/wasm/index.js delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/wasm/wasm_module.d.ts delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/wasm/wasm_module.js delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/index.d.ts delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/index.d.ts.map delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/index.js delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/start_web_module.d.ts delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/start_web_module.d.ts.map delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/start_web_module.js delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/web_data_store.d.ts delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/web_data_store.d.ts.map delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/web_data_store.js delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/data_store.d.ts delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/data_store.d.ts.map delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/data_store.js delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/node/index.d.ts delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/node/index.d.ts.map delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/node/index.js delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/node/node_data_store.d.ts delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/node/node_data_store.d.ts.map delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/node/node_data_store.js delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/node/node_worker.d.ts delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/node/node_worker.d.ts.map delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/node/node_worker.js delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/node/start_node_module.d.ts delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/node/start_node_module.d.ts.map delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/node/start_node_module.js delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/wasm_worker.d.ts delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/wasm_worker.d.ts.map delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/wasm_worker.js delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/worker_pool.d.ts delete mode 100644 circuits/ts/.yalc/@aztec/wasm/dest/worker/worker_pool.d.ts.map delete mode 100644 circuits/ts/.yalc/@aztec/wasm/src/test/gcd.wasm delete mode 100644 circuits/ts/.yalc/@aztec/wasm/src/test/gcd.wat delete mode 100644 circuits/ts/.yalc/@aztec/wasm/src/wasm/async_call_state.ts delete mode 100644 circuits/ts/.yalc/@aztec/wasm/src/wasm/index.ts delete mode 100644 circuits/ts/.yalc/@aztec/wasm/src/worker/browser/index.ts delete mode 100644 circuits/ts/.yalc/@aztec/wasm/src/worker/browser/start_web_module.ts delete mode 100644 circuits/ts/.yalc/@aztec/wasm/src/worker/browser/web_data_store.ts delete mode 100644 circuits/ts/.yalc/@aztec/wasm/src/worker/data_store.ts delete mode 100644 circuits/ts/.yalc/@aztec/wasm/src/worker/node/index.ts delete mode 100644 circuits/ts/.yalc/@aztec/wasm/src/worker/node/node_data_store.ts delete mode 100644 circuits/ts/.yalc/@aztec/wasm/src/worker/node/node_worker.ts delete mode 100644 circuits/ts/.yalc/@aztec/wasm/src/worker/node/start_node_module.ts delete mode 100644 circuits/ts/.yalc/@aztec/wasm/src/worker/wasm_worker.ts delete mode 100644 circuits/ts/.yalc/@aztec/wasm/tsconfig.dest.json delete mode 100644 circuits/ts/.yalc/@aztec/wasm/tsconfig.json delete mode 100644 circuits/ts/yalc.lock delete mode 100644 circuits/ts/yarn.lock create mode 100644 circuits/yarn.lock diff --git a/circuits/.gitignore b/circuits/.gitignore index 600d2d33bad..c44f4a2edde 100644 --- a/circuits/.gitignore +++ b/circuits/.gitignore @@ -1 +1,5 @@ -.vscode \ No newline at end of file +.vscode +node_modules +.yarn/cache +.yarn/install-state.gz +ts/dest diff --git a/circuits/.yalc/@aztec/foundation/.circleci/config.yml b/circuits/.yalc/@aztec/foundation/.circleci/config.yml new file mode 100644 index 00000000000..16bfa7a9716 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/.circleci/config.yml @@ -0,0 +1,73 @@ +# This file uses YAML anchors and aliases to prevent repetition of blocks of config: +# https://support.atlassian.com/bitbucket-cloud/docs/yaml-anchors/ +# +# Two primary anchors are checkout and setup_env, called as the first step of almost all jobs: +# - checkout: A custom checkout step to reduce the amount of data downloaded to improve speed. +# - setup_env: Sets up the common environment used by all build steps. +# + +version: 2.1 +parameters: + workflow: + type: string + default: "system" + +# This build step checks out the code from the repository. It has a hardcoded readonly key to allow the checkout. +# Initially it just fetches the repo metadata for the current commit hash to a depth of 50 commits. +# We need historical commit hashes to calculate diffs between previous and current commits. +# It then checks out the fetched head to actually download the data. +checkout: &checkout + run: + name: "Checkout code" + command: | + cd $HOME + mkdir -p .ssh + chmod 0700 .ssh + ssh-keyscan -t rsa github.com >> .ssh/known_hosts + + # A read only key for cloning the repository. + echo $GIT_CHECKOUT_KEY | base64 -d > .ssh/id_rsa + + chmod 0600 .ssh/id_rsa + + # IF YOU'RE CHANGING THIS, YOU ALSO WANT TO CHANGE: build-system/remote_build/remote_build + # Shallow checkout this commit. + mkdir -p project + cd project + git init + git remote add origin $CIRCLE_REPOSITORY_URL + # Only download metadata when fetching. + git fetch --depth 50 --filter=blob:none origin $CIRCLE_SHA1 + git checkout FETCH_HEAD + # Pull in build-system submodule. + git submodule update --init build-system + +# Called setup_env to setup a bunch of global variables used throughout the rest of the build process. +# It takes the required CCI environment variables as inputs, and gives them normalised names for the rest of +# the build process. This enables easy running of the build system external to CCI, as used for powerful EC2 builds. +setup_env: &setup_env + run: + name: "Setup environment" + command: ./build-system/scripts/setup_env "$CIRCLE_SHA1" "$CIRCLE_TAG" "$CIRCLE_JOB" "$CIRCLE_REPOSITORY_URL" "$CIRCLE_BRANCH" + +jobs: + foundation: + machine: + image: ubuntu-2004:202010-01 + resource_class: large + steps: + - *checkout + - *setup_env + - run: + name: "Build and test" + command: build foundation + +workflows: + system: + when: + equal: [system, << pipeline.parameters.workflow >>] + jobs: + - foundation: + filters: + tags: + only: /v[0-9]+(\.[0-9]+)*(-[a-zA-Z-]+\.[0-9]+)?/ diff --git a/circuits/.yalc/@aztec/foundation/.dockerignore b/circuits/.yalc/@aztec/foundation/.dockerignore new file mode 100644 index 00000000000..eb6cc56dc87 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/.dockerignore @@ -0,0 +1,4 @@ +dest +node_modules +Dockerfile +.tsbuildinfo \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/.editorconfig b/circuits/.yalc/@aztec/foundation/.editorconfig new file mode 100644 index 00000000000..1ed453a371b --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/.editorconfig @@ -0,0 +1,10 @@ +root = true + +[*] +end_of_line = lf +insert_final_newline = true + +[*.{js,json,yml}] +charset = utf-8 +indent_style = space +indent_size = 2 diff --git a/circuits/.yalc/@aztec/foundation/.eslintrc.cjs b/circuits/.yalc/@aztec/foundation/.eslintrc.cjs new file mode 100644 index 00000000000..50e09c1ae68 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/.eslintrc.cjs @@ -0,0 +1,44 @@ +module.exports = { + extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'], + root: true, + parser: '@typescript-eslint/parser', + plugins: ['@typescript-eslint'], + overrides: [ + { + files: ['*.ts', '*.tsx'], + parserOptions: { + project: ['./tsconfig.json'], + }, + }, + ], + env: { + node: true, + }, + rules: { + '@typescript-eslint/explicit-module-boundary-types': 'off', + '@typescript-eslint/no-non-null-assertion': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-empty-function': 'off', + '@typescript-eslint/await-thenable': 'error', + '@typescript-eslint/no-floating-promises': 2, + 'require-await': 2, + 'no-constant-condition': 'off', + camelcase: 2, + 'no-restricted-imports': [ + 'warn', + { + patterns: [ + { + group: ['client-dest'], + message: "Fix this absolute garbage import. It's your duty to solve it before it spreads.", + }, + { + group: ['dest'], + message: 'You should not be importing from a build directory. Did you accidentally do a relative import?', + }, + ], + }, + ], + }, + ignorePatterns: ['node_modules', 'dest*', 'dist', '*.js', '.eslintrc.cjs'], +}; diff --git a/circuits/.yalc/@aztec/foundation/.gitattributes b/circuits/.yalc/@aztec/foundation/.gitattributes new file mode 100644 index 00000000000..70e53eefec5 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/.gitattributes @@ -0,0 +1 @@ +yarn.lock -diff diff --git a/circuits/.yalc/@aztec/foundation/.github/pull_request_template.md b/circuits/.yalc/@aztec/foundation/.github/pull_request_template.md new file mode 100644 index 00000000000..80cf79224fb --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/.github/pull_request_template.md @@ -0,0 +1,12 @@ +# Description + +Please provide a paragraph or two giving a summary of the change, including relevant motivation and context. + +# Checklist: + +- [ ] I have reviewed my diff in github, line by line. +- [ ] Every change is related to the PR description. +- [ ] I have [linked](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue) this pull request to the issue(s) that it resolves. +- [ ] There are no unexpected formatting changes, superfluous debug logs, or commented-out code. +- [ ] The branch has been rebased against the head of its merge target. +- [ ] I'm happy for the PR to be merged at the reviewer's next convenience. diff --git a/circuits/.yalc/@aztec/foundation/.gitmodules b/circuits/.yalc/@aztec/foundation/.gitmodules new file mode 100644 index 00000000000..2668ef48b2f --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/.gitmodules @@ -0,0 +1,3 @@ +[submodule "build-system"] + path = build-system + url = git@github.com:AztecProtocol/build-system.git diff --git a/circuits/.yalc/@aztec/foundation/.nvmrc b/circuits/.yalc/@aztec/foundation/.nvmrc new file mode 100644 index 00000000000..39e593ebeee --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/.nvmrc @@ -0,0 +1 @@ +v18.8.0 diff --git a/circuits/.yalc/@aztec/foundation/.prettierignore b/circuits/.yalc/@aztec/foundation/.prettierignore new file mode 100644 index 00000000000..b9d7ea4e730 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/.prettierignore @@ -0,0 +1,5 @@ +.yarn +.circleci +.pnp.cjs +.pnp.loader.mjs +.vscode \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/.prettierrc.json b/circuits/.yalc/@aztec/foundation/.prettierrc.json new file mode 100644 index 00000000000..7c3bbec6848 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/.prettierrc.json @@ -0,0 +1,6 @@ +{ + "singleQuote": true, + "trailingComma": "all", + "printWidth": 120, + "arrowParens": "avoid" +} diff --git a/circuits/.yalc/@aztec/foundation/.tsbuildinfo b/circuits/.yalc/@aztec/foundation/.tsbuildinfo new file mode 100644 index 00000000000..159a0e68368 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/.tsbuildinfo @@ -0,0 +1 @@ +{"program":{"fileNames":["../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es5.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2015.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2016.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2017.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2018.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2019.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2020.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2021.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2022.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.esnext.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.dom.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2015.core.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2015.collection.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2015.generator.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2015.promise.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2017.object.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2017.string.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2017.intl.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2018.intl.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2018.promise.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2019.array.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2019.object.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2019.string.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2019.intl.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2020.date.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2020.promise.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2020.string.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2020.intl.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2020.number.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2021.promise.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2021.string.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2021.weakref.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2021.intl.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2022.array.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2022.error.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2022.intl.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2022.object.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2022.sharedmemory.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.es2022.string.d.ts","../../../../../../../../opt/homebrew/lib/node_modules/typescript/lib/lib.esnext.intl.d.ts","../../../node_modules/tslib/tslib.d.ts","./src/async-map/index.ts","./src/bigint-buffer/index.ts","./src/errors/index.ts","./src/fifo/memory_fifo.ts","./src/fifo/serial_queue.ts","./src/fifo/semaphore.ts","./src/fifo/bounded_serial_queue.ts","./src/fifo/index.ts","./src/mutex/mutex_database.ts","./src/mutex/index.ts","./src/timer/timeout.ts","./src/timer/timer.ts","./src/timer/index.ts","./src/log/console.ts","./src/log/debug.ts","./src/log/log_history.ts","./src/log/index.ts","./src/sleep/index.ts","./src/retry/index.ts","./src/serialize/free_funcs.ts","./src/serialize/deserializer.ts","./src/serialize/serializer.ts","./src/serialize/index.ts","./src/transport/dispatch/create_dispatch_fn.ts","./src/transport/dispatch/messages.ts","./src/transport/interface/socket.ts","./src/transport/interface/connector.ts","./src/transport/transport_client.ts","./src/transport/interface/transferable.ts","./src/transport/dispatch/create_dispatch_proxy.ts","./src/transport/interface/listener.ts","./src/transport/transport_server.ts","./src/transport/browser/message_port_socket.ts","./src/transport/browser/worker_connector.ts","./src/transport/browser/worker_listener.ts","./src/transport/browser/shared_worker_connector.ts","./src/transport/browser/shared_worker_listener.ts","./src/transport/browser/index.ts","./src/transport/node/node_connector_socket.ts","./src/transport/node/node_connector.ts","./src/transport/node/node_listener_socket.ts","./src/transport/node/node_listener.ts","./src/transport/node/index.ts","./src/transport/index.ts","../../../node_modules/cross-fetch/index.d.ts","./src/iso-fetch/index.ts","../../../node_modules/@types/detect-node/index.d.ts","./src/crypto/random/index.ts","./src/crypto/index.ts","./src/running-promise/index.ts","./src/index.ts","../../../node_modules/@types/abstract-leveldown/index.d.ts","../../../node_modules/@babel/types/lib/index.d.ts","../../../node_modules/@types/babel__generator/index.d.ts","../../../node_modules/@babel/parser/typings/babel-parser.d.ts","../../../node_modules/@types/babel__template/index.d.ts","../../../node_modules/@types/babel__traverse/index.d.ts","../../../node_modules/@types/babel__core/index.d.ts","../../../node_modules/@types/node/assert.d.ts","../../../node_modules/@types/node/assert/strict.d.ts","../../../node_modules/@types/node/globals.d.ts","../../../node_modules/@types/node/async_hooks.d.ts","../../../node_modules/@types/node/buffer.d.ts","../../../node_modules/@types/node/child_process.d.ts","../../../node_modules/@types/node/cluster.d.ts","../../../node_modules/@types/node/console.d.ts","../../../node_modules/@types/node/constants.d.ts","../../../node_modules/@types/node/crypto.d.ts","../../../node_modules/@types/node/dgram.d.ts","../../../node_modules/@types/node/diagnostics_channel.d.ts","../../../node_modules/@types/node/dns.d.ts","../../../node_modules/@types/node/dns/promises.d.ts","../../../node_modules/@types/node/domain.d.ts","../../../node_modules/@types/node/dom-events.d.ts","../../../node_modules/@types/node/events.d.ts","../../../node_modules/@types/node/fs.d.ts","../../../node_modules/@types/node/fs/promises.d.ts","../../../node_modules/@types/node/http.d.ts","../../../node_modules/@types/node/http2.d.ts","../../../node_modules/@types/node/https.d.ts","../../../node_modules/@types/node/inspector.d.ts","../../../node_modules/@types/node/module.d.ts","../../../node_modules/@types/node/net.d.ts","../../../node_modules/@types/node/os.d.ts","../../../node_modules/@types/node/path.d.ts","../../../node_modules/@types/node/perf_hooks.d.ts","../../../node_modules/@types/node/process.d.ts","../../../node_modules/@types/node/punycode.d.ts","../../../node_modules/@types/node/querystring.d.ts","../../../node_modules/@types/node/readline.d.ts","../../../node_modules/@types/node/readline/promises.d.ts","../../../node_modules/@types/node/repl.d.ts","../../../node_modules/@types/node/stream.d.ts","../../../node_modules/@types/node/stream/promises.d.ts","../../../node_modules/@types/node/stream/consumers.d.ts","../../../node_modules/@types/node/stream/web.d.ts","../../../node_modules/@types/node/string_decoder.d.ts","../../../node_modules/@types/node/test.d.ts","../../../node_modules/@types/node/timers.d.ts","../../../node_modules/@types/node/timers/promises.d.ts","../../../node_modules/@types/node/tls.d.ts","../../../node_modules/@types/node/trace_events.d.ts","../../../node_modules/@types/node/tty.d.ts","../../../node_modules/@types/node/url.d.ts","../../../node_modules/@types/node/util.d.ts","../../../node_modules/@types/node/v8.d.ts","../../../node_modules/@types/node/vm.d.ts","../../../node_modules/@types/node/wasi.d.ts","../../../node_modules/@types/node/worker_threads.d.ts","../../../node_modules/@types/node/zlib.d.ts","../../../node_modules/@types/node/globals.global.d.ts","../../../node_modules/@types/node/index.d.ts","../../../node_modules/@types/graceful-fs/index.d.ts","../../../node_modules/@types/istanbul-lib-coverage/index.d.ts","../../../node_modules/@types/istanbul-lib-report/index.d.ts","../../../node_modules/@types/istanbul-reports/index.d.ts","../../../node_modules/@jest/expect-utils/build/index.d.ts","../../../node_modules/chalk/index.d.ts","../../../node_modules/@sinclair/typebox/typebox.d.ts","../../../node_modules/@jest/schemas/build/index.d.ts","../../../node_modules/jest-diff/node_modules/pretty-format/build/index.d.ts","../../../node_modules/jest-diff/build/index.d.ts","../../../node_modules/expect/node_modules/jest-matcher-utils/build/index.d.ts","../../../node_modules/expect/build/index.d.ts","../../../node_modules/@types/jest/node_modules/pretty-format/build/index.d.ts","../../../node_modules/@types/jest/index.d.ts","../../../node_modules/@types/json-schema/index.d.ts","../../../node_modules/@types/leveldown/index.d.ts","../../../node_modules/@types/prettier/index.d.ts","../../../node_modules/@types/semver/classes/semver.d.ts","../../../node_modules/@types/semver/functions/parse.d.ts","../../../node_modules/@types/semver/functions/valid.d.ts","../../../node_modules/@types/semver/functions/clean.d.ts","../../../node_modules/@types/semver/functions/inc.d.ts","../../../node_modules/@types/semver/functions/diff.d.ts","../../../node_modules/@types/semver/functions/major.d.ts","../../../node_modules/@types/semver/functions/minor.d.ts","../../../node_modules/@types/semver/functions/patch.d.ts","../../../node_modules/@types/semver/functions/prerelease.d.ts","../../../node_modules/@types/semver/functions/compare.d.ts","../../../node_modules/@types/semver/functions/rcompare.d.ts","../../../node_modules/@types/semver/functions/compare-loose.d.ts","../../../node_modules/@types/semver/functions/compare-build.d.ts","../../../node_modules/@types/semver/functions/sort.d.ts","../../../node_modules/@types/semver/functions/rsort.d.ts","../../../node_modules/@types/semver/functions/gt.d.ts","../../../node_modules/@types/semver/functions/lt.d.ts","../../../node_modules/@types/semver/functions/eq.d.ts","../../../node_modules/@types/semver/functions/neq.d.ts","../../../node_modules/@types/semver/functions/gte.d.ts","../../../node_modules/@types/semver/functions/lte.d.ts","../../../node_modules/@types/semver/functions/cmp.d.ts","../../../node_modules/@types/semver/functions/coerce.d.ts","../../../node_modules/@types/semver/classes/comparator.d.ts","../../../node_modules/@types/semver/classes/range.d.ts","../../../node_modules/@types/semver/functions/satisfies.d.ts","../../../node_modules/@types/semver/ranges/max-satisfying.d.ts","../../../node_modules/@types/semver/ranges/min-satisfying.d.ts","../../../node_modules/@types/semver/ranges/to-comparators.d.ts","../../../node_modules/@types/semver/ranges/min-version.d.ts","../../../node_modules/@types/semver/ranges/valid.d.ts","../../../node_modules/@types/semver/ranges/outside.d.ts","../../../node_modules/@types/semver/ranges/gtr.d.ts","../../../node_modules/@types/semver/ranges/ltr.d.ts","../../../node_modules/@types/semver/ranges/intersects.d.ts","../../../node_modules/@types/semver/ranges/simplify.d.ts","../../../node_modules/@types/semver/ranges/subset.d.ts","../../../node_modules/@types/semver/internals/identifiers.d.ts","../../../node_modules/@types/semver/index.d.ts","../../../node_modules/@types/stack-utils/index.d.ts","../../../node_modules/@types/yargs-parser/index.d.ts","../../../node_modules/@types/yargs/index.d.ts"],"fileInfos":[{"version":"8730f4bf322026ff5229336391a18bcaa1f94d4f82416c8b2f3954e2ccaae2ba","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc47c4fa66b9b9890cf076304de2a9c5201e94b740cffdf09f87296d877d71f6","impliedFormat":1},{"version":"7a387c58583dfca701b6c85e0adaf43fb17d590fb16d5b2dc0a2fbd89f35c467","impliedFormat":1},{"version":"8a12173c586e95f4433e0c6dc446bc88346be73ffe9ca6eec7aa63c8f3dca7f9","impliedFormat":1},{"version":"5f4e733ced4e129482ae2186aae29fde948ab7182844c3a5a51dd346182c7b06","impliedFormat":1},{"version":"4b421cbfb3a38a27c279dec1e9112c3d1da296f77a1a85ddadf7e7a425d45d18","impliedFormat":1},{"version":"1fc5ab7a764205c68fa10d381b08417795fc73111d6dd16b5b1ed36badb743d9","impliedFormat":1},{"version":"746d62152361558ea6d6115cf0da4dd10ede041d14882ede3568bce5dc4b4f1f","impliedFormat":1},{"version":"d11a03592451da2d1065e09e61f4e2a9bf68f780f4f6623c18b57816a9679d17","impliedFormat":1},{"version":"aea179452def8a6152f98f63b191b84e7cbd69b0e248c91e61fb2e52328abe8c","impliedFormat":1},{"version":"3aafcb693fe5b5c3bd277bd4c3a617b53db474fe498fc5df067c5603b1eebde7","affectsGlobalScope":true,"impliedFormat":1},{"version":"adb996790133eb33b33aadb9c09f15c2c575e71fb57a62de8bf74dbf59ec7dfb","affectsGlobalScope":true,"impliedFormat":1},{"version":"8cc8c5a3bac513368b0157f3d8b31cfdcfe78b56d3724f30f80ed9715e404af8","affectsGlobalScope":true,"impliedFormat":1},{"version":"cdccba9a388c2ee3fd6ad4018c640a471a6c060e96f1232062223063b0a5ac6a","affectsGlobalScope":true,"impliedFormat":1},{"version":"c5c05907c02476e4bde6b7e76a79ffcd948aedd14b6a8f56e4674221b0417398","affectsGlobalScope":true,"impliedFormat":1},{"version":"5f406584aef28a331c36523df688ca3650288d14f39c5d2e555c95f0d2ff8f6f","affectsGlobalScope":true,"impliedFormat":1},{"version":"22f230e544b35349cfb3bd9110b6ef37b41c6d6c43c3314a31bd0d9652fcec72","affectsGlobalScope":true,"impliedFormat":1},{"version":"7ea0b55f6b315cf9ac2ad622b0a7813315bb6e97bf4bb3fbf8f8affbca7dc695","affectsGlobalScope":true,"impliedFormat":1},{"version":"3013574108c36fd3aaca79764002b3717da09725a36a6fc02eac386593110f93","affectsGlobalScope":true,"impliedFormat":1},{"version":"eb26de841c52236d8222f87e9e6a235332e0788af8c87a71e9e210314300410a","affectsGlobalScope":true,"impliedFormat":1},{"version":"3be5a1453daa63e031d266bf342f3943603873d890ab8b9ada95e22389389006","affectsGlobalScope":true,"impliedFormat":1},{"version":"17bb1fc99591b00515502d264fa55dc8370c45c5298f4a5c2083557dccba5a2a","affectsGlobalScope":true,"impliedFormat":1},{"version":"7ce9f0bde3307ca1f944119f6365f2d776d281a393b576a18a2f2893a2d75c98","affectsGlobalScope":true,"impliedFormat":1},{"version":"6a6b173e739a6a99629a8594bfb294cc7329bfb7b227f12e1f7c11bc163b8577","affectsGlobalScope":true,"impliedFormat":1},{"version":"81cac4cbc92c0c839c70f8ffb94eb61e2d32dc1c3cf6d95844ca099463cf37ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"b0124885ef82641903d232172577f2ceb5d3e60aed4da1153bab4221e1f6dd4e","affectsGlobalScope":true,"impliedFormat":1},{"version":"0eb85d6c590b0d577919a79e0084fa1744c1beba6fd0d4e951432fa1ede5510a","affectsGlobalScope":true,"impliedFormat":1},{"version":"da233fc1c8a377ba9e0bed690a73c290d843c2c3d23a7bd7ec5cd3d7d73ba1e0","affectsGlobalScope":true,"impliedFormat":1},{"version":"d154ea5bb7f7f9001ed9153e876b2d5b8f5c2bb9ec02b3ae0d239ec769f1f2ae","affectsGlobalScope":true,"impliedFormat":1},{"version":"bb2d3fb05a1d2ffbca947cc7cbc95d23e1d053d6595391bd325deb265a18d36c","affectsGlobalScope":true,"impliedFormat":1},{"version":"c80df75850fea5caa2afe43b9949338ce4e2de086f91713e9af1a06f973872b8","affectsGlobalScope":true,"impliedFormat":1},{"version":"9d57b2b5d15838ed094aa9ff1299eecef40b190722eb619bac4616657a05f951","affectsGlobalScope":true,"impliedFormat":1},{"version":"6c51b5dd26a2c31dbf37f00cfc32b2aa6a92e19c995aefb5b97a3a64f1ac99de","affectsGlobalScope":true,"impliedFormat":1},{"version":"6e7997ef61de3132e4d4b2250e75343f487903ddf5370e7ce33cf1b9db9a63ed","affectsGlobalScope":true,"impliedFormat":1},{"version":"2ad234885a4240522efccd77de6c7d99eecf9b4de0914adb9a35c0c22433f993","affectsGlobalScope":true,"impliedFormat":1},{"version":"5e5e095c4470c8bab227dbbc61374878ecead104c74ab9960d3adcccfee23205","affectsGlobalScope":true,"impliedFormat":1},{"version":"09aa50414b80c023553090e2f53827f007a301bc34b0495bfb2c3c08ab9ad1eb","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7f680a43f8cd12a6b6122c07c54ba40952b0c8aa140dcfcf32eb9e6cb028596","affectsGlobalScope":true,"impliedFormat":1},{"version":"3787b83e297de7c315d55d4a7c546ae28e5f6c0a361b7a1dcec1f1f50a54ef11","affectsGlobalScope":true,"impliedFormat":1},{"version":"e7e8e1d368290e9295ef18ca23f405cf40d5456fa9f20db6373a61ca45f75f40","affectsGlobalScope":true,"impliedFormat":1},{"version":"faf0221ae0465363c842ce6aa8a0cbda5d9296940a8e26c86e04cc4081eea21e","affectsGlobalScope":true,"impliedFormat":1},{"version":"06393d13ea207a1bfe08ec8d7be562549c5e2da8983f2ee074e00002629d1871","affectsGlobalScope":true,"impliedFormat":1},{"version":"2768ef564cfc0689a1b76106c421a2909bdff0acbe87da010785adab80efdd5c","affectsGlobalScope":true,"impliedFormat":1},{"version":"b248e32ca52e8f5571390a4142558ae4f203ae2f94d5bac38a3084d529ef4e58","affectsGlobalScope":true,"impliedFormat":1},{"version":"6c55633c733c8378db65ac3da7a767c3cf2cf3057f0565a9124a16a3a2019e87","affectsGlobalScope":true,"impliedFormat":1},{"version":"fb4416144c1bf0323ccbc9afb0ab289c07312214e8820ad17d709498c865a3fe","affectsGlobalScope":true,"impliedFormat":1},{"version":"5b0ca94ec819d68d33da516306c15297acec88efeb0ae9e2b39f71dbd9685ef7","affectsGlobalScope":true,"impliedFormat":1},{"version":"34c839eaaa6d78c8674ae2c37af2236dee6831b13db7b4ef4df3ec889a04d4f2","affectsGlobalScope":true,"impliedFormat":1},{"version":"34478567f8a80171f88f2f30808beb7da15eac0538ae91282dd33dce928d98ed","affectsGlobalScope":true,"impliedFormat":1},{"version":"ab7d58e6161a550ff92e5aff755dc37fe896245348332cd5f1e1203479fe0ed1","affectsGlobalScope":true,"impliedFormat":1},{"version":"6bda95ea27a59a276e46043b7065b55bd4b316c25e70e29b572958fa77565d43","affectsGlobalScope":true,"impliedFormat":1},{"version":"aedb8de1abb2ff1095c153854a6df7deae4a5709c37297f9d6e9948b6806fa66","affectsGlobalScope":true,"impliedFormat":1},{"version":"a4da0551fd39b90ca7ce5f68fb55d4dc0c1396d589b612e1902f68ee090aaada","affectsGlobalScope":true,"impliedFormat":1},{"version":"11ffe3c281f375fff9ffdde8bbec7669b4dd671905509079f866f2354a788064","affectsGlobalScope":true,"impliedFormat":1},{"version":"52d1bb7ab7a3306fd0375c8bff560feed26ed676a5b0457fa8027b563aecb9a4","affectsGlobalScope":true,"impliedFormat":1},{"version":"f1c9fe42b65437a61104e601eb298c5c859fb522b483f1bdb700eed67a16f980","impliedFormat":1},{"version":"25ef63a0e5bd353cd8106688e0c0266fe9ff0814798e0afff7348471a02759d8","impliedFormat":99},{"version":"2dce98563cba19612f629d88c2551355228346fb9db690f9a1b82abfb7377087","impliedFormat":99},{"version":"b3a5f82292224b62cc1c4d891b993a61b0f225dcc9c0957d0e354d087c933db4","impliedFormat":99},{"version":"bc5207d1cafc733bb2f8a7abe692a70577431c9c1d52bc3aeecf5010ba0584b0","impliedFormat":99},{"version":"d7e435b85194e75ee8e7b1139298b4419f2d1f76a9080227c1f6edd585632c13","impliedFormat":99},{"version":"996eb3194e71bf12eec75c0b22496e6dfba629f144e501b7780f535dfcb2d7a3","impliedFormat":99},{"version":"da229b029be59e894cbda0a4e2dacd3323a4f6e896da121bfd3bc45072f85a77","impliedFormat":99},{"version":"abf81afefdb2dc976f2c4b4137fadd9f2322e335c9966a0069931e74fda199d1","impliedFormat":99},{"version":"9eda3d6e7d74bdb8935e3c388e6e41490853e75b77a48fee2bf77c6b203ce023","impliedFormat":99},{"version":"eee05565d6ed2aa11baee20bb2d4cb61b79b6c81c71d7f55f2316f0cc60f9315","impliedFormat":99},{"version":"64278e69528c492374909cd391cf1a8005275356024b060dccb044747455d8af","impliedFormat":99},{"version":"e7aed0f4999ccdbf202d0d1a85dabf861ac31038bcdda4551532ff503ef17cfb","impliedFormat":99},{"version":"290f9e82a0de95de8e9b1ccdb299682e0601874aa56dbe454fef21ced35a3863","impliedFormat":99},{"version":"fe052abc31c01d0f7c969b75a661597a2adc62843ab00c70a3e69cc11f92ff51","impliedFormat":99},{"version":"deb28fe8dce3cecf86c451a75b2dd2b91c303ed056e47e4fdabeb80fb7906aee","impliedFormat":99},{"version":"eb6ec0e78eada1db0d9de32b0dc9613067c2027806127a5adef42616c0c077c5","impliedFormat":99},{"version":"c4e1f7299f647938767a7f77d62ddf5b0bc76b6139a22d06aa3b1dad1e795683","impliedFormat":99},{"version":"7dd8e0b7c78a86030bf84740cd98e6764d1bffac8a5c5628d05579640e854ac1","impliedFormat":99},{"version":"0afba95f2c5c01a50c0fb998b05b77299f0b906b0832029863f59e7a04659054","impliedFormat":99},{"version":"2014c08f9f2d16a4a0bc062b8733d070c9a2e744f1d8435b57594211cbac83c0","impliedFormat":99},{"version":"ebc259c43de348b37de65877bd35fab6f0fe5e5aaac85d302ed8ecf7e3d15e43","impliedFormat":99},{"version":"0ca864ae68db0b71faab7dc4d8e2893769079848cd32e3c5d75de1c3f43a0ce9","impliedFormat":99},{"version":"1627f6024425c8bb086803773b2bf72db8f5f7dd6ce921bb3ed9e6d07eece734","impliedFormat":99},{"version":"bf2387a86e91dba26dd3650f8b8907d05ce4b695a1a0fba0decf289efe06b3a5","impliedFormat":99},{"version":"2937731113c2deca6d06d5acbe5a675494e23294a7e3a948de2fa698b2d876fd","impliedFormat":99},{"version":"c35f64730d5ddb935dba2b79506f5c8a851b2c40646637c7070a4033972bd73a","impliedFormat":99},{"version":"4017cfb925dd1318b932861fe1789154f6063bbbf4608bf47d2acc07e3887625","impliedFormat":99},{"version":"12a3f116761929a14d261c60b2adba26c75649e115453e52212ad7cd8dd3b79f","impliedFormat":99},{"version":"a595a4d43efb257103e1a0bfc60c1178449afec9336777c5eba86dbe47ceaae8","impliedFormat":99},{"version":"a42e3e4d50ad755335b10256c66629cfba3d2acef663571db023fcb50091cd70","impliedFormat":99},{"version":"29488db8cc9b41928088c0a874a9740bee7c05b3aee6e02d8b1136aacbb3ea57","impliedFormat":99},{"version":"6cd08be16945e4736f0a78a63aa18945da3860afb9a49fe511f4d4cf47cc382f","impliedFormat":99},{"version":"d4f839a83660b5c14f6e439de84f67e00f309503ed3f2688db7c4ad515e00af4","impliedFormat":99},{"version":"4d626b51f8090e44a1ded8269e8b5d2e6e760192a56beaa2a179013b4988fe76","impliedFormat":99},{"version":"2c59a339b26e24cabf568f58c21d9c529faa13f27ebf5dde94b7e42d1fe0bfd9","impliedFormat":99},{"version":"d462c76b11f2102ae2819a4ffb2b07fd39a23292edc4661884f38d554a75a82c","impliedFormat":99},{"version":"cd370b8e9f5056daed56e9a5eeb3275d37b88d88a27328df8498e8f09faacf49","impliedFormat":99},{"version":"04f0e5540074077b5194e4e50f045b07ea1c0d4ba639f2a90c25d415be93d62a","impliedFormat":99},{"version":"2fb63e3c2d0ab26193d6fa0b349c34766590b497b5cced0e648087f2680e7a68","impliedFormat":99},{"version":"344a2f16476283746885b94c4574e240d29e875a6e6e1fc7589da40995cdee9a","impliedFormat":99},{"version":"f7f7423d696f03891679be9d3d58655c90e7560e537eb35910803ed0f2d5245d","impliedFormat":99},{"version":"70390bf77fcfcc04217e58ddc1dd09e5b0fa32de01c12de6f981a7be0a3ae2e0","impliedFormat":99},{"version":"c2a3209fd29ed0b0daa24d258b108f7b4e4ba2656a99e529ceedd4a044b2edb8","impliedFormat":99},{"version":"a0bd6bccba91b399e4e98bb50ef2064f2dd1e5566151911526368667fb27f151","impliedFormat":99},{"version":"409cf8770fbb9f099124e9ca744282ebfd85df2fd3650ae05c4ee3d03af66714","affectsGlobalScope":true,"impliedFormat":1},{"version":"dfed26d7594c4be1318d1aba3c948b1ce6d701eda65bfe609b58f6577cb9223c","impliedFormat":99},{"version":"3896464bb7e25fceebbd9c8a0b443caaa9b68ec323f46191c36b84293c852a19","impliedFormat":1},{"version":"3d3446794a94c3cbe4ef9dd849fd1cbf246acc9f682d9a88aa8a4e75b7fa7e17","impliedFormat":99},{"version":"31265406885c245879008bf774ab1e0c979ba8f061e58bf7a50c411753b9928b","impliedFormat":99},{"version":"c9ea82231d04828f1ff72010ca388b542f60265e383a64a767d4809c2b59b8ad","impliedFormat":99},{"version":"d8e93b1d8c5fc5d6da317fc34691c18310ac761ce02e0196dbf615b3410b680e","impliedFormat":99},{"version":"409b21f3d0c198cc4866b941cd9303809a13230e2b9b3c1508fe61348a8b43ed","impliedFormat":1},{"version":"3078727fed04c123165efdb42deeac5dceaa42ac62216ca13cb809dc7e13415f","impliedFormat":1},{"version":"cc957354aa3c94c9961ebf46282cfde1e81d107fc5785a61f62c67f1dd3ac2eb","impliedFormat":1},{"version":"b4f76b34637d79cefad486127115fed843762c69512d7101b7096e1293699679","impliedFormat":1},{"version":"93de1c6dab503f053efe8d304cb522bb3a89feab8c98f307a674a4fae04773e9","impliedFormat":1},{"version":"dae3d1adc67ac3dbd1cd471889301339ec439837b5df565982345be20c8fca9a","impliedFormat":1},{"version":"b6ddf3a46ccfa4441d8be84d2e9bf3087573c48804196faedbd4a25b60631beb","impliedFormat":1},{"version":"7e771891adaa85b690266bc37bd6eb43bc57eecc4b54693ead36467e7369952a","impliedFormat":1},{"version":"a69c09dbea52352f479d3e7ac949fde3d17b195abe90b045d619f747b38d6d1a","impliedFormat":1},{"version":"54ba7456adb777a685250cd144115ea51379784012ba1311255b715c6bdcff2a","affectsGlobalScope":true,"impliedFormat":1},{"version":"11e2d554398d2bd460e7d06b2fa5827a297c8acfbe00b4f894a224ac0862857f","impliedFormat":1},{"version":"e193e634a99c9c1d71f1c6e4e1567a4a73584328d21ea02dd5cddbaad6693f61","affectsGlobalScope":true,"impliedFormat":1},{"version":"374ca798f244e464346f14301dc2a8b4b111af1a83b49fffef5906c338a1f922","impliedFormat":1},{"version":"5a94487653355b56018122d92392beb2e5f4a6c63ba5cef83bbe1c99775ef713","impliedFormat":1},{"version":"d5135ad93b33adcce80b18f8065087934cdc1730d63db58562edcf017e1aad9b","affectsGlobalScope":true,"impliedFormat":1},{"version":"82408ed3e959ddc60d3e9904481b5a8dc16469928257af22a3f7d1a3bc7fd8c4","impliedFormat":1},{"version":"e596c9bb2f29a2699fdd4ae89139612652245192f67f45617c5a4b20832aaae9","impliedFormat":1},{"version":"bb9c4ffa5e6290c6980b63c815cdd1625876dadb2efaf77edbe82984be93e55e","impliedFormat":1},{"version":"489532ff54b714f0e0939947a1c560e516d3ae93d51d639ab02e907a0e950114","impliedFormat":1},{"version":"216717f17c095cde1dc19375e1ab3af0a4a485355860c077a4f9d6ea59fab5b5","impliedFormat":1},{"version":"14b5aa23c5d0ae1907bc696ac7b6915d88f7d85799cc0dc2dcf98fbce2c5a67c","impliedFormat":1},{"version":"5c439dafdc09abe4d6c260a96b822fa0ba5be7203c71a63ab1f1423cd9e838ea","impliedFormat":1},{"version":"6b526a5ec4a401ca7c26cfe6a48e641d8f30af76673bad3b06a1b4504594a960","affectsGlobalScope":true,"impliedFormat":1},{"version":"816ad2e607a96de5bcac7d437f843f5afd8957f1fa5eefa6bba8e4ed7ca8fd84","affectsGlobalScope":true,"impliedFormat":1},{"version":"80473bd0dd90ca1e166514c2dfead9d5803f9c51418864ca35abbeec6e6847e1","impliedFormat":1},{"version":"1c84b46267610a34028edfd0d035509341751262bac1062857f3c8df7aff7153","impliedFormat":1},{"version":"e6c86d83bd526c8bdb5d0bf935b8e72ce983763d600743f74d812fdf4abf4df6","impliedFormat":1},{"version":"04eb6578a588d6a46f50299b55f30e3a04ef27d0c5a46c57d8fcc211cd530faa","impliedFormat":1},{"version":"8d3c583a07e0c37e876908c2d5da575019f689df8d9fa4c081d99119d53dba22","impliedFormat":1},{"version":"2c828a5405191d006115ab34e191b8474bc6c86ffdc401d1a9864b1b6e088a58","impliedFormat":1},{"version":"e630e5528e899219ae319e83bef54bf3bcb91b01d76861ecf881e8e614b167f0","affectsGlobalScope":true,"impliedFormat":1},{"version":"bcebb922784739bdb34c18ee51095d25a92b560c78ccd2eaacd6bd00f7443d83","impliedFormat":1},{"version":"7ee6ed878c4528215c82b664fe0cfe80e8b4da6c0d4cc80869367868774db8b1","impliedFormat":1},{"version":"b0973c3cbcdc59b37bf477731d468696ecaf442593ec51bab497a613a580fe30","impliedFormat":1},{"version":"4989e92ba5b69b182d2caaea6295af52b7dc73a4f7a2e336a676722884e7139d","affectsGlobalScope":true,"impliedFormat":1},{"version":"0715e4cd28ad471b2a93f3e552ff51a3ae423417a01a10aa1d3bc7c6b95059d6","affectsGlobalScope":true,"impliedFormat":1},{"version":"5153a2fd150e46ce57bb3f8db1318d33f6ad3261ed70ceeff92281c0608c74a3","impliedFormat":1},{"version":"210d54cd652ec0fec8c8916e4af59bb341065576ecda039842f9ffb2e908507c","impliedFormat":1},{"version":"36b03690b628eab08703d63f04eaa89c5df202e5f1edf3989f13ad389cd2c091","impliedFormat":1},{"version":"0effadd232a20498b11308058e334d3339cc5bf8c4c858393e38d9d4c0013dcf","impliedFormat":1},{"version":"25846d43937c672bab7e8195f3d881f93495df712ee901860effc109918938cc","impliedFormat":1},{"version":"7d55d78cd47cf5280643b53434b16c2d9d11d144126932759fbdd51da525eec4","impliedFormat":1},{"version":"1b952304137851e45bc009785de89ada562d9376177c97e37702e39e60c2f1ff","impliedFormat":1},{"version":"69ee23dd0d215b09907ad30d23f88b7790c93329d1faf31d7835552a10cf7cbf","impliedFormat":1},{"version":"44b8b584a338b190a59f4f6929d072431950c7bd92ec2694821c11bce180c8a5","impliedFormat":1},{"version":"23b89798789dffbd437c0c423f5d02d11f9736aea73d6abf16db4f812ff36eda","impliedFormat":1},{"version":"f69ff39996a61a0dd10f4bce73272b52e8024a4d58b13ab32bf4712909d0a2b7","impliedFormat":1},{"version":"3c4ba1dd9b12ffa284b565063108f2f031d150ea15b8fafbdc17f5d2a07251f3","affectsGlobalScope":true,"impliedFormat":1},{"version":"e10177274a35a9d07c825615340b2fcde2f610f53f3fb40269fd196b4288dda6","impliedFormat":1},{"version":"c4577fb855ca259bdbf3ea663ca73988ce5f84251a92b4aef80a1f4122b6f98e","impliedFormat":1},{"version":"3c13ef48634e7b5012fcf7e8fce7496352c2d779a7201389ca96a2a81ee4314d","impliedFormat":1},{"version":"5d0a25ec910fa36595f85a67ac992d7a53dd4064a1ba6aea1c9f14ab73a023f2","impliedFormat":1},{"version":"f0900cd5d00fe1263ff41201fb8073dbeb984397e4af3b8002a5c207a30bdc33","affectsGlobalScope":true,"impliedFormat":1},{"version":"ff07a9a03c65732ccc59b3c65bc584173da093bd563a6565411c01f5703bd3cb","affectsGlobalScope":true,"impliedFormat":1},{"version":"6de4a219df57d2b27274d59b67708f13c2cbf7ed211abe57d8f9ab8b25cde776","impliedFormat":1},{"version":"a5edeccc71da079d52df5b6492f577d0131c102fc6296632a04f3dd07247911b","impliedFormat":1},{"version":"e59a892d87e72733e2a9ca21611b9beb52977be2696c7ba4b216cbbb9a48f5aa","impliedFormat":1},{"version":"da26af7362f53d122283bc69fed862b9a9fe27e01bc6a69d1d682e0e5a4df3e6","affectsGlobalScope":true,"impliedFormat":1},{"version":"8a300fa9b698845a1f9c41ecbe2c5966634582a8e2020d51abcace9b55aa959e","impliedFormat":1},{"version":"ab9b9a36e5284fd8d3bf2f7d5fcbc60052f25f27e4d20954782099282c60d23e","affectsGlobalScope":true,"impliedFormat":1},{"version":"d8d555f3d607ecaa18d55de6995ea8f206342ecc93305919eac945c7c78c78c6","impliedFormat":1},{"version":"bf88ef4208a770ca39a844b182b3695df536326ea566893fdc5b8418702a331e","impliedFormat":1},{"version":"8b06ac3faeacb8484d84ddb44571d8f410697f98d7bfa86c0fda60373a9f5215","impliedFormat":1},{"version":"7eb06594824ada538b1d8b48c3925a83e7db792f47a081a62cf3e5c4e23cf0ee","impliedFormat":1},{"version":"f5638f7c2f12a9a1a57b5c41b3c1ea7db3876c003bab68e6a57afd6bcc169af0","impliedFormat":1},{"version":"6c1e688f95fcaf53b1e41c0fdadf2c1cfc96fa924eaf7f9fdb60f96deb0a4986","impliedFormat":1},{"version":"0d14fa22c41fdc7277e6f71473b20ebc07f40f00e38875142335d5b63cdfc9d2","impliedFormat":1},{"version":"db25694be959314fd1e868d72e567746db1db9e2001fae545d12d2a8c1bba1b8","impliedFormat":1},{"version":"43883cf3635bb1846cbdc6c363787b76227677388c74f7313e3f0edb380840fa","impliedFormat":1},{"version":"2d47012580f859dae201d2eef898a416bdae719dffc087dfd06aefe3de2f9c8d","impliedFormat":1},{"version":"3e70a7e67c2cb16f8cd49097360c0309fe9d1e3210ff9222e9dac1f8df9d4fb6","impliedFormat":1},{"version":"ab68d2a3e3e8767c3fba8f80de099a1cfc18c0de79e42cb02ae66e22dfe14a66","impliedFormat":1},{"version":"2cec1a31729b9b01e9294c33fc9425d336eff067282809761ad2e74425d6d2a5","impliedFormat":1},{"version":"2d47012580f859dae201d2eef898a416bdae719dffc087dfd06aefe3de2f9c8d","impliedFormat":1},{"version":"458e2fd1185e659cb800ef68d01ef77de70dcab8860bedf6d94eaebe736751f1","affectsGlobalScope":true,"impliedFormat":1},{"version":"f3e604694b624fa3f83f6684185452992088f5efb2cf136b62474aa106d6f1b6","impliedFormat":1},{"version":"2c425702763ca7d738b2f0080be64d366a0818106a73c2595ed3ea51967f18c8","impliedFormat":1},{"version":"bc88e4049153bc4dddb4503ed7e624eb141edfa9064b3659d6c86e900fe9e621","impliedFormat":1},{"version":"2b93035328f7778d200252681c1d86285d501ed424825a18f81e4c3028aa51d9","impliedFormat":1},{"version":"2ac9c8332c5f8510b8bdd571f8271e0f39b0577714d5e95c1e79a12b2616f069","impliedFormat":1},{"version":"42c21aa963e7b86fa00801d96e88b36803188018d5ad91db2a9101bccd40b3ff","impliedFormat":1},{"version":"d31eb848cdebb4c55b4893b335a7c0cca95ad66dee13cbb7d0893810c0a9c301","impliedFormat":1},{"version":"77c1d91a129ba60b8c405f9f539e42df834afb174fe0785f89d92a2c7c16b77a","impliedFormat":1},{"version":"7a9e0a564fee396cacf706523b5aeed96e04c6b871a8bebefad78499fbffc5bc","impliedFormat":1},{"version":"906c751ef5822ec0dadcea2f0e9db64a33fb4ee926cc9f7efa38afe5d5371b2a","impliedFormat":1},{"version":"5387c049e9702f2d2d7ece1a74836a14b47fbebe9bbeb19f94c580a37c855351","impliedFormat":1},{"version":"c68391fb9efad5d99ff332c65b1606248c4e4a9f1dd9a087204242b56c7126d6","impliedFormat":1},{"version":"e9cf02252d3a0ced987d24845dcb1f11c1be5541f17e5daa44c6de2d18138d0c","impliedFormat":1},{"version":"e8b02b879754d85f48489294f99147aeccc352c760d95a6fe2b6e49cd400b2fe","impliedFormat":1},{"version":"9f6908ab3d8a86c68b86e38578afc7095114e66b2fc36a2a96e9252aac3998e0","impliedFormat":1},{"version":"0eedb2344442b143ddcd788f87096961cd8572b64f10b4afc3356aa0460171c6","impliedFormat":1},{"version":"71405cc70f183d029cc5018375f6c35117ffdaf11846c35ebf85ee3956b1b2a6","impliedFormat":1},{"version":"c68baff4d8ba346130e9753cefe2e487a16731bf17e05fdacc81e8c9a26aae9d","impliedFormat":1},{"version":"2cd15528d8bb5d0453aa339b4b52e0696e8b07e790c153831c642c3dea5ac8af","impliedFormat":1},{"version":"479d622e66283ffa9883fbc33e441f7fc928b2277ff30aacbec7b7761b4e9579","impliedFormat":1},{"version":"ade307876dc5ca267ca308d09e737b611505e015c535863f22420a11fffc1c54","impliedFormat":1},{"version":"f8cdefa3e0dee639eccbe9794b46f90291e5fd3989fcba60d2f08fde56179fb9","impliedFormat":1},{"version":"86c5a62f99aac7053976e317dbe9acb2eaf903aaf3d2e5bb1cafe5c2df7b37a8","impliedFormat":1},{"version":"2b300954ce01a8343866f737656e13243e86e5baef51bd0631b21dcef1f6e954","impliedFormat":1},{"version":"a2d409a9ffd872d6b9d78ead00baa116bbc73cfa959fce9a2f29d3227876b2a1","impliedFormat":1},{"version":"b288936f560cd71f4a6002953290de9ff8dfbfbf37f5a9391be5c83322324898","impliedFormat":1},{"version":"61178a781ef82e0ff54f9430397e71e8f365fc1e3725e0e5346f2de7b0d50dfa","impliedFormat":1},{"version":"6a6ccb37feb3aad32d9be026a3337db195979cd5727a616fc0f557e974101a54","impliedFormat":1},{"version":"c649ea79205c029a02272ef55b7ab14ada0903db26144d2205021f24727ac7a3","impliedFormat":1},{"version":"38e2b02897c6357bbcff729ef84c736727b45cc152abe95a7567caccdfad2a1d","impliedFormat":1},{"version":"d6610ea7e0b1a7686dba062a1e5544dd7d34140f4545305b7c6afaebfb348341","impliedFormat":1},{"version":"3dee35db743bdba2c8d19aece7ac049bde6fa587e195d86547c882784e6ba34c","impliedFormat":1},{"version":"b15e55c5fa977c2f25ca0b1db52cfa2d1fd4bf0baf90a8b90d4a7678ca462ff1","impliedFormat":1},{"version":"f41d30972724714763a2698ae949fbc463afb203b5fa7c4ad7e4de0871129a17","impliedFormat":1},{"version":"843dd7b6a7c6269fd43827303f5cbe65c1fecabc30b4670a50d5a15d57daeeb9","impliedFormat":1},{"version":"f06d8b8567ee9fd799bf7f806efe93b67683ef24f4dea5b23ef12edff4434d9d","impliedFormat":1},{"version":"6017384f697ff38bc3ef6a546df5b230c3c31329db84cbfe686c83bec011e2b2","impliedFormat":1},{"version":"e1a5b30d9248549ca0c0bb1d653bafae20c64c4aa5928cc4cd3017b55c2177b0","impliedFormat":1},{"version":"a593632d5878f17295bd53e1c77f27bf4c15212822f764a2bfc1702f4b413fa0","impliedFormat":1},{"version":"a868a534ba1c2ca9060b8a13b0ffbbbf78b4be7b0ff80d8c75b02773f7192c29","impliedFormat":1},{"version":"da7545aba8f54a50fde23e2ede00158dc8112560d934cee58098dfb03aae9b9d","impliedFormat":1},{"version":"34baf65cfee92f110d6653322e2120c2d368ee64b3c7981dff08ed105c4f19b0","impliedFormat":1},{"version":"6aee496bf0ecfbf6731aa8cca32f4b6e92cdc0a444911a7d88410408a45ecc5d","impliedFormat":1},{"version":"b0d10e46cfe3f6c476b69af02eaa38e4ccc7430221ce3109ae84bb9fb8282298","impliedFormat":1},{"version":"70e9a18da08294f75bf23e46c7d69e67634c0765d355887b9b41f0d959e1426e","impliedFormat":1},{"version":"c5e0d2f7a9fdad8a7a3b5de384f932badf64d72c22bdd715aa858748da3f7cda","impliedFormat":1}],"options":{"allowSyntheticDefaultImports":true,"composite":true,"declaration":true,"declarationMap":true,"downlevelIteration":true,"esModuleInterop":true,"importHelpers":true,"inlineSourceMap":true,"module":199,"noUnusedLocals":true,"outDir":"./dest","rootDir":"./src","strict":true,"target":7,"tsBuildInfoFile":"./.tsbuildinfo"},"fileIdsList":[[161],[56,161],[56,104,161],[56,103,124,161],[56,61,62,161],[56,60,61,62,63,161],[56,60,161],[56,57,58,59,64,66,69,73,74,75,79,100,102,105,106,161],[56,101,161],[56,70,71,72,161],[56,71,161],[56,65,161],[56,69,74,161],[56,76,161],[56,58,161],[56,76,77,78,161],[56,76,79,161],[56,59,161],[56,67,68,161],[56,90,91,92,93,161],[56,82,161],[56,83,89,161],[56,87,89,131,161],[56,80,84,85,131,161],[56,80,81,82,83,84,85,86,87,88,94,99,161],[56,82,131,161],[56,96,98,161],[56,83,95,161,165],[56,82,161,165],[56,87,97,131,161,165],[56,73,81,82,83,131,161],[56,81,82,85,87,161],[109,161],[161,175],[109,110,111,112,113,161],[109,111,161],[132,161,168],[161,170],[161,171],[161,177,180],[161,176],[108,161,168],[115,161],[118,161],[119,124,152,161],[120,131,132,139,149,160,161],[120,121,131,139,161],[122,161],[123,124,132,140,161],[124,149,157,161],[125,127,131,139,161],[126,161],[127,128,161],[131,161],[129,131,161],[131,132,133,149,160,161],[131,132,133,146,149,152,161],[161,165],[127,134,139,149,160,161],[131,132,134,135,139,149,157,160,161],[134,136,149,157,160,161],[115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167],[131,137,161],[138,160,161],[127,131,139,149,161],[140,161],[141,161],[118,142,161],[143,159,161,165],[144,161],[145,161],[131,146,147,161],[146,148,161,163],[119,131,149,150,151,152,161],[119,149,151,161],[149,150,161],[152,161],[153,161],[131,155,156,161],[155,156,161],[124,139,149,157,161],[158,161],[139,159,161],[119,134,145,160,161],[124,161],[149,161,162],[161,163],[161,164],[119,124,131,133,142,149,160,161,163,165],[149,161,166],[161,186,225],[161,186,210,225],[161,225],[161,186],[161,186,211,225],[161,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224],[161,211,225],[161,227],[161,173,179],[161,174,178],[161,177]],"referencedMap":[[11,1],[13,1],[12,1],[2,1],[14,1],[15,1],[16,1],[17,1],[18,1],[19,1],[20,1],[21,1],[3,1],[4,1],[25,1],[22,1],[23,1],[24,1],[26,1],[27,1],[28,1],[5,1],[29,1],[30,1],[31,1],[32,1],[6,1],[36,1],[33,1],[34,1],[35,1],[37,1],[7,1],[38,1],[43,1],[44,1],[39,1],[40,1],[41,1],[42,1],[8,1],[48,1],[45,1],[46,1],[47,1],[49,1],[9,1],[50,1],[51,1],[52,1],[53,1],[54,1],[1,1],[10,1],[55,1],[57,2],[58,2],[105,3],[104,4],[59,2],[63,5],[64,6],[60,2],[62,7],[61,7],[107,8],[102,9],[70,2],[71,2],[73,10],[72,11],[66,12],[65,2],[75,13],[106,2],[77,14],[76,15],[79,16],[78,17],[74,18],[69,19],[67,2],[68,2],[94,20],[89,21],[92,22],[93,23],[90,22],[91,23],[80,2],[86,24],[81,2],[100,25],[83,21],[87,26],[82,2],[85,2],[99,27],[96,28],[95,29],[98,30],[97,29],[84,31],[88,32],[111,33],[109,1],[173,1],[176,34],[175,1],[108,1],[114,35],[110,33],[112,36],[113,33],[103,1],[169,37],[170,1],[171,38],[172,39],[182,40],[181,41],[183,1],[184,42],[115,43],[116,43],[118,44],[119,45],[120,46],[121,47],[122,48],[123,49],[124,50],[125,51],[126,52],[127,53],[128,53],[130,54],[129,55],[131,54],[132,56],[133,57],[117,58],[167,1],[134,59],[135,60],[136,61],[168,62],[137,63],[138,64],[139,65],[140,66],[141,67],[142,68],[143,69],[144,70],[145,71],[146,72],[147,72],[148,73],[149,74],[151,75],[150,76],[152,77],[153,78],[154,1],[155,79],[156,80],[157,81],[158,82],[159,83],[160,84],[161,85],[162,86],[163,87],[164,88],[165,89],[166,90],[185,1],[210,91],[211,92],[186,93],[189,93],[208,91],[209,91],[199,91],[198,94],[196,91],[191,91],[204,91],[202,91],[206,91],[190,91],[203,91],[207,91],[192,91],[193,91],[205,91],[187,91],[194,91],[195,91],[197,91],[201,91],[212,95],[200,91],[188,91],[225,96],[224,1],[219,95],[221,97],[220,95],[213,95],[214,95],[216,95],[218,95],[222,97],[223,97],[215,97],[217,97],[226,1],[227,1],[228,98],[174,1],[101,1],[180,99],[179,100],[178,101],[177,41],[56,1]],"exportedModulesMap":[[11,1],[13,1],[12,1],[2,1],[14,1],[15,1],[16,1],[17,1],[18,1],[19,1],[20,1],[21,1],[3,1],[4,1],[25,1],[22,1],[23,1],[24,1],[26,1],[27,1],[28,1],[5,1],[29,1],[30,1],[31,1],[32,1],[6,1],[36,1],[33,1],[34,1],[35,1],[37,1],[7,1],[38,1],[43,1],[44,1],[39,1],[40,1],[41,1],[42,1],[8,1],[48,1],[45,1],[46,1],[47,1],[49,1],[9,1],[50,1],[51,1],[52,1],[53,1],[54,1],[1,1],[10,1],[55,1],[57,2],[58,2],[105,3],[104,4],[59,2],[63,5],[64,6],[60,2],[62,7],[61,7],[107,8],[102,9],[70,2],[71,2],[73,10],[72,11],[66,12],[65,2],[75,13],[106,2],[77,14],[76,15],[79,16],[78,17],[74,18],[69,19],[67,2],[68,2],[94,20],[89,21],[92,22],[93,23],[90,22],[91,23],[80,2],[86,24],[81,2],[100,25],[83,21],[87,26],[82,2],[85,2],[99,27],[96,28],[95,29],[98,30],[97,29],[84,31],[88,32],[111,33],[109,1],[173,1],[176,34],[175,1],[108,1],[114,35],[110,33],[112,36],[113,33],[103,1],[169,37],[170,1],[171,38],[172,39],[182,40],[181,41],[183,1],[184,42],[115,43],[116,43],[118,44],[119,45],[120,46],[121,47],[122,48],[123,49],[124,50],[125,51],[126,52],[127,53],[128,53],[130,54],[129,55],[131,54],[132,56],[133,57],[117,58],[167,1],[134,59],[135,60],[136,61],[168,62],[137,63],[138,64],[139,65],[140,66],[141,67],[142,68],[143,69],[144,70],[145,71],[146,72],[147,72],[148,73],[149,74],[151,75],[150,76],[152,77],[153,78],[154,1],[155,79],[156,80],[157,81],[158,82],[159,83],[160,84],[161,85],[162,86],[163,87],[164,88],[165,89],[166,90],[185,1],[210,91],[211,92],[186,93],[189,93],[208,91],[209,91],[199,91],[198,94],[196,91],[191,91],[204,91],[202,91],[206,91],[190,91],[203,91],[207,91],[192,91],[193,91],[205,91],[187,91],[194,91],[195,91],[197,91],[201,91],[212,95],[200,91],[188,91],[225,96],[224,1],[219,95],[221,97],[220,95],[213,95],[214,95],[216,95],[218,95],[222,97],[223,97],[215,97],[217,97],[226,1],[227,1],[228,98],[174,1],[101,1],[180,99],[179,100],[178,101],[177,41],[56,1]],"semanticDiagnosticsPerFile":[11,13,12,2,14,15,16,17,18,19,20,21,3,4,25,22,23,24,26,27,28,5,29,30,31,32,6,36,33,34,35,37,7,38,43,44,39,40,41,42,8,48,45,46,47,49,9,50,51,52,53,54,1,10,55,57,58,105,104,59,63,64,60,62,61,107,102,70,[71,[{"file":"./src/log/debug.ts","start":18,"length":7,"code":7016,"category":1,"messageText":{"messageText":"Could not find a declaration file for module 'debug'. '/Users/adomurad/sources/aztec3-packages/circuits/node_modules/debug/src/index.js' implicitly has an 'any' type.","category":1,"code":7016,"next":[{"messageText":"Try `npm i --save-dev @types/debug` if it exists or add a new declaration (.d.ts) file containing `declare module 'debug';`","category":1,"code":7035}]}}]],73,72,66,65,75,106,77,76,79,78,74,69,67,68,94,89,92,93,90,91,80,86,81,100,83,87,82,85,99,96,95,98,97,84,88,111,109,173,176,175,108,114,110,112,113,103,169,170,171,172,182,181,183,184,115,116,118,119,120,121,122,123,124,125,126,127,128,130,129,131,132,133,117,167,134,135,136,168,137,138,139,140,141,142,143,144,145,146,147,148,149,151,150,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,185,210,211,186,189,208,209,199,198,196,191,204,202,206,190,203,207,192,193,205,187,194,195,197,201,212,200,188,225,224,219,221,220,213,214,216,218,222,223,215,217,226,227,228,174,101,180,179,178,177,56],"affectedFilesPendingEmit":[[2,1],[3,1],[4,1],[5,1],[6,1],[7,1],[8,1],[9,1],[10,1],[57,1],[58,1],[105,1],[104,1],[59,1],[63,1],[64,1],[60,1],[62,1],[61,1],[107,1],[102,1],[70,1],[71,1],[73,1],[72,1],[66,1],[65,1],[75,1],[106,1],[77,1],[76,1],[79,1],[78,1],[74,1],[69,1],[67,1],[68,1],[94,1],[89,1],[92,1],[93,1],[90,1],[91,1],[80,1],[86,1],[81,1],[100,1],[83,1],[87,1],[82,1],[85,1],[99,1],[96,1],[95,1],[98,1],[97,1],[84,1],[88,1],[111,1],[109,1],[173,1],[176,1],[175,1],[108,1],[114,1],[110,1],[112,1],[113,1],[103,1],[169,1],[170,1],[171,1],[172,1],[182,1],[181,1],[183,1],[184,1],[115,1],[116,1],[118,1],[119,1],[120,1],[121,1],[122,1],[123,1],[124,1],[125,1],[126,1],[127,1],[128,1],[130,1],[129,1],[131,1],[132,1],[133,1],[117,1],[167,1],[134,1],[135,1],[136,1],[168,1],[137,1],[138,1],[139,1],[140,1],[141,1],[142,1],[143,1],[144,1],[145,1],[146,1],[147,1],[148,1],[149,1],[151,1],[150,1],[152,1],[153,1],[154,1],[155,1],[156,1],[157,1],[158,1],[159,1],[160,1],[161,1],[162,1],[163,1],[164,1],[165,1],[166,1],[185,1],[210,1],[211,1],[186,1],[189,1],[208,1],[209,1],[199,1],[198,1],[196,1],[191,1],[204,1],[202,1],[206,1],[190,1],[203,1],[207,1],[192,1],[193,1],[205,1],[187,1],[194,1],[195,1],[197,1],[201,1],[212,1],[200,1],[188,1],[225,1],[224,1],[219,1],[221,1],[220,1],[213,1],[214,1],[216,1],[218,1],[222,1],[223,1],[215,1],[217,1],[226,1],[227,1],[228,1],[174,1],[101,1],[180,1],[179,1],[178,1],[177,1],[56,1]],"emitSignatures":[57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,102,104,105,106,107]},"version":"4.9.5"} \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/.vscode/extensions.json b/circuits/.yalc/@aztec/foundation/.vscode/extensions.json new file mode 100644 index 00000000000..86def6c6947 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/.vscode/extensions.json @@ -0,0 +1,8 @@ +{ + "recommendations": [ + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode", + "eamodio.gitlens", + "ms-vsliveshare.vsliveshare" + ] +} diff --git a/circuits/.yalc/@aztec/foundation/.vscode/launch.json b/circuits/.yalc/@aztec/foundation/.vscode/launch.json new file mode 100644 index 00000000000..9ce9e4e0f3f --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/.vscode/launch.json @@ -0,0 +1,18 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "address": "${config:mainframeAddress}", + "port": 9221, + "type": "node", + "request": "attach", + "name": "Attach to Remote", + "skipFiles": ["/**"], + "localRoot": "${workspaceFolder}", + "sourceMaps": true + } + ] +} \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/.vscode/settings.json b/circuits/.yalc/@aztec/foundation/.vscode/settings.json new file mode 100644 index 00000000000..adebee2c48a --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/.vscode/settings.json @@ -0,0 +1,11 @@ +{ + "search.exclude": { + ".pnp.*": true + }, + "[typescript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[javascript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + } +} diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/Dockerfile b/circuits/.yalc/@aztec/foundation/Dockerfile similarity index 55% rename from circuits/ts/.yalc/@aztec/wasm-worker/Dockerfile rename to circuits/.yalc/@aztec/foundation/Dockerfile index ebffe4d970b..a7b01d7666c 100644 --- a/circuits/ts/.yalc/@aztec/wasm-worker/Dockerfile +++ b/circuits/.yalc/@aztec/foundation/Dockerfile @@ -1,14 +1,14 @@ FROM 278380418400.dkr.ecr.eu-west-2.amazonaws.com/yarn-project-base AS builder -COPY wasm-worker wasm-worker -WORKDIR /usr/src/yarn-project/wasm-worker +COPY foundation foundation +WORKDIR /usr/src/yarn-project/foundation 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 alpine:latest -COPY --from=builder /usr/src/yarn-project/wasm-worker /usr/src/yarn-project/wasm-worker -WORKDIR /usr/src/yarn-project/wasm-worker +FROM node:18-alpine +COPY --from=builder /usr/src/yarn-project/foundation /usr/src/yarn-project/foundation +WORKDIR /usr/src/yarn-project/foundation ENTRYPOINT ["yarn"] \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/LICENSE b/circuits/.yalc/@aztec/foundation/LICENSE new file mode 100644 index 00000000000..261eeb9e9f8 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/circuits/.yalc/@aztec/foundation/PROJECT b/circuits/.yalc/@aztec/foundation/PROJECT new file mode 100644 index 00000000000..dfb88c57bad --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/PROJECT @@ -0,0 +1 @@ +foundation \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/README.md b/circuits/.yalc/@aztec/foundation/README.md new file mode 100644 index 00000000000..474e02c308b --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/README.md @@ -0,0 +1,17 @@ +This repository contains general-purpose packages that can be used in other packages. + +# Async Map + +Much the same as Array.map, only it takes an async fn as an element handler, and ensures that each element handler is executed sequentially. The pattern of `await Promise.all(arr.map(async e => { ... }))` only works if one's happy with each element handler being run concurrently. If one required sequential execution of async fn's, the only alternative was regular loops with mutable state vars. The equivalent with asyncMap: `await asyncMap(arr, async e => { ... })`. + +# Mutex + +Receives a MutexDatabase and allows for locking it and unlocking it on demand. The DB will remain locked by recursively extending its lock (pinging). + +MutexDatabase's interface is comprehended of three methods: `acquireLock`, `extendLock` and `releaseLock`. + +`acquireLock` is called when attempting to lock. If it returns truthy, the db will lock and ping until `unlock` is called. If it returns falsy, `untilAcquired` will take precedence in deciding whether the db will retry to lock or not. In case `untilAcquired` is true, the db will try to relock every `tryLockInterval`. +`extendLock` is called whenever `pingInterval` is fulfilled and the db hasn't been unlocked. +`releaseLock` is called when the db is unlocked. + +TODO: -- Write how to use it! diff --git a/circuits/.yalc/@aztec/foundation/VERSION b/circuits/.yalc/@aztec/foundation/VERSION new file mode 100644 index 00000000000..6b3126cee74 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/VERSION @@ -0,0 +1 @@ +v1.0 diff --git a/circuits/.yalc/@aztec/foundation/bootstrap.sh b/circuits/.yalc/@aztec/foundation/bootstrap.sh new file mode 100755 index 00000000000..1fbba416287 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/bootstrap.sh @@ -0,0 +1,38 @@ +#!/bin/bash +set -e + +export CLEAN=$1 + +# Remove all untracked files and directories. +if [ -n "$CLEAN" ]; then + if [ "$CLEAN" = "clean" ]; then + echo "WARNING: This will erase *all* untracked files, including hooks and submodules." + echo -n "Continue? [y/n] " + read user_input + if [ "$user_input" != "y" ] && [ "$user_input" != "Y" ]; then + exit 1 + fi + rm -rf .git/hooks/* + git clean -fd + exit 0 + else + echo "Unknown command: $CLEAN" + exit 1 + fi +fi + +if [ ! -f ~/.nvm/nvm.sh ]; then + echo "Nvm not found at ~/.nvm" + exit 1 +fi + +\. ~/.nvm/nvm.sh +nvm install + +git submodule update --init --recursive + +yarn install --immutable +yarn build + +echo +echo "Success!" diff --git a/circuits/.yalc/@aztec/foundation/build_manifest.json b/circuits/.yalc/@aztec/foundation/build_manifest.json new file mode 100644 index 00000000000..04932d53d5d --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/build_manifest.json @@ -0,0 +1,7 @@ +{ + "foundation": { + "buildDir": ".", + "dockerfile": "Dockerfile", + "rebuildPatterns": ["*"] + } +} diff --git a/circuits/.yalc/@aztec/foundation/dest/async-map/index.d.ts b/circuits/.yalc/@aztec/foundation/dest/async-map/index.d.ts new file mode 100644 index 00000000000..39a6d3160ff --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/async-map/index.d.ts @@ -0,0 +1,2 @@ +export declare function asyncMap(arr: T[], fn: (e: T, i: number) => Promise): Promise; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/async-map/index.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/async-map/index.d.ts.map new file mode 100644 index 00000000000..583acc4749f --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/async-map/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/async-map/index.ts"],"names":[],"mappings":"AAAA,wBAAsB,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAMhG"} \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/async-map/index.js b/circuits/.yalc/@aztec/foundation/dest/async-map/index.js new file mode 100644 index 00000000000..c89cfad5cfc --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/async-map/index.js @@ -0,0 +1,8 @@ +export async function asyncMap(arr, fn) { + const results = []; + for (let i = 0; i < arr.length; ++i) { + results.push(await fn(arr[i], i)); + } + return results; +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYXN5bmMtbWFwL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE1BQU0sQ0FBQyxLQUFLLFVBQVUsUUFBUSxDQUFPLEdBQVEsRUFBRSxFQUFtQztJQUNoRixNQUFNLE9BQU8sR0FBUSxFQUFFLENBQUM7SUFDeEIsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLEVBQUU7UUFDbkMsT0FBTyxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztLQUNuQztJQUNELE9BQU8sT0FBTyxDQUFDO0FBQ2pCLENBQUMifQ== \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/bigint-buffer/index.d.ts b/circuits/.yalc/@aztec/foundation/dest/bigint-buffer/index.d.ts new file mode 100644 index 00000000000..6f79e17ef11 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/bigint-buffer/index.d.ts @@ -0,0 +1,28 @@ +/// +/** + * Convert a little-endian buffer into a BigInt. + * @param buf The little-endian buffer to convert + * @returns A BigInt with the little-endian representation of buf. + */ +export declare function toBigIntLE(buf: Buffer): bigint; +/** + * Convert a big-endian buffer into a BigInt + * @param buf The big-endian buffer to convert. + * @returns A BigInt with the big-endian representation of buf. + */ +export declare function toBigIntBE(buf: Buffer): bigint; +/** + * Convert a BigInt to a little-endian buffer. + * @param num The BigInt to convert. + * @param width The number of bytes that the resulting buffer should be. + * @returns A little-endian buffer representation of num. + */ +export declare function toBufferLE(num: bigint, width: number): Buffer; +/** + * Convert a BigInt to a big-endian buffer. + * @param num The BigInt to convert. + * @param width The number of bytes that the resulting buffer should be. + * @returns A big-endian buffer representation of num. + */ +export declare function toBufferBE(num: bigint, width: number): Buffer; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/bigint-buffer/index.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/bigint-buffer/index.d.ts.map new file mode 100644 index 00000000000..62cf676a149 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/bigint-buffer/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/bigint-buffer/index.ts"],"names":[],"mappings":";AAAA;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAQ9C;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAM9C;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAK7D;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAG7D"} \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/bigint-buffer/index.js b/circuits/.yalc/@aztec/foundation/dest/bigint-buffer/index.js new file mode 100644 index 00000000000..57c17bfe11c --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/bigint-buffer/index.js @@ -0,0 +1,49 @@ +/** + * Convert a little-endian buffer into a BigInt. + * @param buf The little-endian buffer to convert + * @returns A BigInt with the little-endian representation of buf. + */ +export function toBigIntLE(buf) { + const reversed = Buffer.from(buf); + reversed.reverse(); + const hex = reversed.toString('hex'); + if (hex.length === 0) { + return BigInt(0); + } + return BigInt(`0x${hex}`); +} +/** + * Convert a big-endian buffer into a BigInt + * @param buf The big-endian buffer to convert. + * @returns A BigInt with the big-endian representation of buf. + */ +export function toBigIntBE(buf) { + const hex = buf.toString('hex'); + if (hex.length === 0) { + return BigInt(0); + } + return BigInt(`0x${hex}`); +} +/** + * Convert a BigInt to a little-endian buffer. + * @param num The BigInt to convert. + * @param width The number of bytes that the resulting buffer should be. + * @returns A little-endian buffer representation of num. + */ +export function toBufferLE(num, width) { + const hex = num.toString(16); + const buffer = Buffer.from(hex.padStart(width * 2, '0').slice(0, width * 2), 'hex'); + buffer.reverse(); + return buffer; +} +/** + * Convert a BigInt to a big-endian buffer. + * @param num The BigInt to convert. + * @param width The number of bytes that the resulting buffer should be. + * @returns A big-endian buffer representation of num. + */ +export function toBufferBE(num, width) { + const hex = num.toString(16); + return Buffer.from(hex.padStart(width * 2, '0').slice(0, width * 2), 'hex'); +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYmlnaW50LWJ1ZmZlci9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7OztHQUlHO0FBQ0gsTUFBTSxVQUFVLFVBQVUsQ0FBQyxHQUFXO0lBQ3BDLE1BQU0sUUFBUSxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDbEMsUUFBUSxDQUFDLE9BQU8sRUFBRSxDQUFDO0lBQ25CLE1BQU0sR0FBRyxHQUFHLFFBQVEsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDckMsSUFBSSxHQUFHLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRTtRQUNwQixPQUFPLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQztLQUNsQjtJQUNELE9BQU8sTUFBTSxDQUFDLEtBQUssR0FBRyxFQUFFLENBQUMsQ0FBQztBQUM1QixDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILE1BQU0sVUFBVSxVQUFVLENBQUMsR0FBVztJQUNwQyxNQUFNLEdBQUcsR0FBRyxHQUFHLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ2hDLElBQUksR0FBRyxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUU7UUFDcEIsT0FBTyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUM7S0FDbEI7SUFDRCxPQUFPLE1BQU0sQ0FBQyxLQUFLLEdBQUcsRUFBRSxDQUFDLENBQUM7QUFDNUIsQ0FBQztBQUVEOzs7OztHQUtHO0FBQ0gsTUFBTSxVQUFVLFVBQVUsQ0FBQyxHQUFXLEVBQUUsS0FBYTtJQUNuRCxNQUFNLEdBQUcsR0FBRyxHQUFHLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQzdCLE1BQU0sTUFBTSxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxLQUFLLEdBQUcsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsS0FBSyxHQUFHLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQyxDQUFDO0lBQ3BGLE1BQU0sQ0FBQyxPQUFPLEVBQUUsQ0FBQztJQUNqQixPQUFPLE1BQU0sQ0FBQztBQUNoQixDQUFDO0FBRUQ7Ozs7O0dBS0c7QUFDSCxNQUFNLFVBQVUsVUFBVSxDQUFDLEdBQVcsRUFBRSxLQUFhO0lBQ25ELE1BQU0sR0FBRyxHQUFHLEdBQUcsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDN0IsT0FBTyxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsS0FBSyxHQUFHLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLEtBQUssR0FBRyxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQztBQUM5RSxDQUFDIn0= \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/crypto/index.d.ts b/circuits/.yalc/@aztec/foundation/dest/crypto/index.d.ts new file mode 100644 index 00000000000..5dbe75ece09 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/crypto/index.d.ts @@ -0,0 +1,2 @@ +export * from './random/index.js'; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/index.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/crypto/index.d.ts.map similarity index 52% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/index.d.ts.map rename to circuits/.yalc/@aztec/foundation/dest/crypto/index.d.ts.map index 76536aa0cf1..9959eaa8850 100644 --- a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/index.d.ts.map +++ b/circuits/.yalc/@aztec/foundation/dest/crypto/index.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/worker/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC"} \ No newline at end of file +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/crypto/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC"} \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/crypto/index.js b/circuits/.yalc/@aztec/foundation/dest/crypto/index.js new file mode 100644 index 00000000000..da8135eb499 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/crypto/index.js @@ -0,0 +1,2 @@ +export * from './random/index.js'; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY3J5cHRvL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLGNBQWMsbUJBQW1CLENBQUMifQ== \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/crypto/random/index.d.ts b/circuits/.yalc/@aztec/foundation/dest/crypto/random/index.d.ts new file mode 100644 index 00000000000..4f74a1d069d --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/crypto/random/index.d.ts @@ -0,0 +1,3 @@ +/// +export declare const randomBytes: (len: number) => Buffer; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/crypto/random/index.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/crypto/random/index.d.ts.map new file mode 100644 index 00000000000..4b2f2c6a4a0 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/crypto/random/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/crypto/random/index.ts"],"names":[],"mappings":";AAaA,eAAO,MAAM,WAAW,QAAS,MAAM,WAwBtC,CAAC"} \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/crypto/random/index.js b/circuits/.yalc/@aztec/foundation/dest/crypto/random/index.js new file mode 100644 index 00000000000..ada0839e4f3 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/crypto/random/index.js @@ -0,0 +1,36 @@ +import isNode from 'detect-node'; +import nodeCrypto from 'crypto'; +// limit of Crypto.getRandomValues() +// https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues +const MAX_BYTES = 65536; +const getWebCrypto = () => { + if (typeof window !== 'undefined' && window.crypto) + return window.crypto; + if (typeof self !== 'undefined' && self.crypto) + return self.crypto; + return undefined; +}; +export const randomBytes = (len) => { + if (isNode) { + return nodeCrypto.randomBytes(len); + } + const crypto = getWebCrypto(); + if (!crypto) { + throw new Error('randomBytes UnsupportedEnvironment'); + } + const buf = Buffer.allocUnsafe(len); + if (len > MAX_BYTES) { + // this is the max bytes crypto.getRandomValues + // can do at once see https://developer.mozilla.org/en-US/docs/Web/API/window.crypto.getRandomValues + for (let generated = 0; generated < len; generated += MAX_BYTES) { + // buffer.slice automatically checks if the end is past the end of + // the buffer so we don't have to here + crypto.getRandomValues(buf.slice(generated, generated + MAX_BYTES)); + } + } + else { + crypto.getRandomValues(buf); + } + return buf; +}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvY3J5cHRvL3JhbmRvbS9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLE1BQU0sTUFBTSxhQUFhLENBQUM7QUFDakMsT0FBTyxVQUFVLE1BQU0sUUFBUSxDQUFDO0FBRWhDLG9DQUFvQztBQUNwQywwRUFBMEU7QUFDMUUsTUFBTSxTQUFTLEdBQUcsS0FBSyxDQUFDO0FBRXhCLE1BQU0sWUFBWSxHQUFHLEdBQUcsRUFBRTtJQUN4QixJQUFJLE9BQU8sTUFBTSxLQUFLLFdBQVcsSUFBSSxNQUFNLENBQUMsTUFBTTtRQUFFLE9BQU8sTUFBTSxDQUFDLE1BQU0sQ0FBQztJQUN6RSxJQUFJLE9BQU8sSUFBSSxLQUFLLFdBQVcsSUFBSSxJQUFJLENBQUMsTUFBTTtRQUFFLE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQztJQUNuRSxPQUFPLFNBQVMsQ0FBQztBQUNuQixDQUFDLENBQUM7QUFFRixNQUFNLENBQUMsTUFBTSxXQUFXLEdBQUcsQ0FBQyxHQUFXLEVBQUUsRUFBRTtJQUN6QyxJQUFJLE1BQU0sRUFBRTtRQUNWLE9BQU8sVUFBVSxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQVcsQ0FBQztLQUM5QztJQUVELE1BQU0sTUFBTSxHQUFHLFlBQVksRUFBRSxDQUFDO0lBQzlCLElBQUksQ0FBQyxNQUFNLEVBQUU7UUFDWCxNQUFNLElBQUksS0FBSyxDQUFDLG9DQUFvQyxDQUFDLENBQUM7S0FDdkQ7SUFFRCxNQUFNLEdBQUcsR0FBRyxNQUFNLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ3BDLElBQUksR0FBRyxHQUFHLFNBQVMsRUFBRTtRQUNuQiwrQ0FBK0M7UUFDL0Msb0dBQW9HO1FBQ3BHLEtBQUssSUFBSSxTQUFTLEdBQUcsQ0FBQyxFQUFFLFNBQVMsR0FBRyxHQUFHLEVBQUUsU0FBUyxJQUFJLFNBQVMsRUFBRTtZQUMvRCxrRUFBa0U7WUFDbEUsc0NBQXNDO1lBQ3RDLE1BQU0sQ0FBQyxlQUFlLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxTQUFTLEVBQUUsU0FBUyxHQUFHLFNBQVMsQ0FBQyxDQUFDLENBQUM7U0FDckU7S0FDRjtTQUFNO1FBQ0wsTUFBTSxDQUFDLGVBQWUsQ0FBQyxHQUFHLENBQUMsQ0FBQztLQUM3QjtJQUVELE9BQU8sR0FBRyxDQUFDO0FBQ2IsQ0FBQyxDQUFDIn0= \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/errors/index.d.ts b/circuits/.yalc/@aztec/foundation/dest/errors/index.d.ts new file mode 100644 index 00000000000..d170999a8e6 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/errors/index.d.ts @@ -0,0 +1,3 @@ +export declare class InterruptError extends Error { +} +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/errors/index.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/errors/index.d.ts.map new file mode 100644 index 00000000000..43dc46d4a62 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/errors/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/errors/index.ts"],"names":[],"mappings":"AAAA,qBAAa,cAAe,SAAQ,KAAK;CAAG"} \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/errors/index.js b/circuits/.yalc/@aztec/foundation/dest/errors/index.js new file mode 100644 index 00000000000..75cd68ff856 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/errors/index.js @@ -0,0 +1,3 @@ +export class InterruptError extends Error { +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZXJyb3JzL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE1BQU0sT0FBTyxjQUFlLFNBQVEsS0FBSztDQUFHIn0= \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/fifo/bounded_serial_queue.d.ts b/circuits/.yalc/@aztec/foundation/dest/fifo/bounded_serial_queue.d.ts new file mode 100644 index 00000000000..d983bc97d29 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/fifo/bounded_serial_queue.d.ts @@ -0,0 +1,24 @@ +/** + * Leverages the unbounded SerialQueue and Semaphore to create a SerialQueue that will block when putting an item + * if the queue size = maxQueueSize. + */ +export declare class BoundedSerialQueue { + private readonly queue; + private semaphore; + constructor(maxQueueSize: number); + start(): void; + length(): number; + cancel(): Promise; + end(): Promise; + /** + * The caller will block until fn is succesfully enqueued. + * The fn itself is execute asyncronously and its result discarded. + */ + put(fn: () => Promise): Promise; + /** + * The caller will block until fn is successfully executed, and it's result returned. + */ + exec(fn: () => Promise): Promise; + syncPoint(): Promise; +} +//# sourceMappingURL=bounded_serial_queue.d.ts.map \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/fifo/bounded_serial_queue.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/fifo/bounded_serial_queue.d.ts.map new file mode 100644 index 00000000000..abb0c68e8f5 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/fifo/bounded_serial_queue.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"bounded_serial_queue.d.ts","sourceRoot":"","sources":["../../src/fifo/bounded_serial_queue.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqB;IAC3C,OAAO,CAAC,SAAS,CAAY;gBAEjB,YAAY,EAAE,MAAM;IAIzB,KAAK;IAIL,MAAM;IAIN,MAAM;IAIN,GAAG;IAIV;;;OAGG;IACU,GAAG,CAAC,EAAE,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAexD;;OAEG;IACU,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAYzC,SAAS;CAGvB"} \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/fifo/bounded_serial_queue.js b/circuits/.yalc/@aztec/foundation/dest/fifo/bounded_serial_queue.js new file mode 100644 index 00000000000..6914ec9e116 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/fifo/bounded_serial_queue.js @@ -0,0 +1,62 @@ +import { Semaphore } from './semaphore.js'; +import { SerialQueue } from './serial_queue.js'; +/** + * Leverages the unbounded SerialQueue and Semaphore to create a SerialQueue that will block when putting an item + * if the queue size = maxQueueSize. + */ +export class BoundedSerialQueue { + constructor(maxQueueSize) { + this.queue = new SerialQueue(); + this.semaphore = new Semaphore(maxQueueSize); + } + start() { + this.queue.start(); + } + length() { + return this.queue.length(); + } + cancel() { + return this.queue.cancel(); + } + end() { + return this.queue.end(); + } + /** + * The caller will block until fn is succesfully enqueued. + * The fn itself is execute asyncronously and its result discarded. + */ + async put(fn) { + await this.semaphore.acquire(); + this.queue + .put(async () => { + try { + await fn(); + } + finally { + this.semaphore.release(); + } + }) + .catch(err => { + console.error('BoundedSerialQueue handler exception:', err); + }); + } + /** + * The caller will block until fn is successfully executed, and it's result returned. + */ + async exec(fn) { + await this.semaphore.acquire(); + return this.queue.put(async () => { + try { + return await fn(); + } + finally { + this.semaphore.release(); + } + }); + } + // Awaiting this ensures the queue is empty before resuming. + async syncPoint() { + await this.queue.syncPoint(); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYm91bmRlZF9zZXJpYWxfcXVldWUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZmlmby9ib3VuZGVkX3NlcmlhbF9xdWV1ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDM0MsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBRWhEOzs7R0FHRztBQUNILE1BQU0sT0FBTyxrQkFBa0I7SUFJN0IsWUFBWSxZQUFvQjtRQUhmLFVBQUssR0FBRyxJQUFJLFdBQVcsRUFBRSxDQUFDO1FBSXpDLElBQUksQ0FBQyxTQUFTLEdBQUcsSUFBSSxTQUFTLENBQUMsWUFBWSxDQUFDLENBQUM7SUFDL0MsQ0FBQztJQUVNLEtBQUs7UUFDVixJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQ3JCLENBQUM7SUFFTSxNQUFNO1FBQ1gsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sRUFBRSxDQUFDO0lBQzdCLENBQUM7SUFFTSxNQUFNO1FBQ1gsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sRUFBRSxDQUFDO0lBQzdCLENBQUM7SUFFTSxHQUFHO1FBQ1IsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsRUFBRSxDQUFDO0lBQzFCLENBQUM7SUFFRDs7O09BR0c7SUFDSSxLQUFLLENBQUMsR0FBRyxDQUFDLEVBQXVCO1FBQ3RDLE1BQU0sSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUMvQixJQUFJLENBQUMsS0FBSzthQUNQLEdBQUcsQ0FBQyxLQUFLLElBQUksRUFBRTtZQUNkLElBQUk7Z0JBQ0YsTUFBTSxFQUFFLEVBQUUsQ0FBQzthQUNaO29CQUFTO2dCQUNSLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxFQUFFLENBQUM7YUFDMUI7UUFDSCxDQUFDLENBQUM7YUFDRCxLQUFLLENBQUMsR0FBRyxDQUFDLEVBQUU7WUFDWCxPQUFPLENBQUMsS0FBSyxDQUFDLHVDQUF1QyxFQUFFLEdBQUcsQ0FBQyxDQUFDO1FBQzlELENBQUMsQ0FBQyxDQUFDO0lBQ1AsQ0FBQztJQUVEOztPQUVHO0lBQ0ksS0FBSyxDQUFDLElBQUksQ0FBSSxFQUFvQjtRQUN2QyxNQUFNLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDL0IsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxLQUFLLElBQUksRUFBRTtZQUMvQixJQUFJO2dCQUNGLE9BQU8sTUFBTSxFQUFFLEVBQUUsQ0FBQzthQUNuQjtvQkFBUztnQkFDUixJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sRUFBRSxDQUFDO2FBQzFCO1FBQ0gsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQsNERBQTREO0lBQ3JELEtBQUssQ0FBQyxTQUFTO1FBQ3BCLE1BQU0sSUFBSSxDQUFDLEtBQUssQ0FBQyxTQUFTLEVBQUUsQ0FBQztJQUMvQixDQUFDO0NBQ0YifQ== \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/fifo/index.d.ts b/circuits/.yalc/@aztec/foundation/dest/fifo/index.d.ts new file mode 100644 index 00000000000..e5f0f05c2b2 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/fifo/index.d.ts @@ -0,0 +1,5 @@ +export * from './memory_fifo.js'; +export * from './serial_queue.js'; +export * from './bounded_serial_queue.js'; +export * from './semaphore.js'; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/fifo/index.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/fifo/index.d.ts.map new file mode 100644 index 00000000000..f6a3b8c1b4c --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/fifo/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/fifo/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,gBAAgB,CAAC"} \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/fifo/index.js b/circuits/.yalc/@aztec/foundation/dest/fifo/index.js new file mode 100644 index 00000000000..7822f7c274a --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/fifo/index.js @@ -0,0 +1,5 @@ +export * from './memory_fifo.js'; +export * from './serial_queue.js'; +export * from './bounded_serial_queue.js'; +export * from './semaphore.js'; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZmlmby9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxjQUFjLGtCQUFrQixDQUFDO0FBQ2pDLGNBQWMsbUJBQW1CLENBQUM7QUFDbEMsY0FBYywyQkFBMkIsQ0FBQztBQUMxQyxjQUFjLGdCQUFnQixDQUFDIn0= \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/memory_fifo.d.ts b/circuits/.yalc/@aztec/foundation/dest/fifo/memory_fifo.d.ts similarity index 86% rename from circuits/ts/.yalc/@aztec/wasm/dest/memory_fifo.d.ts rename to circuits/.yalc/@aztec/foundation/dest/fifo/memory_fifo.d.ts index de592d842b4..045f1a6a562 100644 --- a/circuits/ts/.yalc/@aztec/wasm/dest/memory_fifo.d.ts +++ b/circuits/.yalc/@aztec/foundation/dest/fifo/memory_fifo.d.ts @@ -7,22 +7,15 @@ export declare class MemoryFifo { private waiting; private items; private flushing; - /** - * Length of queue. - * @returns integer. - */ length(): number; /** * Returns next item within the queue, or blocks until and item has been put into the queue. * If given a timeout, the promise will reject if no item is received after `timeout` seconds. * If the queue is flushing, `null` is returned. - * @param timeout - In seconds. - * @returns Promise of result. */ get(timeout?: number): Promise; /** * Put an item onto back of the queue. - * @param item - The item to enqueue. */ put(item: T): void; /** @@ -39,7 +32,6 @@ export declare class MemoryFifo { cancel(): void; /** * Helper method that can be used to continously consume and process items on the queue. - * @param handler - The item handler function. */ process(handler: (item: T) => Promise): Promise; } diff --git a/circuits/.yalc/@aztec/foundation/dest/fifo/memory_fifo.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/fifo/memory_fifo.d.ts.map new file mode 100644 index 00000000000..99a03a16c37 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/fifo/memory_fifo.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"memory_fifo.d.ts","sourceRoot":"","sources":["../../src/fifo/memory_fifo.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,qBAAa,UAAU,CAAC,CAAC;IACvB,OAAO,CAAC,OAAO,CAAoC;IACnD,OAAO,CAAC,KAAK,CAAW;IACxB,OAAO,CAAC,QAAQ,CAAS;IAElB,MAAM;IAIb;;;;OAIG;IACI,GAAG,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAyB/C;;OAEG;IACI,GAAG,CAAC,IAAI,EAAE,CAAC;IAUlB;;;;OAIG;IACI,GAAG;IAKV;;;;OAIG;IACI,MAAM;IAMb;;OAEG;IACU,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC;CAazD"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/memory_fifo.js b/circuits/.yalc/@aztec/foundation/dest/fifo/memory_fifo.js similarity index 51% rename from circuits/ts/.yalc/@aztec/wasm/dest/memory_fifo.js rename to circuits/.yalc/@aztec/foundation/dest/fifo/memory_fifo.js index f742e3a773c..ea087ed86c0 100644 --- a/circuits/ts/.yalc/@aztec/wasm/dest/memory_fifo.js +++ b/circuits/.yalc/@aztec/foundation/dest/fifo/memory_fifo.js @@ -1,4 +1,3 @@ -// TODO should come from a dependency /** * A simple fifo queue. It can grow unbounded. It can have multiple producers and consumers. * Putting an item onto the queue always succeeds, unless either end() or cancel() has been called in which case @@ -10,10 +9,6 @@ export class MemoryFifo { this.items = []; this.flushing = false; } - /** - * Length of queue. - * @returns integer. - */ length() { return this.items.length; } @@ -21,8 +16,6 @@ export class MemoryFifo { * Returns next item within the queue, or blocks until and item has been put into the queue. * If given a timeout, the promise will reject if no item is received after `timeout` seconds. * If the queue is flushing, `null` is returned. - * @param timeout - In seconds. - * @returns Promise of result. */ get(timeout) { if (this.items.length) { @@ -47,7 +40,6 @@ export class MemoryFifo { } /** * Put an item onto back of the queue. - * @param item - The item to enqueue. */ put(item) { if (this.flushing) { @@ -81,7 +73,6 @@ export class MemoryFifo { } /** * Helper method that can be used to continously consume and process items on the queue. - * @param handler - The item handler function. */ async process(handler) { try { @@ -98,4 +89,4 @@ export class MemoryFifo { } } } -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVtb3J5X2ZpZm8uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvbWVtb3J5X2ZpZm8udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEscUNBQXFDO0FBQ3JDOzs7O0dBSUc7QUFDSCxNQUFNLE9BQU8sVUFBVTtJQUF2QjtRQUNVLFlBQU8sR0FBaUMsRUFBRSxDQUFDO1FBQzNDLFVBQUssR0FBUSxFQUFFLENBQUM7UUFDaEIsYUFBUSxHQUFHLEtBQUssQ0FBQztJQThGM0IsQ0FBQztJQTVGQzs7O09BR0c7SUFDSSxNQUFNO1FBQ1gsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQztJQUMzQixDQUFDO0lBRUQ7Ozs7OztPQU1HO0lBQ0ksR0FBRyxDQUFDLE9BQWdCO1FBQ3pCLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLEVBQUU7WUFDckIsT0FBTyxPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxFQUFHLENBQUMsQ0FBQztTQUM3QztRQUVELElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLEtBQUssQ0FBQyxJQUFJLElBQUksQ0FBQyxRQUFRLEVBQUU7WUFDNUMsT0FBTyxPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO1NBQzlCO1FBRUQsT0FBTyxJQUFJLE9BQU8sQ0FBVyxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsRUFBRTtZQUMvQyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUUzQixJQUFJLE9BQU8sRUFBRTtnQkFDWCxVQUFVLENBQUMsR0FBRyxFQUFFO29CQUNkLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxLQUFLLE9BQU8sQ0FBQyxDQUFDO29CQUN6RCxJQUFJLEtBQUssR0FBRyxDQUFDLENBQUMsRUFBRTt3QkFDZCxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUM7d0JBQzlCLE1BQU0sR0FBRyxHQUFHLElBQUksS0FBSyxDQUFDLGtDQUFrQyxDQUFDLENBQUM7d0JBQzFELE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQztxQkFDYjtnQkFDSCxDQUFDLEVBQUUsT0FBTyxHQUFHLElBQUksQ0FBQyxDQUFDO2FBQ3BCO1FBQ0gsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQ7OztPQUdHO0lBQ0ksR0FBRyxDQUFDLElBQU87UUFDaEIsSUFBSSxJQUFJLENBQUMsUUFBUSxFQUFFO1lBQ2pCLE9BQU87U0FDUjthQUFNLElBQUksSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLEVBQUU7WUFDOUIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztTQUM3QjthQUFNO1lBQ0wsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7U0FDdkI7SUFDSCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNJLEdBQUc7UUFDUixJQUFJLENBQUMsUUFBUSxHQUFHLElBQUksQ0FBQztRQUNyQixJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQ2pELENBQUM7SUFFRDs7OztPQUlHO0lBQ0ksTUFBTTtRQUNYLElBQUksQ0FBQyxRQUFRLEdBQUcsSUFBSSxDQUFDO1FBQ3JCLElBQUksQ0FBQyxLQUFLLEdBQUcsRUFBRSxDQUFDO1FBQ2hCLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDakQsQ0FBQztJQUVEOzs7T0FHRztJQUNJLEtBQUssQ0FBQyxPQUFPLENBQUMsT0FBbUM7UUFDdEQsSUFBSTtZQUNGLE9BQU8sSUFBSSxFQUFFO2dCQUNYLE1BQU0sSUFBSSxHQUFHLE1BQU0sSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO2dCQUM5QixJQUFJLElBQUksS0FBSyxJQUFJLEVBQUU7b0JBQ2pCLE1BQU07aUJBQ1A7Z0JBQ0QsTUFBTSxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7YUFDckI7U0FDRjtRQUFDLE9BQU8sR0FBRyxFQUFFO1lBQ1osT0FBTyxDQUFDLEtBQUssQ0FBQywwQkFBMEIsRUFBRSxHQUFHLENBQUMsQ0FBQztTQUNoRDtJQUNILENBQUM7Q0FDRiJ9 \ No newline at end of file +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVtb3J5X2ZpZm8uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZmlmby9tZW1vcnlfZmlmby50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7OztHQUlHO0FBQ0gsTUFBTSxPQUFPLFVBQVU7SUFBdkI7UUFDVSxZQUFPLEdBQWlDLEVBQUUsQ0FBQztRQUMzQyxVQUFLLEdBQVEsRUFBRSxDQUFDO1FBQ2hCLGFBQVEsR0FBRyxLQUFLLENBQUM7SUFzRjNCLENBQUM7SUFwRlEsTUFBTTtRQUNYLE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUM7SUFDM0IsQ0FBQztJQUVEOzs7O09BSUc7SUFDSSxHQUFHLENBQUMsT0FBZ0I7UUFDekIsSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sRUFBRTtZQUNyQixPQUFPLE9BQU8sQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLEVBQUcsQ0FBQyxDQUFDO1NBQzdDO1FBRUQsSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sS0FBSyxDQUFDLElBQUksSUFBSSxDQUFDLFFBQVEsRUFBRTtZQUM1QyxPQUFPLE9BQU8sQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7U0FDOUI7UUFFRCxPQUFPLElBQUksT0FBTyxDQUFXLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxFQUFFO1lBQy9DLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBRTNCLElBQUksT0FBTyxFQUFFO2dCQUNYLFVBQVUsQ0FBQyxHQUFHLEVBQUU7b0JBQ2QsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEtBQUssT0FBTyxDQUFDLENBQUM7b0JBQ3pELElBQUksS0FBSyxHQUFHLENBQUMsQ0FBQyxFQUFFO3dCQUNkLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUMsQ0FBQzt3QkFDOUIsTUFBTSxHQUFHLEdBQUcsSUFBSSxLQUFLLENBQUMsa0NBQWtDLENBQUMsQ0FBQzt3QkFDMUQsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDO3FCQUNiO2dCQUNILENBQUMsRUFBRSxPQUFPLEdBQUcsSUFBSSxDQUFDLENBQUM7YUFDcEI7UUFDSCxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRDs7T0FFRztJQUNJLEdBQUcsQ0FBQyxJQUFPO1FBQ2hCLElBQUksSUFBSSxDQUFDLFFBQVEsRUFBRTtZQUNqQixPQUFPO1NBQ1I7YUFBTSxJQUFJLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFO1lBQzlCLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFHLENBQUMsSUFBSSxDQUFDLENBQUM7U0FDN0I7YUFBTTtZQUNMLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO1NBQ3ZCO0lBQ0gsQ0FBQztJQUVEOzs7O09BSUc7SUFDSSxHQUFHO1FBQ1IsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUM7UUFDckIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztJQUNqRCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNJLE1BQU07UUFDWCxJQUFJLENBQUMsUUFBUSxHQUFHLElBQUksQ0FBQztRQUNyQixJQUFJLENBQUMsS0FBSyxHQUFHLEVBQUUsQ0FBQztRQUNoQixJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQ2pELENBQUM7SUFFRDs7T0FFRztJQUNJLEtBQUssQ0FBQyxPQUFPLENBQUMsT0FBbUM7UUFDdEQsSUFBSTtZQUNGLE9BQU8sSUFBSSxFQUFFO2dCQUNYLE1BQU0sSUFBSSxHQUFHLE1BQU0sSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO2dCQUM5QixJQUFJLElBQUksS0FBSyxJQUFJLEVBQUU7b0JBQ2pCLE1BQU07aUJBQ1A7Z0JBQ0QsTUFBTSxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7YUFDckI7U0FDRjtRQUFDLE9BQU8sR0FBRyxFQUFFO1lBQ1osT0FBTyxDQUFDLEtBQUssQ0FBQywwQkFBMEIsRUFBRSxHQUFHLENBQUMsQ0FBQztTQUNoRDtJQUNILENBQUM7Q0FDRiJ9 \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/fifo/semaphore.d.ts b/circuits/.yalc/@aztec/foundation/dest/fifo/semaphore.d.ts new file mode 100644 index 00000000000..036b2aff836 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/fifo/semaphore.d.ts @@ -0,0 +1,10 @@ +/** + * Allows the acquiring of up to `size` tokens before calls to acquire block, waiting for a call to release(). + */ +export declare class Semaphore { + private readonly queue; + constructor(size: number); + acquire(): Promise; + release(): void; +} +//# sourceMappingURL=semaphore.d.ts.map \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/fifo/semaphore.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/fifo/semaphore.d.ts.map new file mode 100644 index 00000000000..9c1f94e784f --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/fifo/semaphore.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"semaphore.d.ts","sourceRoot":"","sources":["../../src/fifo/semaphore.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA6B;gBAEvC,IAAI,EAAE,MAAM;IAIX,OAAO;IAIb,OAAO;CAGf"} \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/fifo/semaphore.js b/circuits/.yalc/@aztec/foundation/dest/fifo/semaphore.js new file mode 100644 index 00000000000..6ca6439f88c --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/fifo/semaphore.js @@ -0,0 +1,17 @@ +import { MemoryFifo } from './memory_fifo.js'; +/** + * Allows the acquiring of up to `size` tokens before calls to acquire block, waiting for a call to release(). + */ +export class Semaphore { + constructor(size) { + this.queue = new MemoryFifo(); + new Array(size).fill(true).map(() => this.queue.put(true)); + } + async acquire() { + await this.queue.get(); + } + release() { + this.queue.put(true); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VtYXBob3JlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2ZpZm8vc2VtYXBob3JlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUU5Qzs7R0FFRztBQUNILE1BQU0sT0FBTyxTQUFTO0lBR3BCLFlBQVksSUFBWTtRQUZQLFVBQUssR0FBRyxJQUFJLFVBQVUsRUFBVyxDQUFDO1FBR2pELElBQUksS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztJQUM3RCxDQUFDO0lBRU0sS0FBSyxDQUFDLE9BQU87UUFDbEIsTUFBTSxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsRUFBRSxDQUFDO0lBQ3pCLENBQUM7SUFFTSxPQUFPO1FBQ1osSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDdkIsQ0FBQztDQUNGIn0= \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/fifo/serial_queue.d.ts b/circuits/.yalc/@aztec/foundation/dest/fifo/serial_queue.d.ts new file mode 100644 index 00000000000..31bfd560bc2 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/fifo/serial_queue.d.ts @@ -0,0 +1,18 @@ +/** + * A more specialised fifo queue that enqueues functions to execute. Enqueued functions are executed in serial. + */ +export declare class SerialQueue { + private readonly queue; + private runningPromise; + start(): void; + length(): number; + cancel(): Promise; + end(): Promise; + /** + * Enqueues fn for execution on the serial queue. + * Returns the result of the function after execution. + */ + put(fn: () => Promise): Promise; + syncPoint(): Promise; +} +//# sourceMappingURL=serial_queue.d.ts.map \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/fifo/serial_queue.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/fifo/serial_queue.d.ts.map new file mode 100644 index 00000000000..fa0f128465e --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/fifo/serial_queue.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"serial_queue.d.ts","sourceRoot":"","sources":["../../src/fifo/serial_queue.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAyC;IAC/D,OAAO,CAAC,cAAc,CAAiB;IAEhC,KAAK;IAIL,MAAM;IAIN,MAAM;IAKN,GAAG;IAKV;;;OAGG;IACI,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAclC,SAAS;CAGvB"} \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/fifo/serial_queue.js b/circuits/.yalc/@aztec/foundation/dest/fifo/serial_queue.js new file mode 100644 index 00000000000..5cb2808754d --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/fifo/serial_queue.js @@ -0,0 +1,45 @@ +import { MemoryFifo } from './memory_fifo.js'; +/** + * A more specialised fifo queue that enqueues functions to execute. Enqueued functions are executed in serial. + */ +export class SerialQueue { + constructor() { + this.queue = new MemoryFifo(); + } + start() { + this.runningPromise = this.queue.process(fn => fn()); + } + length() { + return this.queue.length(); + } + cancel() { + this.queue.cancel(); + return this.runningPromise; + } + end() { + this.queue.end(); + return this.runningPromise; + } + /** + * Enqueues fn for execution on the serial queue. + * Returns the result of the function after execution. + */ + put(fn) { + return new Promise((resolve, reject) => { + this.queue.put(async () => { + try { + const res = await fn(); + resolve(res); + } + catch (e) { + reject(e); + } + }); + }); + } + // Awaiting this ensures the queue is empty before resuming. + async syncPoint() { + await this.put(async () => { }); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VyaWFsX3F1ZXVlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2ZpZm8vc2VyaWFsX3F1ZXVlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUU5Qzs7R0FFRztBQUNILE1BQU0sT0FBTyxXQUFXO0lBQXhCO1FBQ21CLFVBQUssR0FBRyxJQUFJLFVBQVUsRUFBdUIsQ0FBQztJQTBDakUsQ0FBQztJQXZDUSxLQUFLO1FBQ1YsSUFBSSxDQUFDLGNBQWMsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDdkQsQ0FBQztJQUVNLE1BQU07UUFDWCxPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxFQUFFLENBQUM7SUFDN0IsQ0FBQztJQUVNLE1BQU07UUFDWCxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sRUFBRSxDQUFDO1FBQ3BCLE9BQU8sSUFBSSxDQUFDLGNBQWMsQ0FBQztJQUM3QixDQUFDO0lBRU0sR0FBRztRQUNSLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFLENBQUM7UUFDakIsT0FBTyxJQUFJLENBQUMsY0FBYyxDQUFDO0lBQzdCLENBQUM7SUFFRDs7O09BR0c7SUFDSSxHQUFHLENBQUksRUFBb0I7UUFDaEMsT0FBTyxJQUFJLE9BQU8sQ0FBQyxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsRUFBRTtZQUNyQyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxLQUFLLElBQUksRUFBRTtnQkFDeEIsSUFBSTtvQkFDRixNQUFNLEdBQUcsR0FBRyxNQUFNLEVBQUUsRUFBRSxDQUFDO29CQUN2QixPQUFPLENBQUMsR0FBRyxDQUFDLENBQUM7aUJBQ2Q7Z0JBQUMsT0FBTyxDQUFDLEVBQUU7b0JBQ1YsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDO2lCQUNYO1lBQ0gsQ0FBQyxDQUFDLENBQUM7UUFDTCxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRCw0REFBNEQ7SUFDckQsS0FBSyxDQUFDLFNBQVM7UUFDcEIsTUFBTSxJQUFJLENBQUMsR0FBRyxDQUFDLEtBQUssSUFBSSxFQUFFLEdBQUUsQ0FBQyxDQUFDLENBQUM7SUFDakMsQ0FBQztDQUNGIn0= \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/index.d.ts b/circuits/.yalc/@aztec/foundation/dest/index.d.ts new file mode 100644 index 00000000000..9a5509e1ff6 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/index.d.ts @@ -0,0 +1,15 @@ +export * from './async-map/index.js'; +export * from './bigint-buffer/index.js'; +export * from './errors/index.js'; +export * from './fifo/index.js'; +export * from './mutex/index.js'; +export * from './timer/index.js'; +export * from './log/index.js'; +export * from './retry/index.js'; +export * from './sleep/index.js'; +export * from './serialize/index.js'; +export * from './transport/index.js'; +export * from './iso-fetch/index.js'; +export * from './crypto/index.js'; +export * from './running-promise/index.js'; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/index.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/index.d.ts.map new file mode 100644 index 00000000000..d1019e07fc3 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC;AACzC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,4BAA4B,CAAC"} \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/index.js b/circuits/.yalc/@aztec/foundation/dest/index.js new file mode 100644 index 00000000000..94e6719015d --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/index.js @@ -0,0 +1,15 @@ +export * from './async-map/index.js'; +export * from './bigint-buffer/index.js'; +export * from './errors/index.js'; +export * from './fifo/index.js'; +export * from './mutex/index.js'; +export * from './timer/index.js'; +export * from './log/index.js'; +export * from './retry/index.js'; +export * from './sleep/index.js'; +export * from './serialize/index.js'; +export * from './transport/index.js'; +export * from './iso-fetch/index.js'; +export * from './crypto/index.js'; +export * from './running-promise/index.js'; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsY0FBYyxzQkFBc0IsQ0FBQztBQUNyQyxjQUFjLDBCQUEwQixDQUFDO0FBQ3pDLGNBQWMsbUJBQW1CLENBQUM7QUFDbEMsY0FBYyxpQkFBaUIsQ0FBQztBQUNoQyxjQUFjLGtCQUFrQixDQUFDO0FBQ2pDLGNBQWMsa0JBQWtCLENBQUM7QUFDakMsY0FBYyxnQkFBZ0IsQ0FBQztBQUMvQixjQUFjLGtCQUFrQixDQUFDO0FBQ2pDLGNBQWMsa0JBQWtCLENBQUM7QUFDakMsY0FBYyxzQkFBc0IsQ0FBQztBQUNyQyxjQUFjLHNCQUFzQixDQUFDO0FBQ3JDLGNBQWMsc0JBQXNCLENBQUM7QUFDckMsY0FBYyxtQkFBbUIsQ0FBQztBQUNsQyxjQUFjLDRCQUE0QixDQUFDIn0= \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/index.d.ts b/circuits/.yalc/@aztec/foundation/dest/iso-fetch/index.d.ts similarity index 50% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/index.d.ts rename to circuits/.yalc/@aztec/foundation/dest/iso-fetch/index.d.ts index f25d4249a81..89d1b283cef 100644 --- a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/index.d.ts +++ b/circuits/.yalc/@aztec/foundation/dest/iso-fetch/index.d.ts @@ -1,2 +1,2 @@ -export * from './worker_pool.js'; +export * from 'cross-fetch'; //# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/iso-fetch/index.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/iso-fetch/index.d.ts.map new file mode 100644 index 00000000000..09f4c4bc811 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/iso-fetch/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/iso-fetch/index.ts"],"names":[],"mappings":"AACA,cAAc,aAAa,CAAC"} \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/iso-fetch/index.js b/circuits/.yalc/@aztec/foundation/dest/iso-fetch/index.js new file mode 100644 index 00000000000..cb08fc52017 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/iso-fetch/index.js @@ -0,0 +1,3 @@ +// TODO: Remove, node 18 has native fetch. +export * from 'cross-fetch'; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaXNvLWZldGNoL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLDBDQUEwQztBQUMxQyxjQUFjLGFBQWEsQ0FBQyJ9 \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/log/console.d.ts b/circuits/.yalc/@aztec/foundation/dest/log/console.d.ts new file mode 100644 index 00000000000..688a7e1e5c2 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/log/console.d.ts @@ -0,0 +1,3 @@ +export type Logger = (...args: any[]) => void; +export declare function createLogger(prefix: string): Logger; +//# sourceMappingURL=console.d.ts.map \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/log/console.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/log/console.d.ts.map new file mode 100644 index 00000000000..ac69effceef --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/log/console.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"console.d.ts","sourceRoot":"","sources":["../../src/log/console.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;AAU9C,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAMnD"} \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/log/console.js b/circuits/.yalc/@aztec/foundation/dest/log/console.js new file mode 100644 index 00000000000..8167cd83ea7 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/log/console.js @@ -0,0 +1,17 @@ +class ConsoleLogger { + constructor(prefix, logger = console.log) { + this.prefix = prefix; + this.logger = logger; + } + log(...args) { + this.logger(`${this.prefix}:`, ...args); + } +} +export function createLogger(prefix) { + if (prefix) { + const logger = new ConsoleLogger(prefix, console.log); + return (...args) => logger.log(...args); + } + return console.log; +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uc29sZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9sb2cvY29uc29sZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFFQSxNQUFNLGFBQWE7SUFDakIsWUFBb0IsTUFBYyxFQUFVLFNBQW1DLE9BQU8sQ0FBQyxHQUFHO1FBQXRFLFdBQU0sR0FBTixNQUFNLENBQVE7UUFBVSxXQUFNLEdBQU4sTUFBTSxDQUF3QztJQUFHLENBQUM7SUFFdkYsR0FBRyxDQUFDLEdBQUcsSUFBVztRQUN2QixJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsSUFBSSxDQUFDLE1BQU0sR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDLENBQUM7SUFDMUMsQ0FBQztDQUNGO0FBRUQsTUFBTSxVQUFVLFlBQVksQ0FBQyxNQUFjO0lBQ3pDLElBQUksTUFBTSxFQUFFO1FBQ1YsTUFBTSxNQUFNLEdBQUcsSUFBSSxhQUFhLENBQUMsTUFBTSxFQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUN0RCxPQUFPLENBQUMsR0FBRyxJQUFXLEVBQUUsRUFBRSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxJQUFJLENBQUMsQ0FBQztLQUNoRDtJQUNELE9BQU8sT0FBTyxDQUFDLEdBQUcsQ0FBQztBQUNyQixDQUFDIn0= \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/log/debug.d.ts b/circuits/.yalc/@aztec/foundation/dest/log/debug.d.ts new file mode 100644 index 00000000000..6ee596beb27 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/log/debug.d.ts @@ -0,0 +1,6 @@ +export declare function createDebugLogger(name: string): (...args: any[]) => void; +export declare function setPreDebugLogHook(fn: (...args: any[]) => void): void; +export declare function setPostDebugLogHook(fn: (...args: any[]) => void): void; +export declare function enableLogs(str: string): void; +export declare function isLogEnabled(str: string): boolean; +//# sourceMappingURL=debug.d.ts.map \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/log/debug.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/log/debug.d.ts.map new file mode 100644 index 00000000000..8a8a87e15c4 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/log/debug.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"debug.d.ts","sourceRoot":"","sources":["../../src/log/debug.ts"],"names":[],"mappings":"AAkBA,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,aAE3B,GAAG,EAAE,UACvB;AAED,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,QAE9D;AAED,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,QAE/D;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,QAErC;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,WAEvC"} \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/log/debug.js b/circuits/.yalc/@aztec/foundation/dest/log/debug.js new file mode 100644 index 00000000000..299e238145d --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/log/debug.js @@ -0,0 +1,32 @@ +import debug from 'debug'; +let preLogHook; +let postLogHook; +function theFunctionThroughWhichAllLogsPass(logger, ...args) { + if (!debug.enabled(logger.namespace)) { + return; + } + if (preLogHook) { + preLogHook(logger.namespace, ...args); + } + logger(...args); + if (postLogHook) { + postLogHook(logger.namespace, ...args); + } +} +export function createDebugLogger(name) { + const logger = debug(name); + return (...args) => theFunctionThroughWhichAllLogsPass(logger, ...args); +} +export function setPreDebugLogHook(fn) { + preLogHook = fn; +} +export function setPostDebugLogHook(fn) { + postLogHook = fn; +} +export function enableLogs(str) { + debug.enable(str); +} +export function isLogEnabled(str) { + return debug.enabled(str); +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVidWcuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvbG9nL2RlYnVnLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxNQUFNLE9BQU8sQ0FBQztBQUUxQixJQUFJLFVBQWtELENBQUM7QUFDdkQsSUFBSSxXQUFtRCxDQUFDO0FBRXhELFNBQVMsa0NBQWtDLENBQUMsTUFBVyxFQUFFLEdBQUcsSUFBVztJQUNyRSxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLEVBQUU7UUFDcEMsT0FBTztLQUNSO0lBQ0QsSUFBSSxVQUFVLEVBQUU7UUFDZCxVQUFVLENBQUMsTUFBTSxDQUFDLFNBQVMsRUFBRSxHQUFHLElBQUksQ0FBQyxDQUFDO0tBQ3ZDO0lBQ0QsTUFBTSxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUM7SUFDaEIsSUFBSSxXQUFXLEVBQUU7UUFDZixXQUFXLENBQUMsTUFBTSxDQUFDLFNBQVMsRUFBRSxHQUFHLElBQUksQ0FBQyxDQUFDO0tBQ3hDO0FBQ0gsQ0FBQztBQUVELE1BQU0sVUFBVSxpQkFBaUIsQ0FBQyxJQUFZO0lBQzVDLE1BQU0sTUFBTSxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUMzQixPQUFPLENBQUMsR0FBRyxJQUFXLEVBQUUsRUFBRSxDQUFDLGtDQUFrQyxDQUFDLE1BQU0sRUFBRSxHQUFHLElBQUksQ0FBQyxDQUFDO0FBQ2pGLENBQUM7QUFFRCxNQUFNLFVBQVUsa0JBQWtCLENBQUMsRUFBNEI7SUFDN0QsVUFBVSxHQUFHLEVBQUUsQ0FBQztBQUNsQixDQUFDO0FBRUQsTUFBTSxVQUFVLG1CQUFtQixDQUFDLEVBQTRCO0lBQzlELFdBQVcsR0FBRyxFQUFFLENBQUM7QUFDbkIsQ0FBQztBQUVELE1BQU0sVUFBVSxVQUFVLENBQUMsR0FBVztJQUNwQyxLQUFLLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0FBQ3BCLENBQUM7QUFFRCxNQUFNLFVBQVUsWUFBWSxDQUFDLEdBQVc7SUFDdEMsT0FBTyxLQUFLLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0FBQzVCLENBQUMifQ== \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/log/index.d.ts b/circuits/.yalc/@aztec/foundation/dest/log/index.d.ts new file mode 100644 index 00000000000..c9547300ba1 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/log/index.d.ts @@ -0,0 +1,4 @@ +export * from './console.js'; +export * from './debug.js'; +export * from './log_history.js'; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/log/index.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/log/index.d.ts.map new file mode 100644 index 00000000000..569f86da655 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/log/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/log/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC"} \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/log/index.js b/circuits/.yalc/@aztec/foundation/dest/log/index.js new file mode 100644 index 00000000000..c46c2868238 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/log/index.js @@ -0,0 +1,4 @@ +export * from './console.js'; +export * from './debug.js'; +export * from './log_history.js'; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvbG9nL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLGNBQWMsY0FBYyxDQUFDO0FBQzdCLGNBQWMsWUFBWSxDQUFDO0FBQzNCLGNBQWMsa0JBQWtCLENBQUMifQ== \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/log/log_history.d.ts b/circuits/.yalc/@aztec/foundation/dest/log/log_history.d.ts new file mode 100644 index 00000000000..9f09979e1df --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/log/log_history.d.ts @@ -0,0 +1,8 @@ +export declare class LogHistory { + private logs; + enable(): void; + getLogs(last?: number): any[][]; + clear(count?: number): void; +} +export declare const logHistory: LogHistory; +//# sourceMappingURL=log_history.d.ts.map \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/log/log_history.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/log/log_history.d.ts.map new file mode 100644 index 00000000000..076cc677766 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/log/log_history.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"log_history.d.ts","sourceRoot":"","sources":["../../src/log/log_history.ts"],"names":[],"mappings":"AAEA,qBAAa,UAAU;IACrB,OAAO,CAAC,IAAI,CAAe;IAEpB,MAAM;IAMN,OAAO,CAAC,IAAI,SAAI;IAIhB,KAAK,CAAC,KAAK,SAAmB;CAGtC;AAED,eAAO,MAAM,UAAU,YAAmB,CAAC"} \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/log/log_history.js b/circuits/.yalc/@aztec/foundation/dest/log/log_history.js new file mode 100644 index 00000000000..9294d3dae1f --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/log/log_history.js @@ -0,0 +1,19 @@ +import { setPreDebugLogHook } from './debug.js'; +export class LogHistory { + constructor() { + this.logs = []; + } + enable() { + setPreDebugLogHook((...args) => { + this.logs.push([new Date().toISOString(), ...args]); + }); + } + getLogs(last = 0) { + return last ? this.logs.slice(-last) : this.logs; + } + clear(count = this.logs.length) { + this.logs = this.logs.slice(count); + } +} +export const logHistory = new LogHistory(); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9nX2hpc3RvcnkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvbG9nL2xvZ19oaXN0b3J5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLFlBQVksQ0FBQztBQUVoRCxNQUFNLE9BQU8sVUFBVTtJQUF2QjtRQUNVLFNBQUksR0FBWSxFQUFFLENBQUM7SUFlN0IsQ0FBQztJQWJRLE1BQU07UUFDWCxrQkFBa0IsQ0FBQyxDQUFDLEdBQUcsSUFBVyxFQUFFLEVBQUU7WUFDcEMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxJQUFJLElBQUksRUFBRSxDQUFDLFdBQVcsRUFBRSxFQUFFLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQztRQUN0RCxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFTSxPQUFPLENBQUMsSUFBSSxHQUFHLENBQUM7UUFDckIsT0FBTyxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUM7SUFDbkQsQ0FBQztJQUVNLEtBQUssQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNO1FBQ25DLElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDckMsQ0FBQztDQUNGO0FBRUQsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHLElBQUksVUFBVSxFQUFFLENBQUMifQ== \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/mutex/index.d.ts b/circuits/.yalc/@aztec/foundation/dest/mutex/index.d.ts new file mode 100644 index 00000000000..d393fc0d975 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/mutex/index.d.ts @@ -0,0 +1,16 @@ +import { MutexDatabase } from './mutex_database.js'; +export * from './mutex_database.js'; +export declare class Mutex { + private readonly db; + private readonly name; + private readonly timeout; + private readonly tryLockInterval; + private readonly pingInterval; + private id; + private pingTimeout; + constructor(db: MutexDatabase, name: string, timeout?: number, tryLockInterval?: number, pingInterval?: number); + lock(untilAcquired?: boolean): Promise; + unlock(): Promise; + private ping; +} +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/mutex/index.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/mutex/index.d.ts.map new file mode 100644 index 00000000000..18f819e06cc --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/mutex/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mutex/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,cAAc,qBAAqB,CAAC;AAEpC,qBAAa,KAAK;IAKd,OAAO,CAAC,QAAQ,CAAC,EAAE;IACnB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,YAAY;IAR/B,OAAO,CAAC,EAAE,CAAK;IACf,OAAO,CAAC,WAAW,CAAkB;gBAGlB,EAAE,EAAE,aAAa,EACjB,IAAI,EAAE,MAAM,EACZ,OAAO,SAAO,EACd,eAAe,SAAO,EACtB,YAAY,SAAO;IAGzB,IAAI,CAAC,aAAa,UAAO;IAezB,MAAM;YAML,IAAI;CAQnB"} \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/mutex/index.js b/circuits/.yalc/@aztec/foundation/dest/mutex/index.js new file mode 100644 index 00000000000..42d83559208 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/mutex/index.js @@ -0,0 +1,37 @@ +export * from './mutex_database.js'; +export class Mutex { + constructor(db, name, timeout = 5000, tryLockInterval = 2000, pingInterval = 2000) { + this.db = db; + this.name = name; + this.timeout = timeout; + this.tryLockInterval = tryLockInterval; + this.pingInterval = pingInterval; + this.id = 0; + } + async lock(untilAcquired = true) { + while (true) { + if (await this.db.acquireLock(this.name, this.timeout)) { + const id = this.id; + this.pingTimeout = setTimeout(() => this.ping(id), this.pingInterval); + return true; + } + if (!untilAcquired) { + return false; + } + await new Promise(resolve => setTimeout(resolve, this.tryLockInterval)); + } + } + async unlock() { + clearTimeout(this.pingTimeout); + this.id++; + await this.db.releaseLock(this.name); + } + async ping(id) { + if (id !== this.id) { + return; + } + await this.db.extendLock(this.name, this.timeout); + this.pingTimeout = setTimeout(() => this.ping(id), this.pingInterval); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvbXV0ZXgvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBRUEsY0FBYyxxQkFBcUIsQ0FBQztBQUVwQyxNQUFNLE9BQU8sS0FBSztJQUloQixZQUNtQixFQUFpQixFQUNqQixJQUFZLEVBQ1osVUFBVSxJQUFJLEVBQ2Qsa0JBQWtCLElBQUksRUFDdEIsZUFBZSxJQUFJO1FBSm5CLE9BQUUsR0FBRixFQUFFLENBQWU7UUFDakIsU0FBSSxHQUFKLElBQUksQ0FBUTtRQUNaLFlBQU8sR0FBUCxPQUFPLENBQU87UUFDZCxvQkFBZSxHQUFmLGVBQWUsQ0FBTztRQUN0QixpQkFBWSxHQUFaLFlBQVksQ0FBTztRQVI5QixPQUFFLEdBQUcsQ0FBQyxDQUFDO0lBU1osQ0FBQztJQUVHLEtBQUssQ0FBQyxJQUFJLENBQUMsYUFBYSxHQUFHLElBQUk7UUFDcEMsT0FBTyxJQUFJLEVBQUU7WUFDWCxJQUFJLE1BQU0sSUFBSSxDQUFDLEVBQUUsQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLEVBQUU7Z0JBQ3RELE1BQU0sRUFBRSxHQUFHLElBQUksQ0FBQyxFQUFFLENBQUM7Z0JBQ25CLElBQUksQ0FBQyxXQUFXLEdBQUcsVUFBVSxDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUUsSUFBSSxDQUFDLFlBQVksQ0FBQyxDQUFDO2dCQUN0RSxPQUFPLElBQUksQ0FBQzthQUNiO1lBRUQsSUFBSSxDQUFDLGFBQWEsRUFBRTtnQkFDbEIsT0FBTyxLQUFLLENBQUM7YUFDZDtZQUNELE1BQU0sSUFBSSxPQUFPLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxlQUFlLENBQUMsQ0FBQyxDQUFDO1NBQ3pFO0lBQ0gsQ0FBQztJQUVNLEtBQUssQ0FBQyxNQUFNO1FBQ2pCLFlBQVksQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUM7UUFDL0IsSUFBSSxDQUFDLEVBQUUsRUFBRSxDQUFDO1FBQ1YsTUFBTSxJQUFJLENBQUMsRUFBRSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDdkMsQ0FBQztJQUVPLEtBQUssQ0FBQyxJQUFJLENBQUMsRUFBVTtRQUMzQixJQUFJLEVBQUUsS0FBSyxJQUFJLENBQUMsRUFBRSxFQUFFO1lBQ2xCLE9BQU87U0FDUjtRQUVELE1BQU0sSUFBSSxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDbEQsSUFBSSxDQUFDLFdBQVcsR0FBRyxVQUFVLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsRUFBRSxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUM7SUFDeEUsQ0FBQztDQUNGIn0= \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/mutex/mutex_database.d.ts b/circuits/.yalc/@aztec/foundation/dest/mutex/mutex_database.d.ts new file mode 100644 index 00000000000..21278a90088 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/mutex/mutex_database.d.ts @@ -0,0 +1,6 @@ +export interface MutexDatabase { + acquireLock(name: string, timeout: number): Promise; + extendLock(name: string, timeout: number): Promise; + releaseLock(name: string): Promise; +} +//# sourceMappingURL=mutex_database.d.ts.map \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/mutex/mutex_database.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/mutex/mutex_database.d.ts.map new file mode 100644 index 00000000000..5303a4f3e94 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/mutex/mutex_database.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"mutex_database.d.ts","sourceRoot":"","sources":["../../src/mutex/mutex_database.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7D,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1C"} \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/mutex/mutex_database.js b/circuits/.yalc/@aztec/foundation/dest/mutex/mutex_database.js new file mode 100644 index 00000000000..5098e97826a --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/mutex/mutex_database.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibXV0ZXhfZGF0YWJhc2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvbXV0ZXgvbXV0ZXhfZGF0YWJhc2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiJ9 \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/retry/index.d.ts b/circuits/.yalc/@aztec/foundation/dest/retry/index.d.ts new file mode 100644 index 00000000000..d0dcd0cdab5 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/retry/index.d.ts @@ -0,0 +1,4 @@ +export declare function backoffGenerator(): Generator; +export declare function retry(fn: () => Promise, name?: string, backoff?: Generator): Promise; +export declare function retryUntil(fn: () => boolean | Promise, name?: string, timeout?: number, interval?: number): Promise; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/retry/index.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/retry/index.d.ts.map new file mode 100644 index 00000000000..96ad9671ea8 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/retry/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/retry/index.ts"],"names":[],"mappings":"AAGA,wBAAiB,gBAAgB,qCAMhC;AAED,wBAAsB,KAAK,CAAC,MAAM,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,SAAc,EAAE,OAAO,mCAAqB,mBAe9G;AAKD,wBAAsB,UAAU,CAAC,EAAE,EAAE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,EAAE,IAAI,SAAK,EAAE,OAAO,SAAI,EAAE,QAAQ,SAAI,iBAa1G"} \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/retry/index.js b/circuits/.yalc/@aztec/foundation/dest/retry/index.js new file mode 100644 index 00000000000..298cf0ea3d1 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/retry/index.js @@ -0,0 +1,42 @@ +import { sleep } from '../sleep/index.js'; +import { Timer } from '../timer/index.js'; +export function* backoffGenerator() { + const v = [1, 1, 1, 2, 4, 8, 16, 32, 64]; + let i = 0; + while (true) { + yield v[Math.min(i++, v.length - 1)]; + } +} +export async function retry(fn, name = 'Operation', backoff = backoffGenerator()) { + while (true) { + try { + return await fn(); + } + catch (err) { + const s = backoff.next().value; + if (s === undefined) { + throw err; + } + console.log(`${name} failed. Will retry in ${s}s...`); + console.log(err); + await sleep(s * 1000); + continue; + } + } +} +// Call `fn` repeatedly until it returns true or timeout. +// Both `interval` and `timeout` are seconds. +// Will never timeout if the value is 0. +export async function retryUntil(fn, name = '', timeout = 0, interval = 1) { + const timer = new Timer(); + while (true) { + if (await fn()) { + return; + } + await sleep(interval * 1000); + if (timeout && timer.s() > timeout) { + throw new Error(name ? `Timeout awaiting ${name}` : 'Timeout'); + } + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcmV0cnkvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQzFDLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUUxQyxNQUFNLFNBQVMsQ0FBQyxDQUFDLGdCQUFnQjtJQUMvQixNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDekMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ1YsT0FBTyxJQUFJLEVBQUU7UUFDWCxNQUFNLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQztLQUN0QztBQUNILENBQUM7QUFFRCxNQUFNLENBQUMsS0FBSyxVQUFVLEtBQUssQ0FBUyxFQUF5QixFQUFFLElBQUksR0FBRyxXQUFXLEVBQUUsT0FBTyxHQUFHLGdCQUFnQixFQUFFO0lBQzdHLE9BQU8sSUFBSSxFQUFFO1FBQ1gsSUFBSTtZQUNGLE9BQU8sTUFBTSxFQUFFLEVBQUUsQ0FBQztTQUNuQjtRQUFDLE9BQU8sR0FBUSxFQUFFO1lBQ2pCLE1BQU0sQ0FBQyxHQUFHLE9BQU8sQ0FBQyxJQUFJLEVBQUUsQ0FBQyxLQUFLLENBQUM7WUFDL0IsSUFBSSxDQUFDLEtBQUssU0FBUyxFQUFFO2dCQUNuQixNQUFNLEdBQUcsQ0FBQzthQUNYO1lBQ0QsT0FBTyxDQUFDLEdBQUcsQ0FBQyxHQUFHLElBQUksMEJBQTBCLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDdEQsT0FBTyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUNqQixNQUFNLEtBQUssQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUM7WUFDdEIsU0FBUztTQUNWO0tBQ0Y7QUFDSCxDQUFDO0FBRUQseURBQXlEO0FBQ3pELDZDQUE2QztBQUM3Qyx3Q0FBd0M7QUFDeEMsTUFBTSxDQUFDLEtBQUssVUFBVSxVQUFVLENBQUMsRUFBb0MsRUFBRSxJQUFJLEdBQUcsRUFBRSxFQUFFLE9BQU8sR0FBRyxDQUFDLEVBQUUsUUFBUSxHQUFHLENBQUM7SUFDekcsTUFBTSxLQUFLLEdBQUcsSUFBSSxLQUFLLEVBQUUsQ0FBQztJQUMxQixPQUFPLElBQUksRUFBRTtRQUNYLElBQUksTUFBTSxFQUFFLEVBQUUsRUFBRTtZQUNkLE9BQU87U0FDUjtRQUVELE1BQU0sS0FBSyxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUMsQ0FBQztRQUU3QixJQUFJLE9BQU8sSUFBSSxLQUFLLENBQUMsQ0FBQyxFQUFFLEdBQUcsT0FBTyxFQUFFO1lBQ2xDLE1BQU0sSUFBSSxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxvQkFBb0IsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDO1NBQ2hFO0tBQ0Y7QUFDSCxDQUFDIn0= \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/running-promise/index.d.ts b/circuits/.yalc/@aztec/foundation/dest/running-promise/index.d.ts new file mode 100644 index 00000000000..ee66a3515c5 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/running-promise/index.d.ts @@ -0,0 +1,17 @@ +export declare class RunningPromise { + private fn; + private pollingInterval; + private running; + private runningPromise; + private interruptPromise; + private interruptResolve; + constructor(fn: () => Promise, pollingInterval?: number); + /** + * Starts the running promise + */ + start(): void; + stop(): Promise; + private interruptableSleep; + isRunning(): boolean; +} +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/running-promise/index.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/running-promise/index.d.ts.map new file mode 100644 index 00000000000..8d941415038 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/running-promise/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/running-promise/index.ts"],"names":[],"mappings":"AAAA,qBAAa,cAAc;IAKb,OAAO,CAAC,EAAE;IAAuB,OAAO,CAAC,eAAe;IAJpE,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,cAAc,CAAqB;IAC3C,OAAO,CAAC,gBAAgB,CAAqB;IAC7C,OAAO,CAAC,gBAAgB,CAAY;gBAChB,EAAE,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,EAAU,eAAe,SAAQ;IAE5E;;OAEG;IACI,KAAK;IAaN,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YAMb,kBAAkB;IASzB,SAAS;CAGjB"} \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/running-promise/index.js b/circuits/.yalc/@aztec/foundation/dest/running-promise/index.js new file mode 100644 index 00000000000..d081b59f0ec --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/running-promise/index.js @@ -0,0 +1,41 @@ +export class RunningPromise { + constructor(fn, pollingInterval = 10000) { + this.fn = fn; + this.pollingInterval = pollingInterval; + this.running = false; + this.runningPromise = Promise.resolve(); + this.interruptPromise = Promise.resolve(); + this.interruptResolve = () => { }; + } + /** + * Starts the running promise + */ + start() { + this.running = true; + this.interruptPromise = new Promise(resolve => (this.interruptResolve = resolve)); + const poll = async () => { + while (this.running) { + await this.fn(); + await this.interruptableSleep(this.pollingInterval); + } + }; + this.runningPromise = poll(); + } + async stop() { + this.running = false; + this.interruptResolve(); + await this.runningPromise; + } + async interruptableSleep(timeInMs) { + let timeout; + const sleepPromise = new Promise(resolve => { + timeout = setTimeout(resolve, timeInMs); + }); + await Promise.race([sleepPromise, this.interruptPromise]); + clearTimeout(timeout); + } + isRunning() { + return this.running; + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcnVubmluZy1wcm9taXNlL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE1BQU0sT0FBTyxjQUFjO0lBS3pCLFlBQW9CLEVBQXVCLEVBQVUsa0JBQWtCLEtBQUs7UUFBeEQsT0FBRSxHQUFGLEVBQUUsQ0FBcUI7UUFBVSxvQkFBZSxHQUFmLGVBQWUsQ0FBUTtRQUpwRSxZQUFPLEdBQUcsS0FBSyxDQUFDO1FBQ2hCLG1CQUFjLEdBQUcsT0FBTyxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ25DLHFCQUFnQixHQUFHLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUNyQyxxQkFBZ0IsR0FBRyxHQUFHLEVBQUUsR0FBRSxDQUFDLENBQUM7SUFDMkMsQ0FBQztJQUVoRjs7T0FFRztJQUNJLEtBQUs7UUFDVixJQUFJLENBQUMsT0FBTyxHQUFHLElBQUksQ0FBQztRQUNwQixJQUFJLENBQUMsZ0JBQWdCLEdBQUcsSUFBSSxPQUFPLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxPQUFPLENBQUMsQ0FBQyxDQUFDO1FBRWxGLE1BQU0sSUFBSSxHQUFHLEtBQUssSUFBSSxFQUFFO1lBQ3RCLE9BQU8sSUFBSSxDQUFDLE9BQU8sRUFBRTtnQkFDbkIsTUFBTSxJQUFJLENBQUMsRUFBRSxFQUFFLENBQUM7Z0JBQ2hCLE1BQU0sSUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsQ0FBQzthQUNyRDtRQUNILENBQUMsQ0FBQztRQUNGLElBQUksQ0FBQyxjQUFjLEdBQUcsSUFBSSxFQUFFLENBQUM7SUFDL0IsQ0FBQztJQUVELEtBQUssQ0FBQyxJQUFJO1FBQ1IsSUFBSSxDQUFDLE9BQU8sR0FBRyxLQUFLLENBQUM7UUFDckIsSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUM7UUFDeEIsTUFBTSxJQUFJLENBQUMsY0FBYyxDQUFDO0lBQzVCLENBQUM7SUFFTyxLQUFLLENBQUMsa0JBQWtCLENBQUMsUUFBZ0I7UUFDL0MsSUFBSSxPQUF3QixDQUFDO1FBQzdCLE1BQU0sWUFBWSxHQUFHLElBQUksT0FBTyxDQUFDLE9BQU8sQ0FBQyxFQUFFO1lBQ3pDLE9BQU8sR0FBRyxVQUFVLENBQUMsT0FBTyxFQUFFLFFBQVEsQ0FBQyxDQUFDO1FBQzFDLENBQUMsQ0FBQyxDQUFDO1FBQ0gsTUFBTSxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsWUFBWSxFQUFFLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLENBQUM7UUFDMUQsWUFBWSxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ3hCLENBQUM7SUFFTSxTQUFTO1FBQ2QsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDO0lBQ3RCLENBQUM7Q0FDRiJ9 \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/serialize/deserializer.d.ts b/circuits/.yalc/@aztec/foundation/dest/serialize/deserializer.d.ts new file mode 100644 index 00000000000..dbc2905ec49 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/serialize/deserializer.d.ts @@ -0,0 +1,22 @@ +/// +export type DeserializeFn = (buf: Buffer, offset: number) => { + elem: T; + adv: number; +}; +export declare class Deserializer { + private buf; + private offset; + constructor(buf: Buffer, offset?: number); + bool(): boolean; + uInt32(): number; + int32(): number; + bigInt(width?: number): bigint; + vector(): Buffer; + buffer(width: number): Buffer; + string(): string; + date(): Date; + deserializeArray(fn: DeserializeFn): T[]; + exec(fn: DeserializeFn): T; + getOffset(): number; +} +//# sourceMappingURL=deserializer.d.ts.map \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/serialize/deserializer.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/serialize/deserializer.d.ts.map new file mode 100644 index 00000000000..487422cd010 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/serialize/deserializer.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"deserializer.d.ts","sourceRoot":"","sources":["../../src/serialize/deserializer.ts"],"names":[],"mappings":";AASA,MAAM,MAAM,aAAa,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK;IAAE,IAAI,EAAE,CAAC,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzF,qBAAa,YAAY;IACX,OAAO,CAAC,GAAG;IAAU,OAAO,CAAC,MAAM;gBAA3B,GAAG,EAAE,MAAM,EAAU,MAAM,SAAI;IAE5C,IAAI;IAIJ,MAAM;IAIN,KAAK;IAIL,MAAM,CAAC,KAAK,SAAK;IAIjB,MAAM;IAIN,MAAM,CAAC,KAAK,EAAE,MAAM;IAMpB,MAAM;IAIN,IAAI;IAIJ,gBAAgB,CAAC,CAAC,EAAE,EAAE,EAAE,aAAa,CAAC,CAAC,CAAC;IAIxC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC;IAMhC,SAAS;CAGjB"} \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/serialize/deserializer.js b/circuits/.yalc/@aztec/foundation/dest/serialize/deserializer.js new file mode 100644 index 00000000000..e756f8a4cc8 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/serialize/deserializer.js @@ -0,0 +1,45 @@ +import { deserializeArrayFromVector, deserializeBigInt, deserializeBool, deserializeBufferFromVector, deserializeInt32, deserializeUInt32, } from './free_funcs.js'; +export class Deserializer { + constructor(buf, offset = 0) { + this.buf = buf; + this.offset = offset; + } + bool() { + return this.exec(deserializeBool) ? true : false; + } + uInt32() { + return this.exec(deserializeUInt32); + } + int32() { + return this.exec(deserializeInt32); + } + bigInt(width = 32) { + return this.exec((buf, offset) => deserializeBigInt(buf, offset, width)); + } + vector() { + return this.exec(deserializeBufferFromVector); + } + buffer(width) { + const buf = this.buf.slice(this.offset, this.offset + width); + this.offset += width; + return buf; + } + string() { + return this.vector().toString(); + } + date() { + return new Date(Number(this.bigInt(8))); + } + deserializeArray(fn) { + return this.exec((buf, offset) => deserializeArrayFromVector(fn, buf, offset)); + } + exec(fn) { + const { elem, adv } = fn(this.buf, this.offset); + this.offset += adv; + return elem; + } + getOffset() { + return this.offset; + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVzZXJpYWxpemVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NlcmlhbGl6ZS9kZXNlcmlhbGl6ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLDBCQUEwQixFQUMxQixpQkFBaUIsRUFDakIsZUFBZSxFQUNmLDJCQUEyQixFQUMzQixnQkFBZ0IsRUFDaEIsaUJBQWlCLEdBQ2xCLE1BQU0saUJBQWlCLENBQUM7QUFJekIsTUFBTSxPQUFPLFlBQVk7SUFDdkIsWUFBb0IsR0FBVyxFQUFVLFNBQVMsQ0FBQztRQUEvQixRQUFHLEdBQUgsR0FBRyxDQUFRO1FBQVUsV0FBTSxHQUFOLE1BQU0sQ0FBSTtJQUFHLENBQUM7SUFFaEQsSUFBSTtRQUNULE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUM7SUFDbkQsQ0FBQztJQUVNLE1BQU07UUFDWCxPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsaUJBQWlCLENBQUMsQ0FBQztJQUN0QyxDQUFDO0lBRU0sS0FBSztRQUNWLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO0lBQ3JDLENBQUM7SUFFTSxNQUFNLENBQUMsS0FBSyxHQUFHLEVBQUU7UUFDdEIsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBVyxFQUFFLE1BQWMsRUFBRSxFQUFFLENBQUMsaUJBQWlCLENBQUMsR0FBRyxFQUFFLE1BQU0sRUFBRSxLQUFLLENBQUMsQ0FBQyxDQUFDO0lBQzNGLENBQUM7SUFFTSxNQUFNO1FBQ1gsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLDJCQUEyQixDQUFDLENBQUM7SUFDaEQsQ0FBQztJQUVNLE1BQU0sQ0FBQyxLQUFhO1FBQ3pCLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLE1BQU0sR0FBRyxLQUFLLENBQUMsQ0FBQztRQUM3RCxJQUFJLENBQUMsTUFBTSxJQUFJLEtBQUssQ0FBQztRQUNyQixPQUFPLEdBQUcsQ0FBQztJQUNiLENBQUM7SUFFTSxNQUFNO1FBQ1gsT0FBTyxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxFQUFFLENBQUM7SUFDbEMsQ0FBQztJQUVNLElBQUk7UUFDVCxPQUFPLElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUMxQyxDQUFDO0lBRU0sZ0JBQWdCLENBQUksRUFBb0I7UUFDN0MsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBVyxFQUFFLE1BQWMsRUFBRSxFQUFFLENBQUMsMEJBQTBCLENBQUMsRUFBRSxFQUFFLEdBQUcsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDO0lBQ2pHLENBQUM7SUFFTSxJQUFJLENBQUksRUFBb0I7UUFDakMsTUFBTSxFQUFFLElBQUksRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDaEQsSUFBSSxDQUFDLE1BQU0sSUFBSSxHQUFHLENBQUM7UUFDbkIsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRU0sU0FBUztRQUNkLE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQztJQUNyQixDQUFDO0NBQ0YifQ== \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/serialize/free_funcs.d.ts b/circuits/.yalc/@aztec/foundation/dest/serialize/free_funcs.d.ts new file mode 100644 index 00000000000..99b540b5172 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/serialize/free_funcs.d.ts @@ -0,0 +1,42 @@ +/// +export declare function boolToByte(b: boolean): Buffer; +export declare function numToUInt32LE(n: number, bufferSize?: number): Buffer; +export declare function numToUInt32BE(n: number, bufferSize?: number): Buffer; +export declare function numToInt32BE(n: number, bufferSize?: number): Buffer; +export declare function numToUInt8(n: number): Buffer; +export declare function serializeBufferToVector(buf: Buffer): Buffer; +export declare function serializeBigInt(n: bigint, width?: number): Buffer; +export declare function deserializeBigInt(buf: Buffer, offset?: number, width?: number): { + elem: bigint; + adv: number; +}; +export declare function serializeDate(date: Date): Buffer; +export declare function deserializeBufferFromVector(vector: Buffer, offset?: number): { + elem: Buffer; + adv: number; +}; +export declare function deserializeBool(buf: Buffer, offset?: number): { + elem: number; + adv: number; +}; +export declare function deserializeUInt32(buf: Buffer, offset?: number): { + elem: number; + adv: number; +}; +export declare function deserializeInt32(buf: Buffer, offset?: number): { + elem: number; + adv: number; +}; +export declare function deserializeField(buf: Buffer, offset?: number): { + elem: Buffer; + adv: number; +}; +export declare function serializeBufferArrayToVector(arr: Buffer[]): Buffer; +export declare function deserializeArrayFromVector(deserialize: (buf: Buffer, offset: number) => { + elem: T; + adv: number; +}, vector: Buffer, offset?: number): { + elem: T[]; + adv: number; +}; +//# sourceMappingURL=free_funcs.d.ts.map \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/serialize/free_funcs.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/serialize/free_funcs.d.ts.map new file mode 100644 index 00000000000..29592f8e080 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/serialize/free_funcs.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"free_funcs.d.ts","sourceRoot":"","sources":["../../src/serialize/free_funcs.ts"],"names":[],"mappings":";AAGA,wBAAgB,UAAU,CAAC,CAAC,EAAE,OAAO,UAIpC;AAGD,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,UAAU,SAAI,UAItD;AAGD,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,UAAU,SAAI,UAItD;AAGD,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,UAAU,SAAI,UAIrD;AAGD,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,UAKnC;AAGD,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,UAIlD;AAED,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,SAAK,UAEpD;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,SAAI,EAAE,KAAK,SAAK;;;EAEpE;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,UAEvC;AAED,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,SAAI;;;EAIrE;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,SAAI;;;EAGtD;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,SAAI;;;EAGxD;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,SAAI;;;EAGvD;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,SAAI;;;EAGvD;AAGD,wBAAgB,4BAA4B,CAAC,GAAG,EAAE,MAAM,EAAE,UAIzD;AAED,wBAAgB,0BAA0B,CAAC,CAAC,EAC1C,WAAW,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK;IAAE,IAAI,EAAE,CAAC,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,EACtE,MAAM,EAAE,MAAM,EACd,MAAM,SAAI;;;EAYX"} \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/serialize/free_funcs.js b/circuits/.yalc/@aztec/foundation/dest/serialize/free_funcs.js new file mode 100644 index 00000000000..127f3df453f --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/serialize/free_funcs.js @@ -0,0 +1,87 @@ +import { toBigIntBE, toBufferBE } from '../bigint-buffer/index.js'; +// For serializing bool. +export function boolToByte(b) { + const buf = Buffer.alloc(1); + buf.writeUInt8(b ? 1 : 0); + return buf; +} +// For serializing numbers to 32 bit little-endian form. +export function numToUInt32LE(n, bufferSize = 4) { + const buf = Buffer.alloc(bufferSize); + buf.writeUInt32LE(n, bufferSize - 4); + return buf; +} +// For serializing numbers to 32 bit big-endian form. +export function numToUInt32BE(n, bufferSize = 4) { + const buf = Buffer.alloc(bufferSize); + buf.writeUInt32BE(n, bufferSize - 4); + return buf; +} +// For serializing signed numbers to 32 bit big-endian form. +export function numToInt32BE(n, bufferSize = 4) { + const buf = Buffer.alloc(bufferSize); + buf.writeInt32BE(n, bufferSize - 4); + return buf; +} +// For serializing numbers to 32 bit big-endian form. +export function numToUInt8(n) { + const bufferSize = 1; + const buf = Buffer.alloc(bufferSize); + buf.writeUInt8(n, 0); + return buf; +} +// For serializing a buffer as a vector. +export function serializeBufferToVector(buf) { + const lengthBuf = Buffer.alloc(4); + lengthBuf.writeUInt32BE(buf.length, 0); + return Buffer.concat([lengthBuf, buf]); +} +export function serializeBigInt(n, width = 32) { + return toBufferBE(n, width); +} +export function deserializeBigInt(buf, offset = 0, width = 32) { + return { elem: toBigIntBE(buf.slice(offset, offset + width)), adv: width }; +} +export function serializeDate(date) { + return serializeBigInt(BigInt(date.getTime()), 8); +} +export function deserializeBufferFromVector(vector, offset = 0) { + const length = vector.readUInt32BE(offset); + const adv = 4 + length; + return { elem: vector.slice(offset + 4, offset + adv), adv }; +} +export function deserializeBool(buf, offset = 0) { + const adv = 1; + return { elem: buf.readUInt8(offset), adv }; +} +export function deserializeUInt32(buf, offset = 0) { + const adv = 4; + return { elem: buf.readUInt32BE(offset), adv }; +} +export function deserializeInt32(buf, offset = 0) { + const adv = 4; + return { elem: buf.readInt32BE(offset), adv }; +} +export function deserializeField(buf, offset = 0) { + const adv = 32; + return { elem: buf.slice(offset, offset + adv), adv }; +} +// For serializing an array of fixed length elements. +export function serializeBufferArrayToVector(arr) { + const lengthBuf = Buffer.alloc(4); + lengthBuf.writeUInt32BE(arr.length, 0); + return Buffer.concat([lengthBuf, ...arr]); +} +export function deserializeArrayFromVector(deserialize, vector, offset = 0) { + let pos = offset; + const size = vector.readUInt32BE(pos); + pos += 4; + const arr = new Array(size); + for (let i = 0; i < size; ++i) { + const { elem, adv } = deserialize(vector, pos); + pos += adv; + arr[i] = elem; + } + return { elem: arr, adv: pos - offset }; +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnJlZV9mdW5jcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zZXJpYWxpemUvZnJlZV9mdW5jcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLFVBQVUsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBRW5FLHdCQUF3QjtBQUN4QixNQUFNLFVBQVUsVUFBVSxDQUFDLENBQVU7SUFDbkMsTUFBTSxHQUFHLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUM1QixHQUFHLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUMxQixPQUFPLEdBQUcsQ0FBQztBQUNiLENBQUM7QUFFRCx3REFBd0Q7QUFDeEQsTUFBTSxVQUFVLGFBQWEsQ0FBQyxDQUFTLEVBQUUsVUFBVSxHQUFHLENBQUM7SUFDckQsTUFBTSxHQUFHLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUNyQyxHQUFHLENBQUMsYUFBYSxDQUFDLENBQUMsRUFBRSxVQUFVLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDckMsT0FBTyxHQUFHLENBQUM7QUFDYixDQUFDO0FBRUQscURBQXFEO0FBQ3JELE1BQU0sVUFBVSxhQUFhLENBQUMsQ0FBUyxFQUFFLFVBQVUsR0FBRyxDQUFDO0lBQ3JELE1BQU0sR0FBRyxHQUFHLE1BQU0sQ0FBQyxLQUFLLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDckMsR0FBRyxDQUFDLGFBQWEsQ0FBQyxDQUFDLEVBQUUsVUFBVSxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQ3JDLE9BQU8sR0FBRyxDQUFDO0FBQ2IsQ0FBQztBQUVELDREQUE0RDtBQUM1RCxNQUFNLFVBQVUsWUFBWSxDQUFDLENBQVMsRUFBRSxVQUFVLEdBQUcsQ0FBQztJQUNwRCxNQUFNLEdBQUcsR0FBRyxNQUFNLENB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 \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/serialize/index.d.ts b/circuits/.yalc/@aztec/foundation/dest/serialize/index.d.ts new file mode 100644 index 00000000000..f9e4a26e65e --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/serialize/index.d.ts @@ -0,0 +1,4 @@ +export * from './free_funcs.js'; +export * from './deserializer.js'; +export * from './serializer.js'; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/serialize/index.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/serialize/index.d.ts.map new file mode 100644 index 00000000000..c0d8edbe7b0 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/serialize/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/serialize/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC"} \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/serialize/index.js b/circuits/.yalc/@aztec/foundation/dest/serialize/index.js new file mode 100644 index 00000000000..88f802933fa --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/serialize/index.js @@ -0,0 +1,4 @@ +export * from './free_funcs.js'; +export * from './deserializer.js'; +export * from './serializer.js'; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VyaWFsaXplL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLGNBQWMsaUJBQWlCLENBQUM7QUFDaEMsY0FBYyxtQkFBbUIsQ0FBQztBQUNsQyxjQUFjLGlCQUFpQixDQUFDIn0= \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/serialize/serializer.d.ts b/circuits/.yalc/@aztec/foundation/dest/serialize/serializer.d.ts new file mode 100644 index 00000000000..e829f2a6b6c --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/serialize/serializer.d.ts @@ -0,0 +1,25 @@ +/// +export declare class Serializer { + private buf; + constructor(); + bool(bool: boolean): void; + uInt32(num: number): void; + int32(num: number): void; + bigInt(num: bigint): void; + /** + * The given buffer is of variable length. Prefixes the buffer with its length. + */ + vector(buf: Buffer): void; + /** + * Directly serializes a buffer that maybe of fixed, or variable length. + * It is assumed the corresponding deserialize function will handle variable length data, thus the length + * does not need to be prefixed here. + * If serializing a raw, variable length buffer, use vector(). + */ + buffer(buf: Buffer): void; + string(str: string): void; + date(date: Date): void; + getBuffer(): Buffer; + serializeArray(arr: T[]): void; +} +//# sourceMappingURL=serializer.d.ts.map \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/serialize/serializer.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/serialize/serializer.d.ts.map new file mode 100644 index 00000000000..7581c879409 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/serialize/serializer.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"serializer.d.ts","sourceRoot":"","sources":["../../src/serialize/serializer.ts"],"names":[],"mappings":";AAYA,qBAAa,UAAU;IACrB,OAAO,CAAC,GAAG,CAAgB;;IAIpB,IAAI,CAAC,IAAI,EAAE,OAAO;IAIlB,MAAM,CAAC,GAAG,EAAE,MAAM;IAIlB,KAAK,CAAC,GAAG,EAAE,MAAM;IAIjB,MAAM,CAAC,GAAG,EAAE,MAAM;IAIzB;;OAEG;IACI,MAAM,CAAC,GAAG,EAAE,MAAM;IAIzB;;;;;OAKG;IACI,MAAM,CAAC,GAAG,EAAE,MAAM;IAIlB,MAAM,CAAC,GAAG,EAAE,MAAM;IAIlB,IAAI,CAAC,IAAI,EAAE,IAAI;IAIf,SAAS;IAIT,cAAc,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE;CAGlC"} \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/serialize/serializer.js b/circuits/.yalc/@aztec/foundation/dest/serialize/serializer.js new file mode 100644 index 00000000000..9da91af001e --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/serialize/serializer.js @@ -0,0 +1,48 @@ +import { serializeBufferArrayToVector } from './index.js'; +import { boolToByte, numToInt32BE, numToUInt32BE, serializeBigInt, serializeBufferToVector, serializeDate, } from './free_funcs.js'; +// export type DeserializeFn = (buf: Buffer, offset: number) => { elem: T; adv: number }; +export class Serializer { + constructor() { + this.buf = []; + } + bool(bool) { + this.buf.push(boolToByte(bool)); + } + uInt32(num) { + this.buf.push(numToUInt32BE(num)); + } + int32(num) { + this.buf.push(numToInt32BE(num)); + } + bigInt(num) { + this.buf.push(serializeBigInt(num)); + } + /** + * The given buffer is of variable length. Prefixes the buffer with its length. + */ + vector(buf) { + this.buf.push(serializeBufferToVector(buf)); + } + /** + * Directly serializes a buffer that maybe of fixed, or variable length. + * It is assumed the corresponding deserialize function will handle variable length data, thus the length + * does not need to be prefixed here. + * If serializing a raw, variable length buffer, use vector(). + */ + buffer(buf) { + this.buf.push(buf); + } + string(str) { + this.vector(Buffer.from(str)); + } + date(date) { + this.buf.push(serializeDate(date)); + } + getBuffer() { + return Buffer.concat(this.buf); + } + serializeArray(arr) { + this.buf.push(serializeBufferArrayToVector(arr.map((e) => e.toBuffer()))); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VyaWFsaXplci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zZXJpYWxpemUvc2VyaWFsaXplci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsNEJBQTRCLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFDMUQsT0FBTyxFQUNMLFVBQVUsRUFDVixZQUFZLEVBQ1osYUFBYSxFQUNiLGVBQWUsRUFDZix1QkFBdUIsRUFDdkIsYUFBYSxHQUNkLE1BQU0saUJBQWlCLENBQUM7QUFFekIsNEZBQTRGO0FBRTVGLE1BQU0sT0FBTyxVQUFVO0lBR3JCO1FBRlEsUUFBRyxHQUFhLEVBQUUsQ0FBQztJQUVaLENBQUM7SUFFVCxJQUFJLENBQUMsSUFBYTtRQUN2QixJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztJQUNsQyxDQUFDO0lBRU0sTUFBTSxDQUFDLEdBQVc7UUFDdkIsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDcEMsQ0FBQztJQUVNLEtBQUssQ0FBQyxHQUFXO1FBQ3RCLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQ25DLENBQUM7SUFFTSxNQUFNLENBQUMsR0FBVztRQUN2QixJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUN0QyxDQUFDO0lBRUQ7O09BRUc7SUFDSSxNQUFNLENBQUMsR0FBVztRQUN2QixJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyx1QkFBdUIsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQzlDLENBQUM7SUFFRDs7Ozs7T0FLRztJQUNJLE1BQU0sQ0FBQyxHQUFXO1FBQ3ZCLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ3JCLENBQUM7SUFFTSxNQUFNLENBQUMsR0FBVztRQUN2QixJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUNoQyxDQUFDO0lBRU0sSUFBSSxDQUFDLElBQVU7UUFDcEIsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDckMsQ0FBQztJQUVNLFNBQVM7UUFDZCxPQUFPLE1BQU0sQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ2pDLENBQUM7SUFFTSxjQUFjLENBQUksR0FBUTtRQUMvQixJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyw0QkFBNEIsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBTSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDakYsQ0FBQztDQUNGIn0= \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/sleep/index.d.ts b/circuits/.yalc/@aztec/foundation/dest/sleep/index.d.ts new file mode 100644 index 00000000000..8b419d97d81 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/sleep/index.d.ts @@ -0,0 +1,9 @@ +export declare class InterruptableSleep { + private interruptResolve; + private interruptPromise; + private timeouts; + sleep(ms: number): Promise; + interrupt(sleepShouldThrow?: boolean): void; +} +export declare function sleep(ms: number): Promise; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/sleep/index.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/sleep/index.d.ts.map new file mode 100644 index 00000000000..abe0a5cb4a5 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/sleep/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sleep/index.ts"],"names":[],"mappings":"AAEA,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,gBAAgB,CAA4C;IACpE,OAAO,CAAC,gBAAgB,CAAsE;IAC9F,OAAO,CAAC,QAAQ,CAAwB;IAE3B,KAAK,CAAC,EAAE,EAAE,MAAM;IAYtB,SAAS,CAAC,gBAAgB,UAAQ;CAI1C;AAED,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,oBAE/B"} \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/sleep/index.js b/circuits/.yalc/@aztec/foundation/dest/sleep/index.js new file mode 100644 index 00000000000..e0cf2af83fa --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/sleep/index.js @@ -0,0 +1,27 @@ +import { InterruptError } from '../errors/index.js'; +export class InterruptableSleep { + constructor() { + this.interruptResolve = () => { }; + this.interruptPromise = new Promise(resolve => (this.interruptResolve = resolve)); + this.timeouts = []; + } + async sleep(ms) { + let timeout; + const promise = new Promise(resolve => (timeout = setTimeout(() => resolve(false), ms))); + this.timeouts.push(timeout); + const shouldThrow = await Promise.race([promise, this.interruptPromise]); + clearTimeout(timeout); + this.timeouts.splice(this.timeouts.indexOf(timeout), 1); + if (shouldThrow) { + throw new InterruptError('Interrupted.'); + } + } + interrupt(sleepShouldThrow = false) { + this.interruptResolve(sleepShouldThrow); + this.interruptPromise = new Promise(resolve => (this.interruptResolve = resolve)); + } +} +export function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2xlZXAvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBRXBELE1BQU0sT0FBTyxrQkFBa0I7SUFBL0I7UUFDVSxxQkFBZ0IsR0FBbUMsR0FBRyxFQUFFLEdBQUUsQ0FBQyxDQUFDO1FBQzVELHFCQUFnQixHQUFHLElBQUksT0FBTyxDQUFVLE9BQU8sQ0FBQyxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsZ0JBQWdCLEdBQUcsT0FBTyxDQUFDLENBQUMsQ0FBQztRQUN0RixhQUFRLEdBQXFCLEVBQUUsQ0FBQztJQWtCMUMsQ0FBQztJQWhCUSxLQUFLLENBQUMsS0FBSyxDQUFDLEVBQVU7UUFDM0IsSUFBSSxPQUF3QixDQUFDO1FBQzdCLE1BQU0sT0FBTyxHQUFHLElBQUksT0FBTyxDQUFVLE9BQU8sQ0FBQyxFQUFFLENBQUMsQ0FBQyxPQUFPLEdBQUcsVUFBVSxDQUFDLEdBQUcsRUFBRSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDbEcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDNUIsTUFBTSxXQUFXLEdBQUcsTUFBTSxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLENBQUM7UUFDekUsWUFBWSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ3RCLElBQUksQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBQ3hELElBQUksV0FBVyxFQUFFO1lBQ2YsTUFBTSxJQUFJLGNBQWMsQ0FBQyxjQUFjLENBQUMsQ0FBQztTQUMxQztJQUNILENBQUM7SUFFTSxTQUFTLENBQUMsZ0JBQWdCLEdBQUcsS0FBSztRQUN2QyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztRQUN4QyxJQUFJLENBQUMsZ0JBQWdCLEdBQUcsSUFBSSxPQUFPLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxPQUFPLENBQUMsQ0FBQyxDQUFDO0lBQ3BGLENBQUM7Q0FDRjtBQUVELE1BQU0sVUFBVSxLQUFLLENBQUMsRUFBVTtJQUM5QixPQUFPLElBQUksT0FBTyxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsVUFBVSxDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDO0FBQ3pELENBQUMifQ== \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/timer/index.d.ts b/circuits/.yalc/@aztec/foundation/dest/timer/index.d.ts new file mode 100644 index 00000000000..5ca5635c4f4 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/timer/index.d.ts @@ -0,0 +1,3 @@ +export { TimeoutTask } from './timeout.js'; +export { Timer } from './timer.js'; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/timer/index.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/timer/index.d.ts.map new file mode 100644 index 00000000000..41d9b6bf1e7 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/timer/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/timer/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC"} \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/timer/index.js b/circuits/.yalc/@aztec/foundation/dest/timer/index.js new file mode 100644 index 00000000000..a2ac138c513 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/timer/index.js @@ -0,0 +1,3 @@ +export { TimeoutTask } from './timeout.js'; +export { Timer } from './timer.js'; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdGltZXIvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUMzQyxPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0sWUFBWSxDQUFDIn0= \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/timer/timeout.d.ts b/circuits/.yalc/@aztec/foundation/dest/timer/timeout.d.ts new file mode 100644 index 00000000000..f15b8df3b73 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/timer/timeout.d.ts @@ -0,0 +1,13 @@ +export declare class TimeoutTask { + private fn; + private timeout; + private interruptPromise; + private interrupt; + private totalTime; + constructor(fn: () => Promise, timeout?: number, fnName?: string); + exec(): Promise; + getInterruptPromise(): Promise; + getTime(): number; +} +export declare const executeTimeout: (fn: () => Promise, timeout?: number, fnName?: string) => Promise; +//# sourceMappingURL=timeout.d.ts.map \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/timer/timeout.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/timer/timeout.d.ts.map new file mode 100644 index 00000000000..1ba0f91854e --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/timer/timeout.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"timeout.d.ts","sourceRoot":"","sources":["../../src/timer/timeout.ts"],"names":[],"mappings":"AAAA,qBAAa,WAAW,CAAC,CAAC;IAKZ,OAAO,CAAC,EAAE;IAAoB,OAAO,CAAC,OAAO;IAJzD,OAAO,CAAC,gBAAgB,CAAgB;IACxC,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,SAAS,CAAK;gBAEF,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAU,OAAO,SAAI,EAAE,MAAM,SAAK;IAM7D,IAAI;IAYV,mBAAmB;IAInB,OAAO;CAGf;AAED,eAAO,MAAM,cAAc,4EAG1B,CAAC"} \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/timer/timeout.js b/circuits/.yalc/@aztec/foundation/dest/timer/timeout.js new file mode 100644 index 00000000000..aaa9a39173a --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/timer/timeout.js @@ -0,0 +1,34 @@ +export class TimeoutTask { + constructor(fn, timeout = 0, fnName = '') { + this.fn = fn; + this.timeout = timeout; + this.interrupt = () => { }; + this.totalTime = 0; + this.interruptPromise = new Promise((_, reject) => { + this.interrupt = () => reject(new Error(`Timeout${fnName ? ` running ${fnName}` : ''} after ${timeout}ms.`)); + }); + } + async exec() { + const interruptTimeout = !this.timeout ? 0 : setTimeout(this.interrupt, this.timeout); + try { + const start = Date.now(); + const result = await Promise.race([this.fn(), this.interruptPromise]); + this.totalTime = Date.now() - start; + return result; + } + finally { + clearTimeout(interruptTimeout); + } + } + getInterruptPromise() { + return this.interruptPromise; + } + getTime() { + return this.totalTime; + } +} +export const executeTimeout = async (fn, timeout = 0, fnName = '') => { + const task = new TimeoutTask(fn, timeout, fnName); + return await task.exec(); +}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGltZW91dC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90aW1lci90aW1lb3V0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE1BQU0sT0FBTyxXQUFXO0lBS3RCLFlBQW9CLEVBQW9CLEVBQVUsVUFBVSxDQUFDLEVBQUUsTUFBTSxHQUFHLEVBQUU7UUFBdEQsT0FBRSxHQUFGLEVBQUUsQ0FBa0I7UUFBVSxZQUFPLEdBQVAsT0FBTyxDQUFJO1FBSHJELGNBQVMsR0FBRyxHQUFHLEVBQUUsR0FBRSxDQUFDLENBQUM7UUFDckIsY0FBUyxHQUFHLENBQUMsQ0FBQztRQUdwQixJQUFJLENBQUMsZ0JBQWdCLEdBQUcsSUFBSSxPQUFPLENBQUksQ0FBQyxDQUFDLEVBQUUsTUFBTSxFQUFFLEVBQUU7WUFDbkQsSUFBSSxDQUFDLFNBQVMsR0FBRyxHQUFHLEVBQUUsQ0FBQyxNQUFNLENBQUMsSUFBSSxLQUFLLENBQUMsVUFBVSxNQUFNLENBQUMsQ0FBQyxDQUFDLFlBQVksTUFBTSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsVUFBVSxPQUFPLEtBQUssQ0FBQyxDQUFDLENBQUM7UUFDL0csQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRU0sS0FBSyxDQUFDLElBQUk7UUFDZixNQUFNLGdCQUFnQixHQUFHLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDdEYsSUFBSTtZQUNGLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztZQUN6QixNQUFNLE1BQU0sR0FBRyxNQUFNLE9BQU8sQ0FBQyxJQUFJLENBQUksQ0FBQyxJQUFJLENBQUMsRUFBRSxFQUFFLEVBQUUsSUFBSSxDQUFDLGdCQUFnQixDQUFDLENBQUMsQ0FBQztZQUN6RSxJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsR0FBRyxLQUFLLENBQUM7WUFDcEMsT0FBTyxNQUFNLENBQUM7U0FDZjtnQkFBUztZQUNSLFlBQVksQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO1NBQ2hDO0lBQ0gsQ0FBQztJQUVNLG1CQUFtQjtRQUN4QixPQUFPLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQztJQUMvQixDQUFDO0lBRU0sT0FBTztRQUNaLE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQztJQUN4QixDQUFDO0NBQ0Y7QUFFRCxNQUFNLENBQUMsTUFBTSxjQUFjLEdBQUcsS0FBSyxFQUFLLEVBQW9CLEVBQUUsT0FBTyxHQUFHLENBQUMsRUFBRSxNQUFNLEdBQUcsRUFBRSxFQUFFLEVBQUU7SUFDeEYsTUFBTSxJQUFJLEdBQUcsSUFBSSxXQUFXLENBQUMsRUFBRSxFQUFFLE9BQU8sRUFBRSxNQUFNLENBQUMsQ0FBQztJQUNsRCxPQUFPLE1BQU0sSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO0FBQzNCLENBQUMsQ0FBQyJ9 \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/timer/timer.d.ts b/circuits/.yalc/@aztec/foundation/dest/timer/timer.d.ts new file mode 100644 index 00000000000..963906ca853 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/timer/timer.d.ts @@ -0,0 +1,7 @@ +export declare class Timer { + private start; + constructor(); + ms(): number; + s(): number; +} +//# sourceMappingURL=timer.d.ts.map \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/timer/timer.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/timer/timer.d.ts.map new file mode 100644 index 00000000000..40850fe10d4 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/timer/timer.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"timer.d.ts","sourceRoot":"","sources":["../../src/timer/timer.ts"],"names":[],"mappings":"AAAA,qBAAa,KAAK;IAChB,OAAO,CAAC,KAAK,CAAS;;IAMf,EAAE;IAIF,CAAC;CAGT"} \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/timer/timer.js b/circuits/.yalc/@aztec/foundation/dest/timer/timer.js new file mode 100644 index 00000000000..470478b2f72 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/timer/timer.js @@ -0,0 +1,12 @@ +export class Timer { + constructor() { + this.start = new Date().getTime(); + } + ms() { + return new Date().getTime() - this.start; + } + s() { + return (new Date().getTime() - this.start) / 1000; + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGltZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdGltZXIvdGltZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsTUFBTSxPQUFPLEtBQUs7SUFHaEI7UUFDRSxJQUFJLENBQUMsS0FBSyxHQUFHLElBQUksSUFBSSxFQUFFLENBQUMsT0FBTyxFQUFFLENBQUM7SUFDcEMsQ0FBQztJQUVNLEVBQUU7UUFDUCxPQUFPLElBQUksSUFBSSxFQUFFLENBQUMsT0FBTyxFQUFFLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQztJQUMzQyxDQUFDO0lBRU0sQ0FBQztRQUNOLE9BQU8sQ0FBQyxJQUFJLElBQUksRUFBRSxDQUFDLE9BQU8sRUFBRSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxJQUFJLENBQUM7SUFDcEQsQ0FBQztDQUNGIn0= \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/index.d.ts b/circuits/.yalc/@aztec/foundation/dest/transport/browser/index.d.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/index.d.ts rename to circuits/.yalc/@aztec/foundation/dest/transport/browser/index.d.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/index.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/transport/browser/index.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/index.d.ts.map rename to circuits/.yalc/@aztec/foundation/dest/transport/browser/index.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/index.js b/circuits/.yalc/@aztec/foundation/dest/transport/browser/index.js similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/index.js rename to circuits/.yalc/@aztec/foundation/dest/transport/browser/index.js diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/message_port_socket.d.ts b/circuits/.yalc/@aztec/foundation/dest/transport/browser/message_port_socket.d.ts similarity index 52% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/message_port_socket.d.ts rename to circuits/.yalc/@aztec/foundation/dest/transport/browser/message_port_socket.d.ts index 65fcce26e3e..4f8c65248ed 100644 --- a/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/message_port_socket.d.ts +++ b/circuits/.yalc/@aztec/foundation/dest/transport/browser/message_port_socket.d.ts @@ -4,25 +4,9 @@ import { Socket } from '../interface/socket.js'; */ export declare class MessagePortSocket implements Socket { private port; - /** - * Create a MessagePortSocket. - * @param port - MessagePort object to wrap. - */ constructor(port: MessagePort); - /** - * Send a message over our message port. - * @param msg - The message. - * @param transfer - Objects to transfer ownership of. - */ send(msg: any, transfer?: Transferable[]): Promise; - /** - * Add a message handler. - * @param cb - The handler. - */ registerHandler(cb: (msg: any) => any): void; - /** - * Close this message port. - */ close(): void; } //# sourceMappingURL=message_port_socket.d.ts.map \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/transport/browser/message_port_socket.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/transport/browser/message_port_socket.d.ts.map new file mode 100644 index 00000000000..de2dc85bdbb --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/transport/browser/message_port_socket.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"message_port_socket.d.ts","sourceRoot":"","sources":["../../../src/transport/browser/message_port_socket.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAEhD;;GAEG;AACH,qBAAa,iBAAkB,YAAW,MAAM;IAClC,OAAO,CAAC,IAAI;gBAAJ,IAAI,EAAE,WAAW;IAErC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,GAAE,YAAY,EAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAK5D,eAAe,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,GAAG,GAAG,IAAI;IAI5C,KAAK;CAKN"} \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/transport/browser/message_port_socket.js b/circuits/.yalc/@aztec/foundation/dest/transport/browser/message_port_socket.js new file mode 100644 index 00000000000..94f044744e9 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/transport/browser/message_port_socket.js @@ -0,0 +1,21 @@ +/** + * An implementation of a TransportSocket using MessagePorts. + */ +export class MessagePortSocket { + constructor(port) { + this.port = port; + } + send(msg, transfer = []) { + this.port.postMessage(msg, transfer); + return Promise.resolve(); + } + registerHandler(cb) { + this.port.onmessage = event => cb(event.data); + } + close() { + void this.send(undefined); + this.port.onmessage = null; + this.port.close(); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVzc2FnZV9wb3J0X3NvY2tldC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy90cmFuc3BvcnQvYnJvd3Nlci9tZXNzYWdlX3BvcnRfc29ja2V0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUVBOztHQUVHO0FBQ0gsTUFBTSxPQUFPLGlCQUFpQjtJQUM1QixZQUFvQixJQUFpQjtRQUFqQixTQUFJLEdBQUosSUFBSSxDQUFhO0lBQUcsQ0FBQztJQUV6QyxJQUFJLENBQUMsR0FBUSxFQUFFLFdBQTJCLEVBQUU7UUFDMUMsSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsR0FBRyxFQUFFLFFBQVEsQ0FBQyxDQUFDO1FBQ3JDLE9BQU8sT0FBTyxDQUFDLE9BQU8sRUFBRSxDQUFDO0lBQzNCLENBQUM7SUFFRCxlQUFlLENBQUMsRUFBcUI7UUFDbkMsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEdBQUcsS0FBSyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ2hELENBQUM7SUFFRCxLQUFLO1FBQ0gsS0FBSyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQzFCLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksQ0FBQztRQUMzQixJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQ3BCLENBQUM7Q0FDRiJ9 \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_connector.d.ts b/circuits/.yalc/@aztec/foundation/dest/transport/browser/shared_worker_connector.d.ts similarity index 56% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_connector.d.ts rename to circuits/.yalc/@aztec/foundation/dest/transport/browser/shared_worker_connector.d.ts index 032f9df12b3..8f581805083 100644 --- a/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_connector.d.ts +++ b/circuits/.yalc/@aztec/foundation/dest/transport/browser/shared_worker_connector.d.ts @@ -1,19 +1,8 @@ import { Connector } from '../interface/connector.js'; import { MessagePortSocket } from './message_port_socket.js'; -/** - * Connector implementation which wraps a SharedWorker. - */ export declare class SharedWorkerConnector implements Connector { private worker; - /** - * Create a SharedWorkerConnector. - * @param worker - A shared worker. - */ constructor(worker: SharedWorker); - /** - * Create a Socket implementation with our mesage port. - * @returns The socket. - */ createSocket(): Promise; } //# sourceMappingURL=shared_worker_connector.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_connector.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/transport/browser/shared_worker_connector.d.ts.map similarity index 51% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_connector.d.ts.map rename to circuits/.yalc/@aztec/foundation/dest/transport/browser/shared_worker_connector.d.ts.map index b745dd62aed..0f578ce6663 100644 --- a/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_connector.d.ts.map +++ b/circuits/.yalc/@aztec/foundation/dest/transport/browser/shared_worker_connector.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"shared_worker_connector.d.ts","sourceRoot":"","sources":["../../../src/transport/browser/shared_worker_connector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D;;GAEG;AACH,qBAAa,qBAAsB,YAAW,SAAS;IAKzC,OAAO,CAAC,MAAM;IAJ1B;;;OAGG;gBACiB,MAAM,EAAE,YAAY;IAExC;;;OAGG;IACH,YAAY;CAGb"} \ No newline at end of file +{"version":3,"file":"shared_worker_connector.d.ts","sourceRoot":"","sources":["../../../src/transport/browser/shared_worker_connector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D,qBAAa,qBAAsB,YAAW,SAAS;IACzC,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,YAAY;IAExC,YAAY;CAGb"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_connector.js b/circuits/.yalc/@aztec/foundation/dest/transport/browser/shared_worker_connector.js similarity index 50% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_connector.js rename to circuits/.yalc/@aztec/foundation/dest/transport/browser/shared_worker_connector.js index fa8778b40a9..f1a3c5dba1c 100644 --- a/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_connector.js +++ b/circuits/.yalc/@aztec/foundation/dest/transport/browser/shared_worker_connector.js @@ -1,21 +1,10 @@ import { MessagePortSocket } from './message_port_socket.js'; -/** - * Connector implementation which wraps a SharedWorker. - */ export class SharedWorkerConnector { - /** - * Create a SharedWorkerConnector. - * @param worker - A shared worker. - */ constructor(worker) { this.worker = worker; } - /** - * Create a Socket implementation with our mesage port. - * @returns The socket. - */ createSocket() { return Promise.resolve(new MessagePortSocket(this.worker.port)); } } -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2hhcmVkX3dvcmtlcl9jb25uZWN0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvdHJhbnNwb3J0L2Jyb3dzZXIvc2hhcmVkX3dvcmtlcl9jb25uZWN0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFFN0Q7O0dBRUc7QUFDSCxNQUFNLE9BQU8scUJBQXFCO0lBQ2hDOzs7T0FHRztJQUNILFlBQW9CLE1BQW9CO1FBQXBCLFdBQU0sR0FBTixNQUFNLENBQWM7SUFBRyxDQUFDO0lBRTVDOzs7T0FHRztJQUNILFlBQVk7UUFDVixPQUFPLE9BQU8sQ0FBQyxPQUFPLENBQUMsSUFBSSxpQkFBaUIsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDbEUsQ0FBQztDQUNGIn0= \ No newline at end of file +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2hhcmVkX3dvcmtlcl9jb25uZWN0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvdHJhbnNwb3J0L2Jyb3dzZXIvc2hhcmVkX3dvcmtlcl9jb25uZWN0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFFN0QsTUFBTSxPQUFPLHFCQUFxQjtJQUNoQyxZQUFvQixNQUFvQjtRQUFwQixXQUFNLEdBQU4sTUFBTSxDQUFjO0lBQUcsQ0FBQztJQUU1QyxZQUFZO1FBQ1YsT0FBTyxPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksaUJBQWlCLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQ2xFLENBQUM7Q0FDRiJ9 \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_listener.d.ts b/circuits/.yalc/@aztec/foundation/dest/transport/browser/shared_worker_listener.d.ts similarity index 56% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_listener.d.ts rename to circuits/.yalc/@aztec/foundation/dest/transport/browser/shared_worker_listener.d.ts index e6e93d9b214..81344305115 100644 --- a/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_listener.d.ts +++ b/circuits/.yalc/@aztec/foundation/dest/transport/browser/shared_worker_listener.d.ts @@ -1,37 +1,14 @@ /// import EventEmitter from 'events'; import { Listener } from '../interface/listener.js'; -/** - * See https://developer.mozilla.org/en-US/docs/Web/API/SharedWorkerGlobalScope. - */ declare interface SharedWorkerGlobalScope { - /** - * Fired on shared workers when a new client connects. - */ - onconnect: any; + onconnect: (...args: any) => any; } -/** - * Listens for connections to a shared worker. - */ export declare class SharedWorkerListener extends EventEmitter implements Listener { private worker; - /** - * - * @param worker - */ constructor(worker: SharedWorkerGlobalScope); - /** - * - */ open(): void; - /** - * - */ close(): void; - /** - * - * @param event - */ private handleMessageEvent; } export {}; diff --git a/circuits/.yalc/@aztec/foundation/dest/transport/browser/shared_worker_listener.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/transport/browser/shared_worker_listener.d.ts.map new file mode 100644 index 00000000000..a361f3edd47 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/transport/browser/shared_worker_listener.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"shared_worker_listener.d.ts","sourceRoot":"","sources":["../../../src/transport/browser/shared_worker_listener.ts"],"names":[],"mappings":";AAAA,OAAO,YAAY,MAAM,QAAQ,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAGpD,OAAO,WAAW,uBAAuB;IACvC,SAAS,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,KAAK,GAAG,CAAC;CAClC;AAED,qBAAa,oBAAqB,SAAQ,YAAa,YAAW,QAAQ;IAC5D,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,uBAAuB;IAInD,IAAI;IAIJ,KAAK;IAIL,OAAO,CAAC,kBAAkB,CAMxB;CACH"} \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/transport/browser/shared_worker_listener.js b/circuits/.yalc/@aztec/foundation/dest/transport/browser/shared_worker_listener.js new file mode 100644 index 00000000000..e2027a2fb4b --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/transport/browser/shared_worker_listener.js @@ -0,0 +1,22 @@ +import EventEmitter from 'events'; +import { MessagePortSocket } from './message_port_socket.js'; +export class SharedWorkerListener extends EventEmitter { + constructor(worker) { + super(); + this.worker = worker; + this.handleMessageEvent = (event) => { + const [port] = event.ports; + if (!port) { + return; + } + this.emit('new_socket', new MessagePortSocket(port)); + }; + } + open() { + this.worker.onconnect = this.handleMessageEvent; + } + close() { + this.worker.onconnect = () => { }; + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2hhcmVkX3dvcmtlcl9saXN0ZW5lci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy90cmFuc3BvcnQvYnJvd3Nlci9zaGFyZWRfd29ya2VyX2xpc3RlbmVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sWUFBWSxNQUFNLFFBQVEsQ0FBQztBQUVsQyxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQU03RCxNQUFNLE9BQU8sb0JBQXFCLFNBQVEsWUFBWTtJQUNwRCxZQUFvQixNQUErQjtRQUNqRCxLQUFLLEVBQUUsQ0FBQztRQURVLFdBQU0sR0FBTixNQUFNLENBQXlCO1FBWTNDLHVCQUFrQixHQUFHLENBQUMsS0FBbUIsRUFBRSxFQUFFO1lBQ25ELE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxLQUFLLENBQUMsS0FBSyxDQUFDO1lBQzNCLElBQUksQ0FBQyxJQUFJLEVBQUU7Z0JBQ1QsT0FBTzthQUNSO1lBQ0QsSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLEVBQUUsSUFBSSxpQkFBaUIsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO1FBQ3ZELENBQUMsQ0FBQztJQWhCRixDQUFDO0lBRUQsSUFBSTtRQUNGLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxHQUFHLElBQUksQ0FBQyxrQkFBa0IsQ0FBQztJQUNsRCxDQUFDO0lBRUQsS0FBSztRQUNILElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxHQUFHLEdBQUcsRUFBRSxHQUFFLENBQUMsQ0FBQztJQUNuQyxDQUFDO0NBU0YifQ== \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/worker_connector.d.ts b/circuits/.yalc/@aztec/foundation/dest/transport/browser/worker_connector.d.ts similarity index 80% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/worker_connector.d.ts rename to circuits/.yalc/@aztec/foundation/dest/transport/browser/worker_connector.d.ts index a7eba90c1ac..45ea6d3dd6f 100644 --- a/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/worker_connector.d.ts +++ b/circuits/.yalc/@aztec/foundation/dest/transport/browser/worker_connector.d.ts @@ -1,18 +1,8 @@ import { Connector } from '../interface/connector.js'; import { MessagePortSocket } from './message_port_socket.js'; -/** - * - */ export declare class WorkerConnector implements Connector { private worker; - /** - * - * @param worker - */ constructor(worker: Worker); - /** - * - */ createSocket(): Promise; } //# sourceMappingURL=worker_connector.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/worker_connector.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/transport/browser/worker_connector.d.ts.map similarity index 53% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/worker_connector.d.ts.map rename to circuits/.yalc/@aztec/foundation/dest/transport/browser/worker_connector.d.ts.map index a0af81a8776..7c8065a76b3 100644 --- a/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/worker_connector.d.ts.map +++ b/circuits/.yalc/@aztec/foundation/dest/transport/browser/worker_connector.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"worker_connector.d.ts","sourceRoot":"","sources":["../../../src/transport/browser/worker_connector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D;;GAEG;AACH,qBAAa,eAAgB,YAAW,SAAS;IAKnC,OAAO,CAAC,MAAM;IAJ1B;;;OAGG;gBACiB,MAAM,EAAE,MAAM;IAElC;;OAEG;IACH,YAAY;CAKb"} \ No newline at end of file +{"version":3,"file":"worker_connector.d.ts","sourceRoot":"","sources":["../../../src/transport/browser/worker_connector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D,qBAAa,eAAgB,YAAW,SAAS;IACnC,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,MAAM;IAElC,YAAY;CAKb"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/worker_connector.js b/circuits/.yalc/@aztec/foundation/dest/transport/browser/worker_connector.js similarity index 51% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/worker_connector.js rename to circuits/.yalc/@aztec/foundation/dest/transport/browser/worker_connector.js index 4faae6403cf..e65a3cb331d 100644 --- a/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/worker_connector.js +++ b/circuits/.yalc/@aztec/foundation/dest/transport/browser/worker_connector.js @@ -1,22 +1,12 @@ import { MessagePortSocket } from './message_port_socket.js'; -/** - * - */ export class WorkerConnector { - /** - * - * @param worker - */ constructor(worker) { this.worker = worker; } - /** - * - */ createSocket() { const channel = new MessageChannel(); this.worker.postMessage('', [channel.port2]); return Promise.resolve(new MessagePortSocket(channel.port1)); } } -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid29ya2VyX2Nvbm5lY3Rvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy90cmFuc3BvcnQvYnJvd3Nlci93b3JrZXJfY29ubmVjdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBRTdEOztHQUVHO0FBQ0gsTUFBTSxPQUFPLGVBQWU7SUFDMUI7OztPQUdHO0lBQ0gsWUFBb0IsTUFBYztRQUFkLFdBQU0sR0FBTixNQUFNLENBQVE7SUFBRyxDQUFDO0lBRXRDOztPQUVHO0lBQ0gsWUFBWTtRQUNWLE1BQU0sT0FBTyxHQUFHLElBQUksY0FBYyxFQUFFLENBQUM7UUFDckMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxXQUFXLENBQUMsRUFBRSxFQUFFLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7UUFDN0MsT0FBTyxPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksaUJBQWlCLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7SUFDL0QsQ0FBQztDQUNGIn0= \ No newline at end of file +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid29ya2VyX2Nvbm5lY3Rvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy90cmFuc3BvcnQvYnJvd3Nlci93b3JrZXJfY29ubmVjdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBRTdELE1BQU0sT0FBTyxlQUFlO0lBQzFCLFlBQW9CLE1BQWM7UUFBZCxXQUFNLEdBQU4sTUFBTSxDQUFRO0lBQUcsQ0FBQztJQUV0QyxZQUFZO1FBQ1YsTUFBTSxPQUFPLEdBQUcsSUFBSSxjQUFjLEVBQUUsQ0FBQztRQUNyQyxJQUFJLENBQUMsTUFBTSxDQUFDLFdBQVcsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztRQUM3QyxPQUFPLE9BQU8sQ0FBQyxPQUFPLENBQUMsSUFBSSxpQkFBaUIsQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztJQUMvRCxDQUFDO0NBQ0YifQ== \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/worker_listener.d.ts b/circuits/.yalc/@aztec/foundation/dest/transport/browser/worker_listener.d.ts similarity index 70% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/worker_listener.d.ts rename to circuits/.yalc/@aztec/foundation/dest/transport/browser/worker_listener.d.ts index 135a82ed2c4..c9e253887a8 100644 --- a/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/worker_listener.d.ts +++ b/circuits/.yalc/@aztec/foundation/dest/transport/browser/worker_listener.d.ts @@ -1,37 +1,14 @@ /// import EventEmitter from 'events'; import { Listener } from '../interface/listener.js'; -/** - * - */ declare interface DedicatedWorkerGlobalScope { - /** - * - */ - onmessage: any; + onmessage: (...args: any) => any; } -/** - * - */ export declare class WorkerListener extends EventEmitter implements Listener { private worker; - /** - * - * @param worker - */ constructor(worker: DedicatedWorkerGlobalScope); - /** - * - */ open(): void; - /** - * - */ close(): void; - /** - * - * @param event - */ private handleMessageEvent; } export {}; diff --git a/circuits/.yalc/@aztec/foundation/dest/transport/browser/worker_listener.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/transport/browser/worker_listener.d.ts.map new file mode 100644 index 00000000000..62421761d68 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/transport/browser/worker_listener.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"worker_listener.d.ts","sourceRoot":"","sources":["../../../src/transport/browser/worker_listener.ts"],"names":[],"mappings":";AAAA,OAAO,YAAY,MAAM,QAAQ,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAGpD,OAAO,WAAW,0BAA0B;IAC1C,SAAS,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,KAAK,GAAG,CAAC;CAClC;AAED,qBAAa,cAAe,SAAQ,YAAa,YAAW,QAAQ;IACtD,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,0BAA0B;IAItD,IAAI;IAIJ,KAAK;IAIL,OAAO,CAAC,kBAAkB,CAMxB;CACH"} \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/transport/browser/worker_listener.js b/circuits/.yalc/@aztec/foundation/dest/transport/browser/worker_listener.js new file mode 100644 index 00000000000..006e3af3280 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/transport/browser/worker_listener.js @@ -0,0 +1,22 @@ +import EventEmitter from 'events'; +import { MessagePortSocket } from './message_port_socket.js'; +export class WorkerListener extends EventEmitter { + constructor(worker) { + super(); + this.worker = worker; + this.handleMessageEvent = (event) => { + const [port] = event.ports; + if (!port) { + return; + } + this.emit('new_socket', new MessagePortSocket(port)); + }; + } + open() { + this.worker.onmessage = this.handleMessageEvent; + } + close() { + this.worker.onmessage = () => { }; + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid29ya2VyX2xpc3RlbmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3RyYW5zcG9ydC9icm93c2VyL3dvcmtlcl9saXN0ZW5lci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLFlBQVksTUFBTSxRQUFRLENBQUM7QUFFbEMsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFNN0QsTUFBTSxPQUFPLGNBQWUsU0FBUSxZQUFZO0lBQzlDLFlBQW9CLE1BQWtDO1FBQ3BELEtBQUssRUFBRSxDQUFDO1FBRFUsV0FBTSxHQUFOLE1BQU0sQ0FBNEI7UUFZOUMsdUJBQWtCLEdBQUcsQ0FBQyxLQUFtQixFQUFFLEVBQUU7WUFDbkQsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLEtBQUssQ0FBQyxLQUFLLENBQUM7WUFDM0IsSUFBSSxDQUFDLElBQUksRUFBRTtnQkFDVCxPQUFPO2FBQ1I7WUFDRCxJQUFJLENBQUMsSUFBSSxDQUFDLFlBQVksRUFBRSxJQUFJLGlCQUFpQixDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7UUFDdkQsQ0FBQyxDQUFDO0lBaEJGLENBQUM7SUFFRCxJQUFJO1FBQ0YsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLEdBQUcsSUFBSSxDQUFDLGtCQUFrQixDQUFDO0lBQ2xELENBQUM7SUFFRCxLQUFLO1FBQ0gsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLEdBQUcsR0FBRyxFQUFFLEdBQUUsQ0FBQyxDQUFDO0lBQ25DLENBQUM7Q0FTRiJ9 \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_fn.d.ts b/circuits/.yalc/@aztec/foundation/dest/transport/dispatch/create_dispatch_fn.d.ts similarity index 82% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_fn.d.ts rename to circuits/.yalc/@aztec/foundation/dest/transport/dispatch/create_dispatch_fn.d.ts index fdb3921facf..794ee5dee17 100644 --- a/circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_fn.d.ts +++ b/circuits/.yalc/@aztec/foundation/dest/transport/dispatch/create_dispatch_fn.d.ts @@ -1,19 +1,7 @@ -/** - * - */ export interface DispatchMsg { - /** - * - */ fn: string; - /** - * - */ args: any[]; } -/** - * - */ export declare function createDispatchFn(targetFn: () => any, debug?: { (...data: any[]): void; (message?: any, ...optionalParams: any[]): void; diff --git a/circuits/.yalc/@aztec/foundation/dest/transport/dispatch/create_dispatch_fn.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/transport/dispatch/create_dispatch_fn.d.ts.map new file mode 100644 index 00000000000..7b2c8298b41 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/transport/dispatch/create_dispatch_fn.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"create_dispatch_fn.d.ts","sourceRoot":"","sources":["../../../src/transport/dispatch/create_dispatch_fn.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,GAAG,EAAE,CAAC;CACb;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,EAAE,KAAK;;;CAAgB,kBAC7C,WAAW,kBAKxC"} \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/transport/dispatch/create_dispatch_fn.js b/circuits/.yalc/@aztec/foundation/dest/transport/dispatch/create_dispatch_fn.js new file mode 100644 index 00000000000..d188461858f --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/transport/dispatch/create_dispatch_fn.js @@ -0,0 +1,8 @@ +export function createDispatchFn(targetFn, debug = console.error) { + return async ({ fn, args }) => { + const target = targetFn(); + debug(`dispatching to ${target}: ${fn}`, args); + return await target[fn](...args); + }; +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3JlYXRlX2Rpc3BhdGNoX2ZuLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3RyYW5zcG9ydC9kaXNwYXRjaC9jcmVhdGVfZGlzcGF0Y2hfZm4udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBS0EsTUFBTSxVQUFVLGdCQUFnQixDQUFDLFFBQW1CLEVBQUUsS0FBSyxHQUFHLE9BQU8sQ0FBQyxLQUFLO0lBQ3pFLE9BQU8sS0FBSyxFQUFFLEVBQUUsRUFBRSxFQUFFLElBQUksRUFBZSxFQUFFLEVBQUU7UUFDekMsTUFBTSxNQUFNLEdBQUcsUUFBUSxFQUFFLENBQUM7UUFDMUIsS0FBSyxDQUFDLGtCQUFrQixNQUFNLEtBQUssRUFBRSxFQUFFLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFDL0MsT0FBTyxNQUFNLE1BQU0sQ0FBQyxFQUFFLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxDQUFDO0lBQ25DLENBQUMsQ0FBQztBQUNKLENBQUMifQ== \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_proxy.d.ts b/circuits/.yalc/@aztec/foundation/dest/transport/dispatch/create_dispatch_proxy.d.ts similarity index 77% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_proxy.d.ts rename to circuits/.yalc/@aztec/foundation/dest/transport/dispatch/create_dispatch_proxy.d.ts index 27edab62dc3..9e74a47c7c3 100644 --- a/circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_proxy.d.ts +++ b/circuits/.yalc/@aztec/foundation/dest/transport/dispatch/create_dispatch_proxy.d.ts @@ -2,17 +2,14 @@ import { DispatchMsg } from './create_dispatch_fn.js'; import { TransportClient } from '../transport_client.js'; import { TransferDescriptor } from '../interface/transferable.js'; type FilterOutAttributes = { - [Key in keyof Base]: Base[Key] extends (...args: any) => any ? Base[Key] : never; + [Key in keyof Base]: Base[Key] extends (...any: any) => any ? Base[Key] : never; }; -type PromisifyFunction any> = (...args: Parameters) => Promise>; +type PromisifyFunction any> = (...args: Parameters) => Promise>; type Promisify any; + [key: string]: (...any: any) => any; }> = { [Key in keyof Base]: ReturnType extends Promise ? Base[Key] : PromisifyFunction; }; -/** - * Unpack transfer types - */ type TransferTypes = { [Index in keyof Tuple]: Tuple[Index] | (Tuple[Index] extends Transferable ? TransferDescriptor : never); }; @@ -25,11 +22,11 @@ type TransferTypes = { * * type MakeFunctionTransferrable any> = ( * ...args: TransferTypes> - * ) => ReturnType;. + * ) => ReturnType; */ type MakeFunctionTransferrable any> = (...args: TFunction extends (...args: infer P) => any ? TransferTypes

: never) => ReturnType; type Transferrable any; + [key: string]: (...any: any) => any; }> = { [Key in keyof Base]: MakeFunctionTransferrable; }; @@ -37,12 +34,6 @@ export type Proxify = Promisify>>; export declare function createDispatchProxyFromFn(class_: { new (...args: any[]): T; }, requestFn: (fn: string) => (...args: any[]) => Promise): Proxify; -/** - * Create a proxy object of our class T that uses transportClient - * @param class_ - Our class T. - * @param transportClient - The transport infrastructure. - * @returns A proxy over T. - */ export declare function createDispatchProxy(class_: { new (...args: any[]): T; }, transportClient: TransportClient): Proxify; diff --git a/circuits/.yalc/@aztec/foundation/dest/transport/dispatch/create_dispatch_proxy.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/transport/dispatch/create_dispatch_proxy.d.ts.map new file mode 100644 index 00000000000..c0180d3831a --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/transport/dispatch/create_dispatch_proxy.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"create_dispatch_proxy.d.ts","sourceRoot":"","sources":["../../../src/transport/dispatch/create_dispatch_proxy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEzD,OAAO,EAAwB,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAExF,KAAK,mBAAmB,CAAC,IAAI,IAAI;KAC9B,GAAG,IAAI,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,GAAG,EAAE,GAAG,KAAK,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK;CAChF,CAAC;AAEF,KAAK,iBAAiB,CAAC,CAAC,SAAS,CAAC,GAAG,GAAG,EAAE,GAAG,KAAK,GAAG,IAAI,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AAE5G,KAAK,SAAS,CAAC,IAAI,SAAS;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,GAAG,EAAE,GAAG,KAAK,GAAG,CAAA;CAAE,IAAI;KACpE,GAAG,IAAI,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,SAAS,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,iBAAiB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;CAC3G,CAAC;AAEF,KAAK,aAAa,CAAC,KAAK,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,CAAC,IAAI;KAChD,KAAK,IAAI,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,YAAY,GAAG,kBAAkB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC;CACtH,CAAC;AAEF;;;;;;;;;;GAUG;AACH,KAAK,yBAAyB,CAAC,SAAS,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,KAAK,GAAG,IAAI,CACxE,GAAG,IAAI,EAAE,SAAS,SAAS,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,KAAK,GAAG,GAAG,aAAa,CAAC,CAAC,CAAC,GAAG,KAAK,KAC5E,UAAU,CAAC,SAAS,CAAC,CAAC;AAE3B,KAAK,aAAa,CAAC,IAAI,SAAS;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,GAAG,EAAE,GAAG,KAAK,GAAG,CAAA;CAAE,IAAI;KACxE,GAAG,IAAI,MAAM,IAAI,GAAG,yBAAyB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;CAC1D,CAAC;AAEF,MAAM,MAAM,OAAO,CAAC,CAAC,IAAI,SAAS,CAAC,aAAa,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAE1E,wBAAgB,yBAAyB,CAAC,CAAC,EACzC,MAAM,EAAE;IAAE,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;CAAE,EACnC,SAAS,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,GAAG,CAAC,GAC1D,OAAO,CAAC,CAAC,CAAC,CASZ;AAED,wBAAgB,mBAAmB,CAAC,CAAC,EACnC,MAAM,EAAE;IAAE,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;CAAE,EACnC,eAAe,EAAE,eAAe,CAAC,WAAW,CAAC,GAC5C,OAAO,CAAC,CAAC,CAAC,CAqBZ"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_proxy.js b/circuits/.yalc/@aztec/foundation/dest/transport/dispatch/create_dispatch_proxy.js similarity index 57% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_proxy.js rename to circuits/.yalc/@aztec/foundation/dest/transport/dispatch/create_dispatch_proxy.js index 49833dfc748..94777e65550 100644 --- a/circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_proxy.js +++ b/circuits/.yalc/@aztec/foundation/dest/transport/dispatch/create_dispatch_proxy.js @@ -10,12 +10,6 @@ export function createDispatchProxyFromFn(class_, requestFn) { } return proxy; } -/** - * Create a proxy object of our class T that uses transportClient - * @param class_ - Our class T. - * @param transportClient - The transport infrastructure. - * @returns A proxy over T. - */ export function createDispatchProxy(class_, transportClient) { // Create a proxy of class_ that passes along methods over our transportClient const proxy = createDispatchProxyFromFn(class_, (fn) => (...args) => { @@ -35,4 +29,4 @@ export function createDispatchProxy(class_, transportClient) { } return proxy; } -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3JlYXRlX2Rpc3BhdGNoX3Byb3h5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3RyYW5zcG9ydC9kaXNwYXRjaC9jcmVhdGVfZGlzcGF0Y2hfcHJveHkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBRUEsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLFFBQVEsQ0FBQztBQUN0QyxPQUFPLEVBQUUsb0JBQW9CLEVBQXNCLE1BQU0sOEJBQThCLENBQUM7QUF3Q3hGLE1BQU0sVUFBVSx5QkFBeUIsQ0FDdkMsTUFBbUMsRUFDbkMsU0FBMkQ7SUFFM0QsTUFBTSxLQUFLLEdBQVEsTUFBTSxDQUFDLFNBQVMsWUFBWSxZQUFZLENBQUMsQ0FBQyxDQUFDLElBQUksWUFBWSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztJQUN0RixLQUFLLE1BQU0sRUFBRSxJQUFJLE1BQU0sQ0FBQyxtQkFBbUIsQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLEVBQUU7UUFDN0QsSUFBSSxFQUFFLEtBQUssYUFBYSxFQUFFO1lBQ3hCLFNBQVM7U0FDVjtRQUNELEtBQUssQ0FBQyxFQUFFLENBQUMsR0FBRyxTQUFTLENBQUMsRUFBRSxDQUFDLENBQUM7S0FDM0I7SUFDRCxPQUFPLEtBQUssQ0FBQztBQUNmLENBQUM7QUFFRDs7Ozs7R0FLRztBQUNILE1BQU0sVUFBVSxtQkFBbUIsQ0FDakMsTUFBbUMsRUFDbkMsZUFBNkM7SUFFN0MsOEVBQThFO0lBQzlFLE1BQU0sS0FBSyxHQUFHLHlCQUF5QixDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQVUsRUFBRSxFQUFFLENBQUMsQ0FBQyxHQUFHLElBQVcsRUFBRSxFQUFFO1FBQ2pGLHlFQUF5RTtRQUN6RSxNQUFNLFFBQVEsR0FBbUIsSUFBSSxDQUFDLE1BQU0sQ0FDMUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLG9CQUFvQixDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsR0FBRyxFQUFFLEdBQUcsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsRUFDMUUsRUFBb0IsQ0FDckIsQ0FBQztRQUNGLElBQUksR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUM3RCxPQUFPLGVBQWUsQ0FBQyxPQUFPLENBQUMsRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFFLEVBQUUsUUFBUSxDQUFDLENBQUM7SUFDekQsQ0FBQyxDQUFDLENBQUM7SUFDSCxJQUFJLEtBQUssWUFBWSxZQUFZLEVBQUU7UUFDakMscUVBQXFFO1FBQ3JFLGVBQWUsQ0FBQyxFQUFFLENBQUMsV0FBVyxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFFLEVBQUUsRUFBRTtZQUMvQyxJQUFJLEVBQUUsS0FBSyxNQUFNLEVBQUU7Z0JBQ2pCLE1BQU0sQ0FBQyxTQUFTLEVBQUUsR0FBRyxRQUFRLENBQUMsR0FBRyxJQUFJLENBQUM7Z0JBQ3RDLEtBQUssQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLEdBQUcsUUFBUSxDQUFDLENBQUM7YUFDcEM7UUFDSCxDQUFDLENBQUMsQ0FBQztLQUNKO0lBQ0QsT0FBTyxLQUFLLENBQUM7QUFDZixDQUFDIn0= \ No newline at end of file +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3JlYXRlX2Rpc3BhdGNoX3Byb3h5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3RyYW5zcG9ydC9kaXNwYXRjaC9jcmVhdGVfZGlzcGF0Y2hfcHJveHkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBRUEsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLFFBQVEsQ0FBQztBQUN0QyxPQUFPLEVBQUUsb0JBQW9CLEVBQXNCLE1BQU0sOEJBQThCLENBQUM7QUFxQ3hGLE1BQU0sVUFBVSx5QkFBeUIsQ0FDdkMsTUFBbUMsRUFDbkMsU0FBMkQ7SUFFM0QsTUFBTSxLQUFLLEdBQVEsTUFBTSxDQUFDLFNBQVMsWUFBWSxZQUFZLENBQUMsQ0FBQyxDQUFDLElBQUksWUFBWSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztJQUN0RixLQUFLLE1BQU0sRUFBRSxJQUFJLE1BQU0sQ0FBQyxtQkFBbUIsQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLEVBQUU7UUFDN0QsSUFBSSxFQUFFLEtBQUssYUFBYSxFQUFFO1lBQ3hCLFNBQVM7U0FDVjtRQUNELEtBQUssQ0FBQyxFQUFFLENBQUMsR0FBRyxTQUFTLENBQUMsRUFBRSxDQUFDLENBQUM7S0FDM0I7SUFDRCxPQUFPLEtBQUssQ0FBQztBQUNmLENBQUM7QUFFRCxNQUFNLFVBQVUsbUJBQW1CLENBQ2pDLE1BQW1DLEVBQ25DLGVBQTZDO0lBRTdDLDhFQUE4RTtJQUM5RSxNQUFNLEtBQUssR0FBRyx5QkFBeUIsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFVLEVBQUUsRUFBRSxDQUFDLENBQUMsR0FBRyxJQUFXLEVBQUUsRUFBRTtRQUNqRix5RUFBeUU7UUFDekUsTUFBTSxRQUFRLEdBQW1CLElBQUksQ0FBQyxNQUFNLENBQzFDLENBQUMsR0FBRyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLEdBQUcsRUFBRSxHQUFHLENBQUMsQ0FBQyxhQUFhLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLEVBQzFFLEVBQW9CLENBQ3JCLENBQUM7UUFDRixJQUFJLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsb0JBQW9CLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDN0QsT0FBTyxlQUFlLENBQUMsT0FBTyxDQUFDLEVBQUUsRUFBRSxFQUFFLElBQUksRUFBRSxFQUFFLFFBQVEsQ0FBQyxDQUFDO0lBQ3pELENBQUMsQ0FBQyxDQUFDO0lBQ0gsSUFBSSxLQUFLLFlBQVksWUFBWSxFQUFFO1FBQ2pDLHFFQUFxRTtRQUNyRSxlQUFlLENBQUMsRUFBRSxDQUFDLFdBQVcsRUFBRSxDQUFDLEVBQUUsRUFBRSxFQUFFLElBQUksRUFBRSxFQUFFLEVBQUU7WUFDL0MsSUFBSSxFQUFFLEtBQUssTUFBTSxFQUFFO2dCQUNqQixNQUFNLENBQUMsU0FBUyxFQUFFLEdBQUcsUUFBUSxDQUFDLEdBQUcsSUFBSSxDQUFDO2dCQUN0QyxLQUFLLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxHQUFHLFFBQVEsQ0FBQyxDQUFDO2FBQ3BDO1FBQ0gsQ0FBQyxDQUFDLENBQUM7S0FDSjtJQUNELE9BQU8sS0FBSyxDQUFDO0FBQ2YsQ0FBQyJ9 \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/transport/dispatch/messages.d.ts b/circuits/.yalc/@aztec/foundation/dest/transport/dispatch/messages.d.ts new file mode 100644 index 00000000000..ed26786d9c2 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/transport/dispatch/messages.d.ts @@ -0,0 +1,14 @@ +export interface RequestMessage { + msgId: number; + payload: Payload; +} +export interface ResponseMessage { + msgId: number; + payload?: Payload; + error?: string; +} +export interface EventMessage { + payload: Payload; +} +export declare function isEventMessage(msg: ResponseMessage | EventMessage): msg is EventMessage; +//# sourceMappingURL=messages.d.ts.map \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/transport/dispatch/messages.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/transport/dispatch/messages.d.ts.map new file mode 100644 index 00000000000..0085e4fa75a --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/transport/dispatch/messages.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../../src/transport/dispatch/messages.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc,CAAC,OAAO;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,eAAe,CAAC,OAAO;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY,CAAC,OAAO;IACnC,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,wBAAgB,cAAc,CAAC,OAAO,EACpC,GAAG,EAAE,eAAe,CAAC,OAAO,CAAC,GAAG,YAAY,CAAC,OAAO,CAAC,GACpD,GAAG,IAAI,YAAY,CAAC,OAAO,CAAC,CAE9B"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/messages.js b/circuits/.yalc/@aztec/foundation/dest/transport/dispatch/messages.js similarity index 52% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/messages.js rename to circuits/.yalc/@aztec/foundation/dest/transport/dispatch/messages.js index b5d76595237..796d6a932ab 100644 --- a/circuits/ts/.yalc/@aztec/wasm/dest/transport/dispatch/messages.js +++ b/circuits/.yalc/@aztec/foundation/dest/transport/dispatch/messages.js @@ -1,8 +1,4 @@ -/** - * Is this an event message? - * @returns If the msgId was blank. - */ export function isEventMessage(msg) { return msg.msgId === undefined; } -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVzc2FnZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvdHJhbnNwb3J0L2Rpc3BhdGNoL21lc3NhZ2VzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQTBDQTs7O0dBR0c7QUFDSCxNQUFNLFVBQVUsY0FBYyxDQUM1QixHQUFxRDtJQUVyRCxPQUFRLEdBQWdDLENBQUMsS0FBSyxLQUFLLFNBQVMsQ0FBQztBQUMvRCxDQUFDIn0= \ No newline at end of file +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVzc2FnZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvdHJhbnNwb3J0L2Rpc3BhdGNoL21lc3NhZ2VzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQWVBLE1BQU0sVUFBVSxjQUFjLENBQzVCLEdBQXFEO0lBRXJELE9BQVEsR0FBZ0MsQ0FBQyxLQUFLLEtBQUssU0FBUyxDQUFDO0FBQy9ELENBQUMifQ== \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/index.d.ts b/circuits/.yalc/@aztec/foundation/dest/transport/index.d.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/index.d.ts rename to circuits/.yalc/@aztec/foundation/dest/transport/index.d.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/index.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/transport/index.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/index.d.ts.map rename to circuits/.yalc/@aztec/foundation/dest/transport/index.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/index.js b/circuits/.yalc/@aztec/foundation/dest/transport/index.js similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/index.js rename to circuits/.yalc/@aztec/foundation/dest/transport/index.js diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/connector.d.ts b/circuits/.yalc/@aztec/foundation/dest/transport/interface/connector.d.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/connector.d.ts rename to circuits/.yalc/@aztec/foundation/dest/transport/interface/connector.d.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/connector.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/transport/interface/connector.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/connector.d.ts.map rename to circuits/.yalc/@aztec/foundation/dest/transport/interface/connector.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/connector.js b/circuits/.yalc/@aztec/foundation/dest/transport/interface/connector.js similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/connector.js rename to circuits/.yalc/@aztec/foundation/dest/transport/interface/connector.js diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/listener.d.ts b/circuits/.yalc/@aztec/foundation/dest/transport/interface/listener.d.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/listener.d.ts rename to circuits/.yalc/@aztec/foundation/dest/transport/interface/listener.d.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/listener.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/transport/interface/listener.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/listener.d.ts.map rename to circuits/.yalc/@aztec/foundation/dest/transport/interface/listener.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/listener.js b/circuits/.yalc/@aztec/foundation/dest/transport/interface/listener.js similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/listener.js rename to circuits/.yalc/@aztec/foundation/dest/transport/interface/listener.js diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/socket.d.ts b/circuits/.yalc/@aztec/foundation/dest/transport/interface/socket.d.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/socket.d.ts rename to circuits/.yalc/@aztec/foundation/dest/transport/interface/socket.d.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/socket.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/transport/interface/socket.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/socket.d.ts.map rename to circuits/.yalc/@aztec/foundation/dest/transport/interface/socket.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/socket.js b/circuits/.yalc/@aztec/foundation/dest/transport/interface/socket.js similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/socket.js rename to circuits/.yalc/@aztec/foundation/dest/transport/interface/socket.js diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/transferable.d.ts b/circuits/.yalc/@aztec/foundation/dest/transport/interface/transferable.d.ts similarity index 70% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/transferable.d.ts rename to circuits/.yalc/@aztec/foundation/dest/transport/interface/transferable.d.ts index f8ef5f290e3..b00c1dd82fe 100644 --- a/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/transferable.d.ts +++ b/circuits/.yalc/@aztec/foundation/dest/transport/interface/transferable.d.ts @@ -1,25 +1,9 @@ declare const $transferable: unique symbol; -/** - * A descriptor representing a payload with transferable components. - * These components will have ownership transfered when published on an event bus. - */ export interface TransferDescriptor { - /** - * Marked as transferable. - */ [$transferable]: true; - /** - * The payload with the transferable objects. - */ send: T; - /** - * The objects to transfer. - */ transferables: Transferable[]; } -/** - * - */ export declare function isTransferDescriptor(thing: any): thing is TransferDescriptor; /** * Mark a transferable object as such, so it will no be serialized and @@ -34,8 +18,8 @@ export declare function isTransferDescriptor(thing: any): thing is TransferDescr * The transferable object cannot be accessed by this thread again * unless the receiving thread transfers it back again! * - * @param transferable - Array buffer, message port or similar. - * @see https://developers.google.com/web/updates/2011/12/Transferable-Objects-Lightning-Fast + * @param transferable Array buffer, message port or similar. + * @see */ export declare function Transfer(transferable: Transferable): TransferDescriptor; /** @@ -52,8 +36,8 @@ export declare function Transfer(transferable: Transferable): TransferDescrip * The transferable object cannot be accessed by this thread again * unless the receiving thread transfers it back again! * - * @param transferable - Array buffer, message port or similar. - * @see https://developers.google.com/web/updates/2011/12/Transferable-Objects-Lightning-Fast + * @param transferable Array buffer, message port or similar. + * @see */ export declare function Transfer(payload: T, transferables: Transferable[]): TransferDescriptor; export {}; diff --git a/circuits/.yalc/@aztec/foundation/dest/transport/interface/transferable.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/transport/interface/transferable.d.ts.map new file mode 100644 index 00000000000..3a8ea51b034 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/transport/interface/transferable.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"transferable.d.ts","sourceRoot":"","sources":["../../../src/transport/interface/transferable.ts"],"names":[],"mappings":"AAAA,QAAA,MAAM,aAAa,eAAgC,CAAC;AAEpD,MAAM,WAAW,kBAAkB,CAAC,CAAC,GAAG,GAAG;IACzC,CAAC,aAAa,CAAC,EAAE,IAAI,CAAC;IACtB,IAAI,EAAE,CAAC,CAAC;IACR,aAAa,EAAE,YAAY,EAAE,CAAC;CAC/B;AAQD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,GAAG,GAAG,KAAK,IAAI,kBAAkB,CAE5E;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,YAAY,EAAE,YAAY,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAAC;AAE/E;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,aAAa,EAAE,YAAY,EAAE,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/transport/interface/transferable.js b/circuits/.yalc/@aztec/foundation/dest/transport/interface/transferable.js new file mode 100644 index 00000000000..163352d6166 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/transport/interface/transferable.js @@ -0,0 +1,23 @@ +const $transferable = Symbol('thread.transferable'); +function isTransferable(thing) { + if (!thing || typeof thing !== 'object') + return false; + // Don't check too thoroughly, since the list of transferable things in JS might grow over time + return true; +} +export function isTransferDescriptor(thing) { + return thing && typeof thing === 'object' && thing[$transferable]; +} +export function Transfer(payload, transferables) { + if (!transferables) { + if (!isTransferable(payload)) + throw Error(); + transferables = [payload]; + } + return { + [$transferable]: true, + send: payload, + transferables, + }; +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhbnNmZXJhYmxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3RyYW5zcG9ydC9pbnRlcmZhY2UvdHJhbnNmZXJhYmxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE1BQU0sYUFBYSxHQUFHLE1BQU0sQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDO0FBUXBELFNBQVMsY0FBYyxDQUFDLEtBQVU7SUFDaEMsSUFBSSxDQUFDLEtBQUssSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRO1FBQUUsT0FBTyxLQUFLLENBQUM7SUFDdEQsK0ZBQStGO0lBQy9GLE9BQU8sSUFBSSxDQUFDO0FBQ2QsQ0FBQztBQUVELE1BQU0sVUFBVSxvQkFBb0IsQ0FBQyxLQUFVO0lBQzdDLE9BQU8sS0FBSyxJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVEsSUFBSSxLQUFLLENBQUMsYUFBYSxDQUFDLENBQUM7QUFDcEUsQ0FBQztBQXVDRCxNQUFNLFVBQVUsUUFBUSxDQUFJLE9BQVUsRUFBRSxhQUE4QjtJQUNwRSxJQUFJLENBQUMsYUFBYSxFQUFFO1FBQ2xCLElBQUksQ0FBQyxjQUFjLENBQUMsT0FBTyxDQUFDO1lBQUUsTUFBTSxLQUFLLEVBQUUsQ0FBQztRQUM1QyxhQUFhLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQztLQUMzQjtJQUVELE9BQU87UUFDTCxDQUFDLGFBQWEsQ0FBQyxFQUFFLElBQUk7UUFDckIsSUFBSSxFQUFFLE9BQU87UUFDYixhQUFhO0tBQ2QsQ0FBQztBQUNKLENBQUMifQ== \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/index.d.ts b/circuits/.yalc/@aztec/foundation/dest/transport/node/index.d.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/index.d.ts rename to circuits/.yalc/@aztec/foundation/dest/transport/node/index.d.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/index.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/transport/node/index.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/index.d.ts.map rename to circuits/.yalc/@aztec/foundation/dest/transport/node/index.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/index.js b/circuits/.yalc/@aztec/foundation/dest/transport/node/index.js similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/index.js rename to circuits/.yalc/@aztec/foundation/dest/transport/node/index.js diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_connector.d.ts b/circuits/.yalc/@aztec/foundation/dest/transport/node/node_connector.d.ts similarity index 74% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_connector.d.ts rename to circuits/.yalc/@aztec/foundation/dest/transport/node/node_connector.d.ts index b1d8890543c..9a1e86341a6 100644 --- a/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_connector.d.ts +++ b/circuits/.yalc/@aztec/foundation/dest/transport/node/node_connector.d.ts @@ -2,16 +2,9 @@ import { Worker } from 'worker_threads'; import { Connector } from '../interface/connector.js'; import { NodeConnectorSocket } from './node_connector_socket.js'; -/** - * Creates sockets backed by a Node worker. - */ export declare class NodeConnector implements Connector { private worker; constructor(worker: Worker); - /** - * Creates a socket backed by a node worker. - * @returns The socket. - */ createSocket(): Promise; } //# sourceMappingURL=node_connector.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_connector.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/transport/node/node_connector.d.ts.map similarity index 67% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_connector.d.ts.map rename to circuits/.yalc/@aztec/foundation/dest/transport/node/node_connector.d.ts.map index 57ef4337f76..fcaadfee1cd 100644 --- a/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_connector.d.ts.map +++ b/circuits/.yalc/@aztec/foundation/dest/transport/node/node_connector.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"node_connector.d.ts","sourceRoot":"","sources":["../../../src/transport/node/node_connector.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAEjE;;GAEG;AACH,qBAAa,aAAc,YAAW,SAAS;IACjC,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,MAAM;IAElC;;;OAGG;IACH,YAAY;CAGb"} \ No newline at end of file +{"version":3,"file":"node_connector.d.ts","sourceRoot":"","sources":["../../../src/transport/node/node_connector.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAEjE,qBAAa,aAAc,YAAW,SAAS;IACjC,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,MAAM;IAElC,YAAY;CAGb"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_connector.js b/circuits/.yalc/@aztec/foundation/dest/transport/node/node_connector.js similarity index 53% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_connector.js rename to circuits/.yalc/@aztec/foundation/dest/transport/node/node_connector.js index 2525dc38092..24e90bc5137 100644 --- a/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_connector.js +++ b/circuits/.yalc/@aztec/foundation/dest/transport/node/node_connector.js @@ -1,17 +1,10 @@ import { NodeConnectorSocket } from './node_connector_socket.js'; -/** - * Creates sockets backed by a Node worker. - */ export class NodeConnector { constructor(worker) { this.worker = worker; } - /** - * Creates a socket backed by a node worker. - * @returns The socket. - */ createSocket() { return Promise.resolve(new NodeConnectorSocket(this.worker)); } } -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZV9jb25uZWN0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvdHJhbnNwb3J0L25vZGUvbm9kZV9jb25uZWN0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBRUEsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFFakU7O0dBRUc7QUFDSCxNQUFNLE9BQU8sYUFBYTtJQUN4QixZQUFvQixNQUFjO1FBQWQsV0FBTSxHQUFOLE1BQU0sQ0FBUTtJQUFHLENBQUM7SUFFdEM7OztPQUdHO0lBQ0gsWUFBWTtRQUNWLE9BQU8sT0FBTyxDQUFDLE9BQU8sQ0FBQyxJQUFJLG1CQUFtQixDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDO0lBQy9ELENBQUM7Q0FDRiJ9 \ No newline at end of file +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZV9jb25uZWN0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvdHJhbnNwb3J0L25vZGUvbm9kZV9jb25uZWN0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBRUEsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFFakUsTUFBTSxPQUFPLGFBQWE7SUFDeEIsWUFBb0IsTUFBYztRQUFkLFdBQU0sR0FBTixNQUFNLENBQVE7SUFBRyxDQUFDO0lBRXRDLFlBQVk7UUFDVixPQUFPLE9BQU8sQ0FBQyxPQUFPLENBQUMsSUFBSSxtQkFBbUIsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQztJQUMvRCxDQUFDO0NBQ0YifQ== \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_connector_socket.d.ts b/circuits/.yalc/@aztec/foundation/dest/transport/node/node_connector_socket.d.ts similarity index 54% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_connector_socket.d.ts rename to circuits/.yalc/@aztec/foundation/dest/transport/node/node_connector_socket.d.ts index a87192030c2..d627fea0e84 100644 --- a/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_connector_socket.d.ts +++ b/circuits/.yalc/@aztec/foundation/dest/transport/node/node_connector_socket.d.ts @@ -1,27 +1,11 @@ /// import { Worker } from 'worker_threads'; import { Socket } from '../interface/socket.js'; -/** - * A socket implementation using a Node worker. - */ export declare class NodeConnectorSocket implements Socket { private worker; constructor(worker: Worker); - /** - * Send a message. - * @param msg - The message. - * @param transfer - Objects to transfer ownership of. - * @returns A void promise. - */ send(msg: any, transfer?: Transferable[]): Promise; - /** - * Register a message handler. - * @param cb - The handler function. - */ registerHandler(cb: (msg: any) => any): void; - /** - * Remove all listeners from our worker. - */ close(): void; } //# sourceMappingURL=node_connector_socket.d.ts.map \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/transport/node/node_connector_socket.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/transport/node/node_connector_socket.d.ts.map new file mode 100644 index 00000000000..0e244422e21 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/transport/node/node_connector_socket.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"node_connector_socket.d.ts","sourceRoot":"","sources":["../../../src/transport/node/node_connector_socket.ts"],"names":[],"mappings":";AAAA,OAAO,EAAoB,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAEhD,qBAAa,mBAAoB,YAAW,MAAM;IACpC,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,MAAM;IAElC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,GAAE,YAAY,EAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAK5D,eAAe,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,GAAG,GAAG,IAAI;IAI5C,KAAK;CAIN"} \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/transport/node/node_connector_socket.js b/circuits/.yalc/@aztec/foundation/dest/transport/node/node_connector_socket.js new file mode 100644 index 00000000000..da6def001fb --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/transport/node/node_connector_socket.js @@ -0,0 +1,17 @@ +export class NodeConnectorSocket { + constructor(worker) { + this.worker = worker; + } + send(msg, transfer = []) { + this.worker.postMessage(msg, transfer); + return Promise.resolve(); + } + registerHandler(cb) { + this.worker.on('message', cb); + } + close() { + void this.send(undefined); + this.worker.removeAllListeners(); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZV9jb25uZWN0b3Jfc29ja2V0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3RyYW5zcG9ydC9ub2RlL25vZGVfY29ubmVjdG9yX3NvY2tldC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFHQSxNQUFNLE9BQU8sbUJBQW1CO0lBQzlCLFlBQW9CLE1BQWM7UUFBZCxXQUFNLEdBQU4sTUFBTSxDQUFRO0lBQUcsQ0FBQztJQUV0QyxJQUFJLENBQUMsR0FBUSxFQUFFLFdBQTJCLEVBQUU7UUFDMUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxXQUFXLENBQUMsR0FBRyxFQUFFLFFBQThCLENBQUMsQ0FBQztRQUM3RCxPQUFPLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQztJQUMzQixDQUFDO0lBRUQsZUFBZSxDQUFDLEVBQXFCO1FBQ25DLElBQUksQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLFNBQVMsRUFBRSxFQUFFLENBQUMsQ0FBQztJQUNoQyxDQUFDO0lBRUQsS0FBSztRQUNILEtBQUssSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUMxQixJQUFJLENBQUMsTUFBTSxDQUFDLGtCQUFrQixFQUFFLENBQUM7SUFDbkMsQ0FBQztDQUNGIn0= \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_listener.d.ts b/circuits/.yalc/@aztec/foundation/dest/transport/node/node_listener.d.ts similarity index 70% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_listener.d.ts rename to circuits/.yalc/@aztec/foundation/dest/transport/node/node_listener.d.ts index e9bf26a20ce..bc8632e3336 100644 --- a/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_listener.d.ts +++ b/circuits/.yalc/@aztec/foundation/dest/transport/node/node_listener.d.ts @@ -1,18 +1,9 @@ /// import EventEmitter from 'events'; import { Listener } from '../interface/listener.js'; -/** - * A socket listener that works with Node. - */ export declare class NodeListener extends EventEmitter implements Listener { constructor(); - /** - * Open the listener. - */ open(): void; - /** - * Close the listener. - */ close(): void; } //# sourceMappingURL=node_listener.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_listener.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/transport/node/node_listener.d.ts.map similarity index 61% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_listener.d.ts.map rename to circuits/.yalc/@aztec/foundation/dest/transport/node/node_listener.d.ts.map index e15acee10b1..30f0580d386 100644 --- a/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_listener.d.ts.map +++ b/circuits/.yalc/@aztec/foundation/dest/transport/node/node_listener.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"node_listener.d.ts","sourceRoot":"","sources":["../../../src/transport/node/node_listener.ts"],"names":[],"mappings":";AACA,OAAO,YAAY,MAAM,QAAQ,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAGpD;;GAEG;AACH,qBAAa,YAAa,SAAQ,YAAa,YAAW,QAAQ;;IAKhE;;OAEG;IACH,IAAI;IAIJ;;OAEG;IACH,KAAK;CACN"} \ No newline at end of file +{"version":3,"file":"node_listener.d.ts","sourceRoot":"","sources":["../../../src/transport/node/node_listener.ts"],"names":[],"mappings":";AACA,OAAO,YAAY,MAAM,QAAQ,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAGpD,qBAAa,YAAa,SAAQ,YAAa,YAAW,QAAQ;;IAKhE,IAAI;IAIJ,KAAK;CACN"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_listener.js b/circuits/.yalc/@aztec/foundation/dest/transport/node/node_listener.js similarity index 62% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_listener.js rename to circuits/.yalc/@aztec/foundation/dest/transport/node/node_listener.js index 318369699af..666e8badac4 100644 --- a/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_listener.js +++ b/circuits/.yalc/@aztec/foundation/dest/transport/node/node_listener.js @@ -1,22 +1,13 @@ import { parentPort } from 'worker_threads'; import EventEmitter from 'events'; import { NodeListenerSocket } from './node_listener_socket.js'; -/** - * A socket listener that works with Node. - */ export class NodeListener extends EventEmitter { constructor() { super(); } - /** - * Open the listener. - */ open() { this.emit('new_socket', new NodeListenerSocket(parentPort)); } - /** - * Close the listener. - */ close() { } } -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZV9saXN0ZW5lci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy90cmFuc3BvcnQvbm9kZS9ub2RlX2xpc3RlbmVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUM1QyxPQUFPLFlBQVksTUFBTSxRQUFRLENBQUM7QUFFbEMsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFFL0Q7O0dBRUc7QUFDSCxNQUFNLE9BQU8sWUFBYSxTQUFRLFlBQVk7SUFDNUM7UUFDRSxLQUFLLEVBQUUsQ0FBQztJQUNWLENBQUM7SUFFRDs7T0FFRztJQUNILElBQUk7UUFDRixJQUFJLENBQUMsSUFBSSxDQUFDLFlBQVksRUFBRSxJQUFJLGtCQUFrQixDQUFDLFVBQWlCLENBQUMsQ0FBQyxDQUFDO0lBQ3JFLENBQUM7SUFFRDs7T0FFRztJQUNILEtBQUssS0FBSSxDQUFDO0NBQ1gifQ== \ No newline at end of file +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZV9saXN0ZW5lci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy90cmFuc3BvcnQvbm9kZS9ub2RlX2xpc3RlbmVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUM1QyxPQUFPLFlBQVksTUFBTSxRQUFRLENBQUM7QUFFbEMsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFFL0QsTUFBTSxPQUFPLFlBQWEsU0FBUSxZQUFZO0lBQzVDO1FBQ0UsS0FBSyxFQUFFLENBQUM7SUFDVixDQUFDO0lBRUQsSUFBSTtRQUNGLElBQUksQ0FBQyxJQUFJLENBQUMsWUFBWSxFQUFFLElBQUksa0JBQWtCLENBQUMsVUFBaUIsQ0FBQyxDQUFDLENBQUM7SUFDckUsQ0FBQztJQUVELEtBQUssS0FBSSxDQUFDO0NBQ1gifQ== \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_listener_socket.d.ts b/circuits/.yalc/@aztec/foundation/dest/transport/node/node_listener_socket.d.ts similarity index 63% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_listener_socket.d.ts rename to circuits/.yalc/@aztec/foundation/dest/transport/node/node_listener_socket.d.ts index ee114126deb..85fe837b26a 100644 --- a/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_listener_socket.d.ts +++ b/circuits/.yalc/@aztec/foundation/dest/transport/node/node_listener_socket.d.ts @@ -7,21 +7,8 @@ import { Socket } from '../interface/socket.js'; export declare class NodeListenerSocket implements Socket { private port; constructor(port: MessagePort); - /** - * Send a message over this port. - * @param msg - The message. - * @param transfer - Transferable objects. - * @returns A void promise. - */ send(msg: any, transfer?: Transferable[]): Promise; - /** - * Add a handler to this port. - * @param cb - The handler function. - */ registerHandler(cb: (msg: any) => any): void; - /** - * Close this socket. - */ close(): void; } //# sourceMappingURL=node_listener_socket.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_listener_socket.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/transport/node/node_listener_socket.d.ts.map similarity index 61% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_listener_socket.d.ts.map rename to circuits/.yalc/@aztec/foundation/dest/transport/node/node_listener_socket.d.ts.map index 31986e0cd02..02b25c7758d 100644 --- a/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/node_listener_socket.d.ts.map +++ b/circuits/.yalc/@aztec/foundation/dest/transport/node/node_listener_socket.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"node_listener_socket.d.ts","sourceRoot":"","sources":["../../../src/transport/node/node_listener_socket.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,WAAW,EAAoB,MAAM,gBAAgB,CAAC;AAC/D,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAEhD;;GAEG;AACH,qBAAa,kBAAmB,YAAW,MAAM;IACnC,OAAO,CAAC,IAAI;gBAAJ,IAAI,EAAE,WAAW;IAErC;;;;;OAKG;IACH,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,GAAE,YAAY,EAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAK5D;;;OAGG;IACH,eAAe,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,GAAG,GAAG,IAAI;IAI5C;;OAEG;IACH,KAAK;CAKN"} \ No newline at end of file +{"version":3,"file":"node_listener_socket.d.ts","sourceRoot":"","sources":["../../../src/transport/node/node_listener_socket.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,WAAW,EAAoB,MAAM,gBAAgB,CAAC;AAC/D,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAEhD;;GAEG;AACH,qBAAa,kBAAmB,YAAW,MAAM;IACnC,OAAO,CAAC,IAAI;gBAAJ,IAAI,EAAE,WAAW;IAErC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,GAAE,YAAY,EAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAK5D,eAAe,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,GAAG,GAAG,IAAI;IAI5C,KAAK;CAKN"} \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/transport/node/node_listener_socket.js b/circuits/.yalc/@aztec/foundation/dest/transport/node/node_listener_socket.js new file mode 100644 index 00000000000..16ffdfacb9e --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/transport/node/node_listener_socket.js @@ -0,0 +1,21 @@ +/** + * An implementation of a TransportSocket using MessagePorts. + */ +export class NodeListenerSocket { + constructor(port) { + this.port = port; + } + send(msg, transfer = []) { + this.port.postMessage(msg, transfer); + return Promise.resolve(); + } + registerHandler(cb) { + this.port.on('message', cb); + } + close() { + void this.send(undefined); + this.port.removeAllListeners(); + this.port.close(); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZV9saXN0ZW5lcl9zb2NrZXQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvdHJhbnNwb3J0L25vZGUvbm9kZV9saXN0ZW5lcl9zb2NrZXQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBR0E7O0dBRUc7QUFDSCxNQUFNLE9BQU8sa0JBQWtCO0lBQzdCLFlBQW9CLElBQWlCO1FBQWpCLFNBQUksR0FBSixJQUFJLENBQWE7SUFBRyxDQUFDO0lBRXpDLElBQUksQ0FBQyxHQUFRLEVBQUUsV0FBMkIsRUFBRTtRQUMxQyxJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxHQUFHLEVBQUUsUUFBOEIsQ0FBQyxDQUFDO1FBQzNELE9BQU8sT0FBTyxDQUFDLE9BQU8sRUFBRSxDQUFDO0lBQzNCLENBQUM7SUFFRCxlQUFlLENBQUMsRUFBcUI7UUFDbkMsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsU0FBUyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQzlCLENBQUM7SUFFRCxLQUFLO1FBQ0gsS0FBSyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQzFCLElBQUksQ0FBQyxJQUFJLENBQUMsa0JBQWtCLEVBQUUsQ0FBQztRQUMvQixJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQ3BCLENBQUM7Q0FDRiJ9 \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/transport_client.d.ts b/circuits/.yalc/@aztec/foundation/dest/transport/transport_client.d.ts similarity index 68% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/transport_client.d.ts rename to circuits/.yalc/@aztec/foundation/dest/transport/transport_client.d.ts index a70ae9fea5e..631e8737938 100644 --- a/circuits/ts/.yalc/@aztec/wasm/dest/transport/transport_client.d.ts +++ b/circuits/.yalc/@aztec/foundation/dest/transport/transport_client.d.ts @@ -1,9 +1,6 @@ /// import EventEmitter from 'events'; import { Connector } from './interface/connector.js'; -/** - * Augments the TransportClient class with more precise EventEmitter types. - */ export interface TransportClient extends EventEmitter { on(name: 'event_msg', handler: (payload: Payload) => void): this; emit(name: 'event_msg', payload: Payload): boolean; @@ -20,25 +17,9 @@ export declare class TransportClient extends EventEmitter { private pendingRequests; private socket?; constructor(transportConnect: Connector); - /** - * Create and register our socket using our Connector. - */ open(): Promise; - /** - * Close this and stop listening for messages. - */ close(): void; - /** - * Queue a request. - * @param payload - The request payload. - * @param transfer - Objects to transfer ownership of. - * @returns A promise of the query result. - */ request(payload: Payload, transfer?: Transferable[]): Promise; - /** - * Handle an incoming socket message. - * @param msg - The message. - */ private handleSocketMessage; } //# sourceMappingURL=transport_client.d.ts.map \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/transport/transport_client.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/transport/transport_client.d.ts.map new file mode 100644 index 00000000000..e305e8cecb5 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/transport/transport_client.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"transport_client.d.ts","sourceRoot":"","sources":["../../src/transport/transport_client.ts"],"names":[],"mappings":";AAAA,OAAO,YAAY,MAAM,QAAQ,CAAC;AAElC,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAYrD,MAAM,WAAW,eAAe,CAAC,OAAO,CAAE,SAAQ,YAAY;IAC5D,EAAE,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI,CAAC;IACjE,IAAI,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC;CACpD;AAED;;;;;GAKG;AACH,qBAAa,eAAe,CAAC,OAAO,CAAE,SAAQ,YAAY;IAK5C,OAAO,CAAC,gBAAgB;IAJpC,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,eAAe,CAAwB;IAC/C,OAAO,CAAC,MAAM,CAAC,CAAS;gBAEJ,gBAAgB,EAAE,SAAS;IAIzC,IAAI;IAKV,KAAK;IAML,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,YAAY,EAAE;IAanD,OAAO,CAAC,mBAAmB;CAsB5B"} \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/dest/transport/transport_client.js b/circuits/.yalc/@aztec/foundation/dest/transport/transport_client.js new file mode 100644 index 00000000000..ba563aebd8b --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/dest/transport/transport_client.js @@ -0,0 +1,63 @@ +import EventEmitter from 'events'; +import { isEventMessage } from './dispatch/messages.js'; +import { createDebugLogger } from '../log/index.js'; +const debug = createDebugLogger('aztec:transport_client'); +/** + * A TransportClient provides a request/response and event api to a corresponding TransportServer. + * If `broadcast` is called on TransportServer, TransportClients will emit an `event_msg`. + * The `request` method will block until a response is returned from the TransportServer's dispatch function. + * Request multiplexing is supported. + */ +export class TransportClient extends EventEmitter { + constructor(transportConnect) { + super(); + this.transportConnect = transportConnect; + this.msgId = 0; + this.pendingRequests = []; + } + async open() { + this.socket = await this.transportConnect.createSocket(); + this.socket.registerHandler(msg => this.handleSocketMessage(msg)); + } + close() { + this.socket?.close(); + this.socket = undefined; + this.removeAllListeners(); + } + request(payload, transfer) { + if (!this.socket) { + throw new Error('Socket not open.'); + } + const msgId = this.msgId++; + const msg = { msgId, payload }; + debug(`->`, msg); + return new Promise((resolve, reject) => { + this.pendingRequests.push({ resolve, reject, msgId }); + this.socket.send(msg, transfer).catch(reject); + }); + } + handleSocketMessage(msg) { + if (msg === undefined) { + // The remote socket closed. + this.close(); + return; + } + debug(`<-`, msg); + if (isEventMessage(msg)) { + this.emit('event_msg', msg.payload); + return; + } + const reqIndex = this.pendingRequests.findIndex(r => r.msgId === msg.msgId); + if (reqIndex === -1) { + return; + } + const [pending] = this.pendingRequests.splice(reqIndex, 1); + if (msg.error) { + pending.reject(new Error(msg.error)); + } + else { + pending.resolve(msg.payload); + } + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhbnNwb3J0X2NsaWVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90cmFuc3BvcnQvdHJhbnNwb3J0X2NsaWVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLFlBQVksTUFBTSxRQUFRLENBQUM7QUFDbEMsT0FBTyxFQUFnQixjQUFjLEVBQW1CLE1BQU0sd0JBQXdCLENBQUM7QUFHdkYsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFFcEQsTUFBTSxLQUFLLEdBQUcsaUJBQWlCLENBQUMsd0JBQXdCLENBQUMsQ0FBQztBQWExRDs7Ozs7R0FLRztBQUNILE1BQU0sT0FBTyxlQUF5QixTQUFRLFlBQVk7SUFLeEQsWUFBb0IsZ0JBQTJCO1FBQzdDLEtBQUssRUFBRSxDQUFDO1FBRFUscUJBQWdCLEdBQWhCLGdCQUFnQixDQUFXO1FBSnZDLFVBQUssR0FBRyxDQUFDLENBQUM7UUFDVixvQkFBZSxHQUFxQixFQUFFLENBQUM7SUFLL0MsQ0FBQztJQUVELEtBQUssQ0FBQyxJQUFJO1FBQ1IsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxZQUFZLEVBQUUsQ0FBQztRQUN6RCxJQUFJLENBQUMsTUFBTSxDQUFDLGVBQWUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQ3BFLENBQUM7SUFFRCxLQUFLO1FBQ0gsSUFBSSxDQUFDLE1BQU0sRUFBRSxLQUFLLEVBQUUsQ0FBQztRQUNyQixJQUFJLENBQUMsTUFBTSxHQUFHLFNBQVMsQ0FBQztRQUN4QixJQUFJLENBQUMsa0JBQWtCLEVBQUUsQ0FBQztJQUM1QixDQUFDO0lBRUQsT0FBTyxDQUFDLE9BQWdCLEVBQUUsUUFBeUI7UUFDakQsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUU7WUFDaEIsTUFBTSxJQUFJLEtBQUssQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDO1NBQ3JDO1FBQ0QsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQzNCLE1BQU0sR0FBRyxHQUFHLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxDQUFDO1FBQy9CLEtBQUssQ0FBQyxJQUFJLEVBQUUsR0FBRyxDQUFDLENBQUM7UUFDakIsT0FBTyxJQUFJLE9BQU8sQ0FBTSxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsRUFBRTtZQUMxQyxJQUFJLENBQUMsZUFBZSxDQUFDLElBQUksQ0FBQyxFQUFFLE9BQU8sRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztZQUN0RCxJQUFJLENBQUMsTUFBTyxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsUUFBUSxDQUFDLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ2pELENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVPLG1CQUFtQixDQUFDLEdBQWlFO1FBQzNGLElBQUksR0FBRyxLQUFLLFNBQVMsRUFBRTtZQUNyQiw0QkFBNEI7WUFDNUIsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ2IsT0FBTztTQUNSO1FBQ0QsS0FBSyxDQUFDLElBQUksRUFBRSxHQUFHLENBQUMsQ0FBQztRQUNqQixJQUFJLGNBQWMsQ0FBQyxHQUFHLENBQUMsRUFBRTtZQUN2QixJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRSxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUM7WUFDcEMsT0FBTztTQUNSO1FBQ0QsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLGVBQWUsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsS0FBSyxLQUFLLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUM1RSxJQUFJLFFBQVEsS0FBSyxDQUFDLENBQUMsRUFBRTtZQUNuQixPQUFPO1NBQ1I7UUFDRCxNQUFNLENBQUMsT0FBTyxDQUFDLEdBQUcsSUFBSSxDQUFDLGVBQWUsQ0FBQyxNQUFNLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBQzNELElBQUksR0FBRyxDQUFDLEtBQUssRUFBRTtZQUNiLE9BQU8sQ0FBQyxNQUFNLENBQUMsSUFBSSxLQUFLLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7U0FDdEM7YUFBTTtZQUNMLE9BQU8sQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1NBQzlCO0lBQ0gsQ0FBQztDQUNGIn0= \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/transport_server.d.ts b/circuits/.yalc/@aztec/foundation/dest/transport/transport_server.d.ts similarity index 64% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/transport_server.d.ts rename to circuits/.yalc/@aztec/foundation/dest/transport/transport_server.d.ts index 109e9210f8b..d929f1a70d3 100644 --- a/circuits/ts/.yalc/@aztec/wasm/dest/transport/transport_server.d.ts +++ b/circuits/.yalc/@aztec/foundation/dest/transport/transport_server.d.ts @@ -7,38 +7,19 @@ export declare class TransportServer { private msgHandlerFn; private sockets; constructor(listener: Listener, msgHandlerFn: (msg: Payload) => Promise); - /** - * Start accepting new connections. - */ start(): void; /** * Stops accepting new connections. It doesn't close existing sockets. * It's expected the clients will gracefully complete by closing their end, sending an `undefined` message. */ stop(): void; - /** - * Broadcast a message. - * @param msg - The message. - */ broadcast(msg: Payload): Promise; - /** - * New socket registration. - * @param socket - The socket to register. - */ private handleNewSocket; /** * Detect the 'transferables' argument to our socket from our message * handler return type. - * @param data - The return object. - * @returns - The data and the. */ private getPayloadAndTransfers; - /** - * Handles a socket message from a listener. - * @param socket - The socket. - * @param requestMessage - The message to handle. - * @returns The socket response. - */ private handleSocketMessage; } //# sourceMappingURL=transport_server.d.ts.map \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/transport_server.d.ts.map b/circuits/.yalc/@aztec/foundation/dest/transport/transport_server.d.ts.map similarity index 57% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/transport_server.d.ts.map rename to circuits/.yalc/@aztec/foundation/dest/transport/transport_server.d.ts.map index 103804f9808..8fcb26702d3 100644 --- a/circuits/ts/.yalc/@aztec/wasm/dest/transport/transport_server.d.ts.map +++ b/circuits/.yalc/@aztec/foundation/dest/transport/transport_server.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"transport_server.d.ts","sourceRoot":"","sources":["../../src/transport/transport_server.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAInD;;GAEG;AACH,qBAAa,eAAe,CAAC,OAAO;IAGtB,OAAO,CAAC,QAAQ;IAAY,OAAO,CAAC,YAAY;IAF5D,OAAO,CAAC,OAAO,CAAgB;gBAEX,QAAQ,EAAE,QAAQ,EAAU,YAAY,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,GAAG,CAAC;IAE5F;;OAEG;IACH,KAAK;IAKL;;;OAGG;IACH,IAAI;IAIJ;;;OAGG;IACG,SAAS,CAAC,GAAG,EAAE,OAAO;IAI5B;;;OAGG;IACH,OAAO,CAAC,eAAe;IAcvB;;;;;OAKG;IACH,OAAO,CAAC,sBAAsB;IAe9B;;;;;OAKG;YACW,mBAAmB;CAalC"} \ No newline at end of file +{"version":3,"file":"transport_server.d.ts","sourceRoot":"","sources":["../../src/transport/transport_server.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAInD;;GAEG;AACH,qBAAa,eAAe,CAAC,OAAO;IAGtB,OAAO,CAAC,QAAQ;IAAY,OAAO,CAAC,YAAY;IAF5D,OAAO,CAAC,OAAO,CAAgB;gBAEX,QAAQ,EAAE,QAAQ,EAAU,YAAY,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,GAAG,CAAC;IAE5F,KAAK;IAKL;;;OAGG;IACH,IAAI;IAIE,SAAS,CAAC,GAAG,EAAE,OAAO;IAI5B,OAAO,CAAC,eAAe;IAcvB;;;OAGG;IACH,OAAO,CAAC,sBAAsB;YAehB,mBAAmB;CAalC"} \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/transport_server.js b/circuits/.yalc/@aztec/foundation/dest/transport/transport_server.js similarity index 50% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/transport_server.js rename to circuits/.yalc/@aztec/foundation/dest/transport/transport_server.js index b1865345fc4..febfd312f42 100644 --- a/circuits/ts/.yalc/@aztec/wasm/dest/transport/transport_server.js +++ b/circuits/.yalc/@aztec/foundation/dest/transport/transport_server.js @@ -8,9 +8,6 @@ export class TransportServer { this.msgHandlerFn = msgHandlerFn; this.sockets = []; } - /** - * Start accepting new connections. - */ start() { this.listener.on('new_socket', client => this.handleNewSocket(client)); this.listener.open(); @@ -22,17 +19,9 @@ export class TransportServer { stop() { this.listener.close(); } - /** - * Broadcast a message. - * @param msg - The message. - */ async broadcast(msg) { await Promise.all(this.sockets.map(s => s.send({ payload: msg }))); } - /** - * New socket registration. - * @param socket - The socket to register. - */ handleNewSocket(socket) { socket.registerHandler(async (msg) => { if (msg === undefined) { @@ -49,8 +38,6 @@ export class TransportServer { /** * Detect the 'transferables' argument to our socket from our message * handler return type. - * @param data - The return object. - * @returns - The data and the. */ getPayloadAndTransfers(data) { if (isTransferDescriptor(data)) { @@ -67,12 +54,6 @@ export class TransportServer { } return [data, []]; } - /** - * Handles a socket message from a listener. - * @param socket - The socket. - * @param requestMessage - The message to handle. - * @returns The socket response. - */ async handleSocketMessage(socket, { msgId, payload }) { try { const data = await this.msgHandlerFn(payload); @@ -86,4 +67,4 @@ export class TransportServer { } } } -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhbnNwb3J0X3NlcnZlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90cmFuc3BvcnQvdHJhbnNwb3J0X3NlcnZlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFHQSxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUVuRTs7R0FFRztBQUNILE1BQU0sT0FBTyxlQUFlO0lBRzFCLFlBQW9CLFFBQWtCLEVBQVUsWUFBNEM7UUFBeEUsYUFBUSxHQUFSLFFBQVEsQ0FBVTtRQUFVLGlCQUFZLEdBQVosWUFBWSxDQUFnQztRQUZwRixZQUFPLEdBQWEsRUFBRSxDQUFDO0lBRWdFLENBQUM7SUFFaEc7O09BRUc7SUFDSCxLQUFLO1FBQ0gsSUFBSSxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUMsWUFBWSxFQUFFLE1BQU0sQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDO1FBQ3ZFLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDdkIsQ0FBQztJQUVEOzs7T0FHRztJQUNILElBQUk7UUFDRixJQUFJLENBQUMsUUFBUSxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQ3hCLENBQUM7SUFFRDs7O09BR0c7SUFDSCxLQUFLLENBQUMsU0FBUyxDQUFDLEdBQVk7UUFDMUIsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxFQUFFLE9BQU8sRUFBRSxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNyRSxDQUFDO0lBRUQ7OztPQUdHO0lBQ0ssZUFBZSxDQUFDLE1BQWM7UUFDcEMsTUFBTSxDQUFDLGVBQWUsQ0FBQyxLQUFLLEVBQUMsR0FBRyxFQUFDLEVBQUU7WUFDakMsSUFBSSxHQUFHLEtBQUssU0FBUyxFQUFFO2dCQUNyQixrR0FBa0c7Z0JBQ2xHLE1BQU0sV0FBVyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxLQUFLLE1BQU0sQ0FBQyxDQUFDO2dCQUM5RCxNQUFNLENBQUMsYUFBYSxDQUFDLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsV0FBVyxFQUFFLENBQUMsQ0FBQyxDQUFDO2dCQUM1RCxhQUFhLENBQUMsS0FBSyxFQUFFLENBQUM7Z0JBQ3RCLE9BQU87YUFDUjtZQUNELE9BQU8sTUFBTSxJQUFJLENBQUMsbUJBQW1CLENBQUMsTUFBTSxFQUFFLEdBQUcsQ0FBQyxDQUFDO1FBQ3JELENBQUMsQ0FBQyxDQUFDO1FBQ0gsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDNUIsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ0ssc0JBQXNCLENBQUMsSUFBUztRQUN0QyxJQUFJLG9CQUFvQixDQUFDLElBQUksQ0FBQyxFQUFFO1lBQzlCLGdFQUFnRTtZQUNoRSxzRUFBc0U7WUFDdEUsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDO1NBQ3hDO1FBQ0QsSUFBSSxJQUFJLFlBQVksVUFBVSxFQUFFO1lBQzlCLDRHQUE0RztZQUM1Ryw0R0FBNEc7WUFDNUcsTUFBTSxXQUFXLEdBQUcsSUFBSSxZQUFZLFVBQVUsSUFBSSxXQUFXLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLFVBQVUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDO1lBQ3pHLE1BQU0sYUFBYSxHQUFHLElBQUksWUFBWSxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsV0FBVyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7WUFDN0UsT0FBTyxDQUFDLFdBQVcsRUFBRSxhQUFhLENBQUMsQ0FBQztTQUNyQztRQUNELE9BQU8sQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDcEIsQ0FBQztJQUNEOzs7OztPQUtHO0lBQ0ssS0FBSyxDQUFDLG1CQUFtQixDQUFDLE1BQWMsRUFBRSxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQTJCO1FBQzNGLElBQUk7WUFDRixNQUFNLElBQUksR0FBRyxNQUFNLElBQUksQ0FBQyxZQUFZLENBQUMsT0FBTyxDQUFDLENBQUM7WUFFOUMsTUFBTSxDQUFDLFdBQVcsRUFBRSxhQUFhLENBQUMsR0FBRyxJQUFJLENBQUMsc0JBQXNCLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDdkUsTUFBTSxHQUFHLEdBQTZCLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxXQUFXLEVBQUUsQ0FBQztZQUV0RSxNQUFNLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLGFBQWEsQ0FBQyxDQUFDO1NBQ3ZDO1FBQUMsT0FBTyxHQUFRLEVBQUU7WUFDakIsTUFBTSxHQUFHLEdBQTZCLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxHQUFHLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDbEUsTUFBTSxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1NBQ3hCO0lBQ0gsQ0FBQztDQUNGIn0= \ No newline at end of file +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhbnNwb3J0X3NlcnZlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90cmFuc3BvcnQvdHJhbnNwb3J0X3NlcnZlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFHQSxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUVuRTs7R0FFRztBQUNILE1BQU0sT0FBTyxlQUFlO0lBRzFCLFlBQW9CLFFBQWtCLEVBQVUsWUFBNEM7UUFBeEUsYUFBUSxHQUFSLFFBQVEsQ0FBVTtRQUFVLGlCQUFZLEdBQVosWUFBWSxDQUFnQztRQUZwRixZQUFPLEdBQWEsRUFBRSxDQUFDO0lBRWdFLENBQUM7SUFFaEcsS0FBSztRQUNILElBQUksQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDLFlBQVksRUFBRSxNQUFNLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQztRQUN2RSxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksRUFBRSxDQUFDO0lBQ3ZCLENBQUM7SUFFRDs7O09BR0c7SUFDSCxJQUFJO1FBQ0YsSUFBSSxDQUFDLFFBQVEsQ0FBQyxLQUFLLEVBQUUsQ0FBQztJQUN4QixDQUFDO0lBRUQsS0FBSyxDQUFDLFNBQVMsQ0FBQyxHQUFZO1FBQzFCLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFBRSxPQUFPLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDckUsQ0FBQztJQUVPLGVBQWUsQ0FBQyxNQUFjO1FBQ3BDLE1BQU0sQ0FBQyxlQUFlLENBQUMsS0FBSyxFQUFDLEdBQUcsRUFBQyxFQUFFO1lBQ2pDLElBQUksR0FBRyxLQUFLLFNBQVMsRUFBRTtnQkFDckIsa0dBQWtHO2dCQUNsRyxNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsS0FBSyxNQUFNLENBQUMsQ0FBQztnQkFDOUQsTUFBTSxDQUFDLGFBQWEsQ0FBQyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLFdBQVcsRUFBRSxDQUFDLENBQUMsQ0FBQztnQkFDNUQsYUFBYSxDQUFDLEtBQUssRUFBRSxDQUFDO2dCQUN0QixPQUFPO2FBQ1I7WUFDRCxPQUFPLE1BQU0sSUFBSSxDQUFDLG1CQUFtQixDQUFDLE1BQU0sRUFBRSxHQUFHLENBQUMsQ0FBQztRQUNyRCxDQUFDLENBQUMsQ0FBQztRQUNILElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQzVCLENBQUM7SUFFRDs7O09BR0c7SUFDSyxzQkFBc0IsQ0FBQyxJQUFTO1FBQ3RDLElBQUksb0JBQW9CLENBQUMsSUFBSSxDQUFDLEVBQUU7WUFDOUIsZ0VBQWdFO1lBQ2hFLHNFQUFzRTtZQUN0RSxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUM7U0FDeEM7UUFDRCxJQUFJLElBQUksWUFBWSxVQUFVLEVBQUU7WUFDOUIsNEdBQTRHO1lBQzVHLDRHQUE0RztZQUM1RyxNQUFNLFdBQVcsR0FBRyxJQUFJLFlBQVksVUFBVSxJQUFJLFdBQVcsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUM7WUFDekcsTUFBTSxhQUFhLEdBQUcsSUFBSSxZQUFZLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztZQUM3RSxPQUFPLENBQUMsV0FBVyxFQUFFLGFBQWEsQ0FBQyxDQUFDO1NBQ3JDO1FBQ0QsT0FBTyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsQ0FBQztJQUNwQixDQUFDO0lBQ08sS0FBSyxDQUFDLG1CQUFtQixDQUFDLE1BQWMsRUFBRSxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQTJCO1FBQzNGLElBQUk7WUFDRixNQUFNLElBQUksR0FBRyxNQUFNLElBQUksQ0FBQyxZQUFZLENBQUMsT0FBTyxDQUFDLENBQUM7WUFFOUMsTUFBTSxDQUFDLFdBQVcsRUFBRSxhQUFhLENBQUMsR0FBRyxJQUFJLENBQUMsc0JBQXNCLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDdkUsTUFBTSxHQUFHLEdBQTZCLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxXQUFXLEVBQUUsQ0FBQztZQUV0RSxNQUFNLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLGFBQWEsQ0FBQyxDQUFDO1NBQ3ZDO1FBQUMsT0FBTyxHQUFRLEVBQUU7WUFDakIsTUFBTSxHQUFHLEdBQTZCLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxHQUFHLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDbEUsTUFBTSxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1NBQ3hCO0lBQ0gsQ0FBQztDQUNGIn0= \ No newline at end of file diff --git a/circuits/.yalc/@aztec/foundation/package.json b/circuits/.yalc/@aztec/foundation/package.json new file mode 100644 index 00000000000..a3ee053cf7a --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/package.json @@ -0,0 +1,39 @@ +{ + "name": "@aztec/foundation", + "version": "0.0.0", + "packageManager": "yarn@3.4.1", + "private": true, + "type": "module", + "exports": { + ".": "./dest/index.js", + "./eslint": "./.eslintrc.cjs", + "./prettier": "./.prettierrc.json" + }, + "scripts": { + "build": "yarn clean && tsc -b tsconfig.dest.json", + "build:dev": "tsc -b tsconfig.dest.json --watch", + "clean": "rm -rf ./dest .tsbuildinfo", + "formatting": "prettier --check ./src && eslint --max-warnings 0 ./src", + "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --no-cache" + }, + "jest": { + "preset": "ts-jest/presets/default-esm", + "globals": { + "ts-jest": { + "useESM": true + } + }, + "moduleNameMapper": { + "^(\\.{1,2}/.*)\\.js$": "$1" + }, + "testRegex": "./src/.*\\.test\\.ts$", + "rootDir": "./src" + }, + "dependencies": { + "cross-fetch": "^3.1.5", + "debug": "^4.3.4", + "detect-node": "^2.1.0" + }, + "prettier": "./src/prettier-config/index.js", + "yalcSig": "6fbabe5e1e3b5094c9842e160930d04a" +} diff --git a/circuits/.yalc/@aztec/foundation/src/async-map/async_map.test.ts b/circuits/.yalc/@aztec/foundation/src/async-map/async_map.test.ts new file mode 100644 index 00000000000..2ec4c370153 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/src/async-map/async_map.test.ts @@ -0,0 +1,9 @@ +import { asyncMap } from './index.js'; + +describe('asyncMap', () => { + test('execute list item sequentially', async () => { + const sleepAndLog = (ms: number, idx: number) => new Promise(resolve => setTimeout(() => resolve(idx), ms)); + const result = await asyncMap([100, 0, 30, 1], (ms, i) => sleepAndLog(ms, i)); + expect(result).toEqual([0, 1, 2, 3]); + }); +}); diff --git a/circuits/.yalc/@aztec/foundation/src/async-map/index.ts b/circuits/.yalc/@aztec/foundation/src/async-map/index.ts new file mode 100644 index 00000000000..cdd0e9b6e79 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/src/async-map/index.ts @@ -0,0 +1,7 @@ +export async function asyncMap(arr: T[], fn: (e: T, i: number) => Promise): Promise { + const results: U[] = []; + for (let i = 0; i < arr.length; ++i) { + results.push(await fn(arr[i], i)); + } + return results; +} diff --git a/circuits/.yalc/@aztec/foundation/src/bigint-buffer/index.ts b/circuits/.yalc/@aztec/foundation/src/bigint-buffer/index.ts new file mode 100644 index 00000000000..b04faaaf864 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/src/bigint-buffer/index.ts @@ -0,0 +1,51 @@ +/** + * Convert a little-endian buffer into a BigInt. + * @param buf The little-endian buffer to convert + * @returns A BigInt with the little-endian representation of buf. + */ +export function toBigIntLE(buf: Buffer): bigint { + const reversed = Buffer.from(buf); + reversed.reverse(); + const hex = reversed.toString('hex'); + if (hex.length === 0) { + return BigInt(0); + } + return BigInt(`0x${hex}`); +} + +/** + * Convert a big-endian buffer into a BigInt + * @param buf The big-endian buffer to convert. + * @returns A BigInt with the big-endian representation of buf. + */ +export function toBigIntBE(buf: Buffer): bigint { + const hex = buf.toString('hex'); + if (hex.length === 0) { + return BigInt(0); + } + return BigInt(`0x${hex}`); +} + +/** + * Convert a BigInt to a little-endian buffer. + * @param num The BigInt to convert. + * @param width The number of bytes that the resulting buffer should be. + * @returns A little-endian buffer representation of num. + */ +export function toBufferLE(num: bigint, width: number): Buffer { + const hex = num.toString(16); + const buffer = Buffer.from(hex.padStart(width * 2, '0').slice(0, width * 2), 'hex'); + buffer.reverse(); + return buffer; +} + +/** + * Convert a BigInt to a big-endian buffer. + * @param num The BigInt to convert. + * @param width The number of bytes that the resulting buffer should be. + * @returns A big-endian buffer representation of num. + */ +export function toBufferBE(num: bigint, width: number): Buffer { + const hex = num.toString(16); + return Buffer.from(hex.padStart(width * 2, '0').slice(0, width * 2), 'hex'); +} diff --git a/circuits/.yalc/@aztec/foundation/src/crypto/index.ts b/circuits/.yalc/@aztec/foundation/src/crypto/index.ts new file mode 100644 index 00000000000..3f7761cd585 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/src/crypto/index.ts @@ -0,0 +1 @@ +export * from './random/index.js'; diff --git a/circuits/.yalc/@aztec/foundation/src/crypto/random/index.test.ts b/circuits/.yalc/@aztec/foundation/src/crypto/random/index.test.ts new file mode 100644 index 00000000000..7aa2c740374 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/src/crypto/random/index.test.ts @@ -0,0 +1,13 @@ +import { randomBytes } from './index.js'; + +describe('random', () => { + it('randomBytes returns a filled byte array', () => { + const data = randomBytes(32); + expect(data.length).toEqual(32); + let identical = true; + for (let i = 1; i < data.length; ++i) { + identical = identical && data[i] == data[i - 1]; + } + expect(identical).toEqual(false); + }); +}); diff --git a/circuits/.yalc/@aztec/foundation/src/crypto/random/index.ts b/circuits/.yalc/@aztec/foundation/src/crypto/random/index.ts new file mode 100644 index 00000000000..8b5df8f5643 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/src/crypto/random/index.ts @@ -0,0 +1,38 @@ +import isNode from 'detect-node'; +import nodeCrypto from 'crypto'; + +// limit of Crypto.getRandomValues() +// https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues +const MAX_BYTES = 65536; + +const getWebCrypto = () => { + if (typeof window !== 'undefined' && window.crypto) return window.crypto; + if (typeof self !== 'undefined' && self.crypto) return self.crypto; + return undefined; +}; + +export const randomBytes = (len: number) => { + if (isNode) { + return nodeCrypto.randomBytes(len) as Buffer; + } + + const crypto = getWebCrypto(); + if (!crypto) { + throw new Error('randomBytes UnsupportedEnvironment'); + } + + const buf = Buffer.allocUnsafe(len); + if (len > MAX_BYTES) { + // this is the max bytes crypto.getRandomValues + // can do at once see https://developer.mozilla.org/en-US/docs/Web/API/window.crypto.getRandomValues + for (let generated = 0; generated < len; generated += MAX_BYTES) { + // buffer.slice automatically checks if the end is past the end of + // the buffer so we don't have to here + crypto.getRandomValues(buf.slice(generated, generated + MAX_BYTES)); + } + } else { + crypto.getRandomValues(buf); + } + + return buf; +}; diff --git a/circuits/.yalc/@aztec/foundation/src/errors/index.ts b/circuits/.yalc/@aztec/foundation/src/errors/index.ts new file mode 100644 index 00000000000..77f44d90e25 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/src/errors/index.ts @@ -0,0 +1 @@ +export class InterruptError extends Error {} diff --git a/circuits/ts/.yalc/@aztec/eslint-config/index.js b/circuits/.yalc/@aztec/foundation/src/eslint-config/index.js similarity index 83% rename from circuits/ts/.yalc/@aztec/eslint-config/index.js rename to circuits/.yalc/@aztec/foundation/src/eslint-config/index.js index ee45c8912bf..33833650a8c 100644 --- a/circuits/ts/.yalc/@aztec/eslint-config/index.js +++ b/circuits/.yalc/@aztec/foundation/src/eslint-config/index.js @@ -1,9 +1,6 @@ const contexts = [ 'TSMethodDefinition', 'MethodDefinition', - 'TSParameterProperty[accessibility=public]', - 'TSPropertyDefinition[accessibility=public]', - 'PropertyDefinition[accessibility=public]', 'TSPropertySignature', 'PropertySignature', 'TSInterfaceDeclaration', @@ -27,11 +24,7 @@ const contexts = [ ]; module.exports = { - extends: [ - 'eslint:recommended', - 'plugin:@typescript-eslint/recommended', - 'prettier', - ], + extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'], root: true, parser: '@typescript-eslint/parser', plugins: ['@typescript-eslint', 'eslint-plugin-tsdoc', 'jsdoc'], @@ -62,13 +55,11 @@ module.exports = { patterns: [ { group: ['client-dest'], - message: - 'Fix this absolute garbage import. It's your duty to solve it before it spreads.', + message: "Fix this absolute garbage import. It's your duty to solve it before it spreads.", }, { group: ['dest'], - message: - 'You should not be importing from a build directory. Did you accidentally do a relative import?', + message: 'You should not be importing from a build directory. Did you accidentally do a relative import?', }, ], }, diff --git a/circuits/ts/.yalc/@aztec/eslint-config/package.json b/circuits/.yalc/@aztec/foundation/src/eslint-config/package.json similarity index 55% rename from circuits/ts/.yalc/@aztec/eslint-config/package.json rename to circuits/.yalc/@aztec/foundation/src/eslint-config/package.json index 336361c7ea4..b059ec8e99c 100644 --- a/circuits/ts/.yalc/@aztec/eslint-config/package.json +++ b/circuits/.yalc/@aztec/foundation/src/eslint-config/package.json @@ -2,21 +2,12 @@ "name": "@aztec/eslint-config", "version": "0.0.0", "packageManager": "yarn@3.2.2", - "files": [ - "index.js" - ], - "scripts": { - "build": "echo \"Did nothing.\"" - }, "dependencies": { - "@aztec/eslint-config": "link:../../../yarn-project/eslint-config", - "@aztec/wasm-worker": "link:../../../yarn-project/wasm-worker", "@typescript-eslint/eslint-plugin": "^5.38.0", "@typescript-eslint/parser": "^5.38.0", "eslint": "^8.21.0", "eslint-config-prettier": "^8.5.0", "eslint-plugin-jsdoc": "^40.0.0", "eslint-plugin-tsdoc": "^0.2.17" - }, - "yalcSig": "afe1f6648a5208f857a53f99fbc458af" + } } diff --git a/circuits/.yalc/@aztec/foundation/src/fifo/bounded_serial_queue.ts b/circuits/.yalc/@aztec/foundation/src/fifo/bounded_serial_queue.ts new file mode 100644 index 00000000000..4aa0984af9c --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/src/fifo/bounded_serial_queue.ts @@ -0,0 +1,69 @@ +import { Semaphore } from './semaphore.js'; +import { SerialQueue } from './serial_queue.js'; + +/** + * Leverages the unbounded SerialQueue and Semaphore to create a SerialQueue that will block when putting an item + * if the queue size = maxQueueSize. + */ +export class BoundedSerialQueue { + private readonly queue = new SerialQueue(); + private semaphore: Semaphore; + + constructor(maxQueueSize: number) { + this.semaphore = new Semaphore(maxQueueSize); + } + + public start() { + this.queue.start(); + } + + public length() { + return this.queue.length(); + } + + public cancel() { + return this.queue.cancel(); + } + + public end() { + return this.queue.end(); + } + + /** + * The caller will block until fn is succesfully enqueued. + * The fn itself is execute asyncronously and its result discarded. + */ + public async put(fn: () => Promise): Promise { + await this.semaphore.acquire(); + this.queue + .put(async () => { + try { + await fn(); + } finally { + this.semaphore.release(); + } + }) + .catch(err => { + console.error('BoundedSerialQueue handler exception:', err); + }); + } + + /** + * The caller will block until fn is successfully executed, and it's result returned. + */ + public async exec(fn: () => Promise): Promise { + await this.semaphore.acquire(); + return this.queue.put(async () => { + try { + return await fn(); + } finally { + this.semaphore.release(); + } + }); + } + + // Awaiting this ensures the queue is empty before resuming. + public async syncPoint() { + await this.queue.syncPoint(); + } +} diff --git a/circuits/.yalc/@aztec/foundation/src/fifo/index.ts b/circuits/.yalc/@aztec/foundation/src/fifo/index.ts new file mode 100644 index 00000000000..73b23f23dbd --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/src/fifo/index.ts @@ -0,0 +1,4 @@ +export * from './memory_fifo.js'; +export * from './serial_queue.js'; +export * from './bounded_serial_queue.js'; +export * from './semaphore.js'; diff --git a/circuits/ts/.yalc/@aztec/wasm/src/memory_fifo.ts b/circuits/.yalc/@aztec/foundation/src/fifo/memory_fifo.ts similarity index 91% rename from circuits/ts/.yalc/@aztec/wasm/src/memory_fifo.ts rename to circuits/.yalc/@aztec/foundation/src/fifo/memory_fifo.ts index 03dc63d93ee..7e333661365 100644 --- a/circuits/ts/.yalc/@aztec/wasm/src/memory_fifo.ts +++ b/circuits/.yalc/@aztec/foundation/src/fifo/memory_fifo.ts @@ -1,4 +1,3 @@ -// TODO should come from a dependency /** * A simple fifo queue. It can grow unbounded. It can have multiple producers and consumers. * Putting an item onto the queue always succeeds, unless either end() or cancel() has been called in which case @@ -9,10 +8,6 @@ export class MemoryFifo { private items: T[] = []; private flushing = false; - /** - * Length of queue. - * @returns integer. - */ public length() { return this.items.length; } @@ -21,8 +16,6 @@ export class MemoryFifo { * Returns next item within the queue, or blocks until and item has been put into the queue. * If given a timeout, the promise will reject if no item is received after `timeout` seconds. * If the queue is flushing, `null` is returned. - * @param timeout - In seconds. - * @returns Promise of result. */ public get(timeout?: number): Promise { if (this.items.length) { @@ -51,7 +44,6 @@ export class MemoryFifo { /** * Put an item onto back of the queue. - * @param item - The item to enqueue. */ public put(item: T) { if (this.flushing) { @@ -86,7 +78,6 @@ export class MemoryFifo { /** * Helper method that can be used to continously consume and process items on the queue. - * @param handler - The item handler function. */ public async process(handler: (item: T) => Promise) { try { diff --git a/circuits/.yalc/@aztec/foundation/src/fifo/semaphore.ts b/circuits/.yalc/@aztec/foundation/src/fifo/semaphore.ts new file mode 100644 index 00000000000..2db1a851d47 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/src/fifo/semaphore.ts @@ -0,0 +1,20 @@ +import { MemoryFifo } from './memory_fifo.js'; + +/** + * Allows the acquiring of up to `size` tokens before calls to acquire block, waiting for a call to release(). + */ +export class Semaphore { + private readonly queue = new MemoryFifo(); + + constructor(size: number) { + new Array(size).fill(true).map(() => this.queue.put(true)); + } + + public async acquire() { + await this.queue.get(); + } + + public release() { + this.queue.put(true); + } +} diff --git a/circuits/.yalc/@aztec/foundation/src/fifo/serial_queue.ts b/circuits/.yalc/@aztec/foundation/src/fifo/serial_queue.ts new file mode 100644 index 00000000000..aa5004a2557 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/src/fifo/serial_queue.ts @@ -0,0 +1,49 @@ +import { MemoryFifo } from './memory_fifo.js'; + +/** + * A more specialised fifo queue that enqueues functions to execute. Enqueued functions are executed in serial. + */ +export class SerialQueue { + private readonly queue = new MemoryFifo<() => Promise>(); + private runningPromise!: Promise; + + public start() { + this.runningPromise = this.queue.process(fn => fn()); + } + + public length() { + return this.queue.length(); + } + + public cancel() { + this.queue.cancel(); + return this.runningPromise; + } + + public end() { + this.queue.end(); + return this.runningPromise; + } + + /** + * Enqueues fn for execution on the serial queue. + * Returns the result of the function after execution. + */ + public put(fn: () => Promise): Promise { + return new Promise((resolve, reject) => { + this.queue.put(async () => { + try { + const res = await fn(); + resolve(res); + } catch (e) { + reject(e); + } + }); + }); + } + + // Awaiting this ensures the queue is empty before resuming. + public async syncPoint() { + await this.put(async () => {}); + } +} diff --git a/circuits/.yalc/@aztec/foundation/src/index.ts b/circuits/.yalc/@aztec/foundation/src/index.ts new file mode 100644 index 00000000000..5673396d800 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/src/index.ts @@ -0,0 +1,14 @@ +export * from './async-map/index.js'; +export * from './bigint-buffer/index.js'; +export * from './errors/index.js'; +export * from './fifo/index.js'; +export * from './mutex/index.js'; +export * from './timer/index.js'; +export * from './log/index.js'; +export * from './retry/index.js'; +export * from './sleep/index.js'; +export * from './serialize/index.js'; +export * from './transport/index.js'; +export * from './iso-fetch/index.js'; +export * from './crypto/index.js'; +export * from './running-promise/index.js'; diff --git a/circuits/.yalc/@aztec/foundation/src/iso-fetch/index.ts b/circuits/.yalc/@aztec/foundation/src/iso-fetch/index.ts new file mode 100644 index 00000000000..548093e9863 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/src/iso-fetch/index.ts @@ -0,0 +1,2 @@ +// TODO: Remove, node 18 has native fetch. +export * from 'cross-fetch'; diff --git a/circuits/.yalc/@aztec/foundation/src/log/console.ts b/circuits/.yalc/@aztec/foundation/src/log/console.ts new file mode 100644 index 00000000000..6315a10e0e7 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/src/log/console.ts @@ -0,0 +1,17 @@ +export type Logger = (...args: any[]) => void; + +class ConsoleLogger { + constructor(private prefix: string, private logger: (...args: any[]) => void = console.log) {} + + public log(...args: any[]) { + this.logger(`${this.prefix}:`, ...args); + } +} + +export function createLogger(prefix: string): Logger { + if (prefix) { + const logger = new ConsoleLogger(prefix, console.log); + return (...args: any[]) => logger.log(...args); + } + return console.log; +} diff --git a/circuits/.yalc/@aztec/foundation/src/log/debug.ts b/circuits/.yalc/@aztec/foundation/src/log/debug.ts new file mode 100644 index 00000000000..f9be3945d9b --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/src/log/debug.ts @@ -0,0 +1,38 @@ +import debug from 'debug'; + +let preLogHook: ((...args: any[]) => void) | undefined; +let postLogHook: ((...args: any[]) => void) | undefined; + +function theFunctionThroughWhichAllLogsPass(logger: any, ...args: any[]) { + if (!debug.enabled(logger.namespace)) { + return; + } + if (preLogHook) { + preLogHook(logger.namespace, ...args); + } + logger(...args); + if (postLogHook) { + postLogHook(logger.namespace, ...args); + } +} + +export function createDebugLogger(name: string) { + const logger = debug(name); + return (...args: any[]) => theFunctionThroughWhichAllLogsPass(logger, ...args); +} + +export function setPreDebugLogHook(fn: (...args: any[]) => void) { + preLogHook = fn; +} + +export function setPostDebugLogHook(fn: (...args: any[]) => void) { + postLogHook = fn; +} + +export function enableLogs(str: string) { + debug.enable(str); +} + +export function isLogEnabled(str: string) { + return debug.enabled(str); +} diff --git a/circuits/.yalc/@aztec/foundation/src/log/index.ts b/circuits/.yalc/@aztec/foundation/src/log/index.ts new file mode 100644 index 00000000000..1705648184a --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/src/log/index.ts @@ -0,0 +1,3 @@ +export * from './console.js'; +export * from './debug.js'; +export * from './log_history.js'; diff --git a/circuits/.yalc/@aztec/foundation/src/log/log_history.test.ts b/circuits/.yalc/@aztec/foundation/src/log/log_history.test.ts new file mode 100644 index 00000000000..8b1e640d9d7 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/src/log/log_history.test.ts @@ -0,0 +1,87 @@ +import { jest } from '@jest/globals'; +import { createDebugLogger, enableLogs } from './debug.js'; +import { LogHistory } from './log_history.js'; + +jest.useFakeTimers(); + +describe('log history', () => { + let debug: (...any: any) => void; + let logHistory: LogHistory; + const timestemp = new Date().toISOString(); + const name = 'test:a'; + + beforeEach(() => { + debug = createDebugLogger(name); + enableLogs(name); + logHistory = new LogHistory(); + }); + + it('keeps debug logs', () => { + logHistory.enable(); + expect(logHistory.getLogs()).toEqual([]); + debug('0'); + debug('1', 2); + debug('2', { key: ['value'] }, Buffer.alloc(2)); + expect(logHistory.getLogs()).toEqual([ + [timestemp, name, '0'], + [timestemp, name, '1', 2], + [timestemp, name, '2', { key: ['value'] }, Buffer.alloc(2)], + ]); + }); + + it('does not keep logs if not enabled', () => { + debug('0'); + debug('1', 2); + expect(logHistory.getLogs()).toEqual([]); + }); + + it('returns last n logs', () => { + logHistory.enable(); + expect(logHistory.getLogs()).toEqual([]); + debug('0'); + debug('1'); + debug('2'); + debug('3'); + debug('4'); + expect(logHistory.getLogs(2)).toEqual([ + [timestemp, name, '3'], + [timestemp, name, '4'], + ]); + }); + + it('only keeps logs with enabled namespace', () => { + logHistory.enable(); + const name2 = 'test:b'; + const debug2 = createDebugLogger(name2); + debug('0'); + debug2('zero'); + expect(logHistory.getLogs()).toEqual([[timestemp, name, '0']]); + + enableLogs(`${name},${name2}`); + debug('1', 2); + debug2('one', 3); + expect(logHistory.getLogs()).toEqual([ + [timestemp, name, '0'], + [timestemp, name, '1', 2], + [timestemp, name2, 'one', 3], + ]); + }); + + it('clears all logs', () => { + logHistory.enable(); + debug('0'); + debug('1'); + debug('2'); + logHistory.clear(); + expect(logHistory.getLogs()).toEqual([]); + }); + + it('clears first n logs', () => { + logHistory.enable(); + debug('0'); + debug('1'); + debug('2'); + logHistory.clear(2); + expect(logHistory.getLogs()).toEqual([[timestemp, name, '2']]); + }); +}); diff --git a/circuits/.yalc/@aztec/foundation/src/log/log_history.ts b/circuits/.yalc/@aztec/foundation/src/log/log_history.ts new file mode 100644 index 00000000000..d60151a78c1 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/src/log/log_history.ts @@ -0,0 +1,21 @@ +import { setPreDebugLogHook } from './debug.js'; + +export class LogHistory { + private logs: any[][] = []; + + public enable() { + setPreDebugLogHook((...args: any[]) => { + this.logs.push([new Date().toISOString(), ...args]); + }); + } + + public getLogs(last = 0) { + return last ? this.logs.slice(-last) : this.logs; + } + + public clear(count = this.logs.length) { + this.logs = this.logs.slice(count); + } +} + +export const logHistory = new LogHistory(); diff --git a/circuits/.yalc/@aztec/foundation/src/mutex/index.ts b/circuits/.yalc/@aztec/foundation/src/mutex/index.ts new file mode 100644 index 00000000000..1b80796d86b --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/src/mutex/index.ts @@ -0,0 +1,46 @@ +import { MutexDatabase } from './mutex_database.js'; + +export * from './mutex_database.js'; + +export class Mutex { + private id = 0; + private pingTimeout!: NodeJS.Timeout; + + constructor( + private readonly db: MutexDatabase, + private readonly name: string, + private readonly timeout = 5000, + private readonly tryLockInterval = 2000, + private readonly pingInterval = 2000, + ) {} + + public async lock(untilAcquired = true) { + while (true) { + if (await this.db.acquireLock(this.name, this.timeout)) { + const id = this.id; + this.pingTimeout = setTimeout(() => this.ping(id), this.pingInterval); + return true; + } + + if (!untilAcquired) { + return false; + } + await new Promise(resolve => setTimeout(resolve, this.tryLockInterval)); + } + } + + public async unlock() { + clearTimeout(this.pingTimeout); + this.id++; + await this.db.releaseLock(this.name); + } + + private async ping(id: number) { + if (id !== this.id) { + return; + } + + await this.db.extendLock(this.name, this.timeout); + this.pingTimeout = setTimeout(() => this.ping(id), this.pingInterval); + } +} diff --git a/circuits/.yalc/@aztec/foundation/src/mutex/mutex.test.ts b/circuits/.yalc/@aztec/foundation/src/mutex/mutex.test.ts new file mode 100644 index 00000000000..fefe96abe6d --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/src/mutex/mutex.test.ts @@ -0,0 +1,64 @@ +import { jest } from '@jest/globals'; +import { Mutex } from './index.js'; +import { MutexDatabase } from './mutex_database.js'; + +export function sleep(ms: number) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +type Mockify = { + [P in keyof T]: jest.Mock; +}; + +describe('mutex', () => { + let db: Mockify; + let mutex: Mutex; + const mutexName = 'test-mutex'; + const timeout = 500; + const tryLockInterval = 100; + const pingInterval = 200; + + beforeEach(() => { + db = { + acquireLock: jest.fn().mockImplementation(() => false), + extendLock: jest.fn().mockImplementation(() => { + (db.acquireLock.mockResolvedValueOnce as any)(false); + }), + releaseLock: jest.fn().mockImplementation(() => { + (db.acquireLock.mockResolvedValueOnce as any)(true); + }), + } as any; + (db.acquireLock.mockResolvedValueOnce as any)(true); + + mutex = new Mutex(db as MutexDatabase, mutexName, timeout, tryLockInterval, pingInterval); + }); + + it('cannot lock if locked', async () => { + const result: string[] = []; + const fn1 = async (runAfterLocked: () => Promise) => { + await mutex.lock(); + const pm = runAfterLocked(); + await sleep(500); + result.push('fn1'); + await mutex.unlock(); + return pm; + }; + + const fn2 = async () => { + await mutex.lock(); + result.push('fn2'); + await mutex.unlock(); + }; + + await fn1(fn2); + expect(result).toEqual(['fn1', 'fn2']); + }); + + it('automatically extend the expiry time of the lock', async () => { + await mutex.lock(); + await sleep(1000); + await mutex.unlock(); + + expect(db.extendLock).toHaveBeenCalledWith(mutexName, timeout); + }); +}); diff --git a/circuits/.yalc/@aztec/foundation/src/mutex/mutex_database.ts b/circuits/.yalc/@aztec/foundation/src/mutex/mutex_database.ts new file mode 100644 index 00000000000..a07cac84875 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/src/mutex/mutex_database.ts @@ -0,0 +1,5 @@ +export interface MutexDatabase { + acquireLock(name: string, timeout: number): Promise; + extendLock(name: string, timeout: number): Promise; + releaseLock(name: string): Promise; +} diff --git a/circuits/.yalc/@aztec/foundation/src/prettier-config/index.js b/circuits/.yalc/@aztec/foundation/src/prettier-config/index.js new file mode 100644 index 00000000000..e80a1d3874a --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/src/prettier-config/index.js @@ -0,0 +1,6 @@ +module.exports = { + singleQuote: true, + trailingComma: 'all', + printWidth: 120, + arrowParens: 'avoid', +}; diff --git a/circuits/.yalc/@aztec/foundation/src/prettier-config/package.json b/circuits/.yalc/@aztec/foundation/src/prettier-config/package.json new file mode 100644 index 00000000000..94229538215 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/src/prettier-config/package.json @@ -0,0 +1,8 @@ +{ + "name": "@aztec/prettier-config", + "version": "0.0.0", + "packageManager": "yarn@3.2.2", + "dependencies": { + "prettier": "^2.7.1" + } +} diff --git a/circuits/.yalc/@aztec/foundation/src/retry/index.ts b/circuits/.yalc/@aztec/foundation/src/retry/index.ts new file mode 100644 index 00000000000..b46415e1172 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/src/retry/index.ts @@ -0,0 +1,45 @@ +import { sleep } from '../sleep/index.js'; +import { Timer } from '../timer/index.js'; + +export function* backoffGenerator() { + const v = [1, 1, 1, 2, 4, 8, 16, 32, 64]; + let i = 0; + while (true) { + yield v[Math.min(i++, v.length - 1)]; + } +} + +export async function retry(fn: () => Promise, name = 'Operation', backoff = backoffGenerator()) { + while (true) { + try { + return await fn(); + } catch (err: any) { + const s = backoff.next().value; + if (s === undefined) { + throw err; + } + console.log(`${name} failed. Will retry in ${s}s...`); + console.log(err); + await sleep(s * 1000); + continue; + } + } +} + +// Call `fn` repeatedly until it returns true or timeout. +// Both `interval` and `timeout` are seconds. +// Will never timeout if the value is 0. +export async function retryUntil(fn: () => boolean | Promise, name = '', timeout = 0, interval = 1) { + const timer = new Timer(); + while (true) { + if (await fn()) { + return; + } + + await sleep(interval * 1000); + + if (timeout && timer.s() > timeout) { + throw new Error(name ? `Timeout awaiting ${name}` : 'Timeout'); + } + } +} diff --git a/circuits/.yalc/@aztec/foundation/src/running-promise/index.ts b/circuits/.yalc/@aztec/foundation/src/running-promise/index.ts new file mode 100644 index 00000000000..ea8b594ce73 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/src/running-promise/index.ts @@ -0,0 +1,42 @@ +export class RunningPromise { + private running = false; + private runningPromise = Promise.resolve(); + private interruptPromise = Promise.resolve(); + private interruptResolve = () => {}; + constructor(private fn: () => Promise, private pollingInterval = 10000) {} + + /** + * Starts the running promise + */ + public start() { + this.running = true; + this.interruptPromise = new Promise(resolve => (this.interruptResolve = resolve)); + + const poll = async () => { + while (this.running) { + await this.fn(); + await this.interruptableSleep(this.pollingInterval); + } + }; + this.runningPromise = poll(); + } + + async stop(): Promise { + this.running = false; + this.interruptResolve(); + await this.runningPromise; + } + + private async interruptableSleep(timeInMs: number) { + let timeout!: NodeJS.Timeout; + const sleepPromise = new Promise(resolve => { + timeout = setTimeout(resolve, timeInMs); + }); + await Promise.race([sleepPromise, this.interruptPromise]); + clearTimeout(timeout); + } + + public isRunning() { + return this.running; + } +} diff --git a/circuits/.yalc/@aztec/foundation/src/serialize/deserializer.ts b/circuits/.yalc/@aztec/foundation/src/serialize/deserializer.ts new file mode 100644 index 00000000000..7ff25fd9c63 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/src/serialize/deserializer.ts @@ -0,0 +1,62 @@ +import { + deserializeArrayFromVector, + deserializeBigInt, + deserializeBool, + deserializeBufferFromVector, + deserializeInt32, + deserializeUInt32, +} from './free_funcs.js'; + +export type DeserializeFn = (buf: Buffer, offset: number) => { elem: T; adv: number }; + +export class Deserializer { + constructor(private buf: Buffer, private offset = 0) {} + + public bool() { + return this.exec(deserializeBool) ? true : false; + } + + public uInt32() { + return this.exec(deserializeUInt32); + } + + public int32() { + return this.exec(deserializeInt32); + } + + public bigInt(width = 32) { + return this.exec((buf: Buffer, offset: number) => deserializeBigInt(buf, offset, width)); + } + + public vector() { + return this.exec(deserializeBufferFromVector); + } + + public buffer(width: number) { + const buf = this.buf.slice(this.offset, this.offset + width); + this.offset += width; + return buf; + } + + public string() { + return this.vector().toString(); + } + + public date() { + return new Date(Number(this.bigInt(8))); + } + + public deserializeArray(fn: DeserializeFn) { + return this.exec((buf: Buffer, offset: number) => deserializeArrayFromVector(fn, buf, offset)); + } + + public exec(fn: DeserializeFn): T { + const { elem, adv } = fn(this.buf, this.offset); + this.offset += adv; + return elem; + } + + public getOffset() { + return this.offset; + } +} diff --git a/circuits/.yalc/@aztec/foundation/src/serialize/free_funcs.ts b/circuits/.yalc/@aztec/foundation/src/serialize/free_funcs.ts new file mode 100644 index 00000000000..4c1d89f0a7f --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/src/serialize/free_funcs.ts @@ -0,0 +1,106 @@ +import { toBigIntBE, toBufferBE } from '../bigint-buffer/index.js'; + +// For serializing bool. +export function boolToByte(b: boolean) { + const buf = Buffer.alloc(1); + buf.writeUInt8(b ? 1 : 0); + return buf; +} + +// For serializing numbers to 32 bit little-endian form. +export function numToUInt32LE(n: number, bufferSize = 4) { + const buf = Buffer.alloc(bufferSize); + buf.writeUInt32LE(n, bufferSize - 4); + return buf; +} + +// For serializing numbers to 32 bit big-endian form. +export function numToUInt32BE(n: number, bufferSize = 4) { + const buf = Buffer.alloc(bufferSize); + buf.writeUInt32BE(n, bufferSize - 4); + return buf; +} + +// For serializing signed numbers to 32 bit big-endian form. +export function numToInt32BE(n: number, bufferSize = 4) { + const buf = Buffer.alloc(bufferSize); + buf.writeInt32BE(n, bufferSize - 4); + return buf; +} + +// For serializing numbers to 32 bit big-endian form. +export function numToUInt8(n: number) { + const bufferSize = 1; + const buf = Buffer.alloc(bufferSize); + buf.writeUInt8(n, 0); + return buf; +} + +// For serializing a buffer as a vector. +export function serializeBufferToVector(buf: Buffer) { + const lengthBuf = Buffer.alloc(4); + lengthBuf.writeUInt32BE(buf.length, 0); + return Buffer.concat([lengthBuf, buf]); +} + +export function serializeBigInt(n: bigint, width = 32) { + return toBufferBE(n, width); +} + +export function deserializeBigInt(buf: Buffer, offset = 0, width = 32) { + return { elem: toBigIntBE(buf.slice(offset, offset + width)), adv: width }; +} + +export function serializeDate(date: Date) { + return serializeBigInt(BigInt(date.getTime()), 8); +} + +export function deserializeBufferFromVector(vector: Buffer, offset = 0) { + const length = vector.readUInt32BE(offset); + const adv = 4 + length; + return { elem: vector.slice(offset + 4, offset + adv), adv }; +} + +export function deserializeBool(buf: Buffer, offset = 0) { + const adv = 1; + return { elem: buf.readUInt8(offset), adv }; +} + +export function deserializeUInt32(buf: Buffer, offset = 0) { + const adv = 4; + return { elem: buf.readUInt32BE(offset), adv }; +} + +export function deserializeInt32(buf: Buffer, offset = 0) { + const adv = 4; + return { elem: buf.readInt32BE(offset), adv }; +} + +export function deserializeField(buf: Buffer, offset = 0) { + const adv = 32; + return { elem: buf.slice(offset, offset + adv), adv }; +} + +// For serializing an array of fixed length elements. +export function serializeBufferArrayToVector(arr: Buffer[]) { + const lengthBuf = Buffer.alloc(4); + lengthBuf.writeUInt32BE(arr.length, 0); + return Buffer.concat([lengthBuf, ...arr]); +} + +export function deserializeArrayFromVector( + deserialize: (buf: Buffer, offset: number) => { elem: T; adv: number }, + vector: Buffer, + offset = 0, +) { + let pos = offset; + const size = vector.readUInt32BE(pos); + pos += 4; + const arr = new Array(size); + for (let i = 0; i < size; ++i) { + const { elem, adv } = deserialize(vector, pos); + pos += adv; + arr[i] = elem; + } + return { elem: arr, adv: pos - offset }; +} diff --git a/circuits/.yalc/@aztec/foundation/src/serialize/index.ts b/circuits/.yalc/@aztec/foundation/src/serialize/index.ts new file mode 100644 index 00000000000..fed2e36332b --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/src/serialize/index.ts @@ -0,0 +1,3 @@ +export * from './free_funcs.js'; +export * from './deserializer.js'; +export * from './serializer.js'; diff --git a/circuits/.yalc/@aztec/foundation/src/serialize/serialize.test.ts b/circuits/.yalc/@aztec/foundation/src/serialize/serialize.test.ts new file mode 100644 index 00000000000..60c30af772c --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/src/serialize/serialize.test.ts @@ -0,0 +1,88 @@ +import { randomBytes } from '../crypto/index.js'; +import { + serializeBufferToVector, + deserializeBufferFromVector, + deserializeUInt32, + deserializeField, + serializeBufferArrayToVector, + deserializeArrayFromVector, +} from './index.js'; + +describe('serialize', () => { + it('serialize buffer to vector and deserialize it back', () => { + const data = randomBytes(32); + const vector = serializeBufferToVector(data); + expect(vector.length).toBe(36); + + const recovered = deserializeBufferFromVector(vector); + expect(recovered.elem).toEqual(data); + expect(recovered.adv).toEqual(4 + 32); + + const paddedVector = Buffer.concat([randomBytes(10), vector, randomBytes(20)]); + const recovered2 = deserializeBufferFromVector(paddedVector, 10); + expect(recovered2.elem).toEqual(data); + expect(recovered2.adv).toEqual(4 + 32); + }); + + it('deserialize uint32', () => { + const uintBuf = Buffer.alloc(4); + uintBuf.writeUInt32BE(19, 0); + + const recovered = deserializeUInt32(uintBuf); + expect(recovered.elem).toBe(19); + expect(recovered.adv).toBe(4); + + const paddedBuf = Buffer.concat([randomBytes(10), uintBuf, randomBytes(20)]); + const recovered2 = deserializeUInt32(paddedBuf, 10); + expect(recovered2.elem).toBe(19); + expect(recovered2.adv).toBe(4); + }); + + it('deserialize field', () => { + const fieldBuf = randomBytes(32); + + const recovered = deserializeField(fieldBuf); + expect(recovered.elem).toEqual(fieldBuf); + expect(recovered.adv).toBe(32); + + const paddedBuf = Buffer.concat([randomBytes(10), fieldBuf, randomBytes(20)]); + const recovered2 = deserializeField(paddedBuf, 10); + expect(recovered2.elem).toEqual(fieldBuf); + expect(recovered2.adv).toBe(32); + }); + + it('serialize buffer array to vector and deserialize it back', () => { + // Array of uint32 + const uintArr = [7, 13, 16]; + const uintBufArr = uintArr.map(num => { + const uintBuf = Buffer.alloc(4); + uintBuf.writeUInt32BE(num, 0); + return uintBuf; + }); + const uintArrVec = serializeBufferArrayToVector(uintBufArr); + expect(uintArrVec.length).toBe(4 + 4 * 3); + + const recoveredUintArr = deserializeArrayFromVector(deserializeUInt32, uintArrVec); + expect(recoveredUintArr.elem).toEqual(uintArr); + expect(recoveredUintArr.adv).toEqual(4 + 4 * 3); + + const paddedUintArrVec = Buffer.concat([randomBytes(10), uintArrVec, randomBytes(20)]); + const recoveredUintArr2 = deserializeArrayFromVector(deserializeUInt32, paddedUintArrVec, 10); + expect(recoveredUintArr2.elem).toEqual(uintArr); + expect(recoveredUintArr2.adv).toEqual(4 + 4 * 3); + + // Array of field + const fieldArr = [randomBytes(32), randomBytes(32), randomBytes(32)]; + const fieldArrVec = serializeBufferArrayToVector(fieldArr); + expect(fieldArrVec.length).toBe(4 + 32 * 3); + + const recoveredFieldArr = deserializeArrayFromVector(deserializeField, fieldArrVec); + expect(recoveredFieldArr.elem).toEqual(fieldArr); + expect(recoveredFieldArr.adv).toEqual(4 + 32 * 3); + + const paddedFieldVec = Buffer.concat([randomBytes(10), fieldArrVec, randomBytes(20)]); + const recoveredFieldArr2 = deserializeArrayFromVector(deserializeField, paddedFieldVec, 10); + expect(recoveredFieldArr2.elem).toEqual(fieldArr); + expect(recoveredFieldArr2.adv).toEqual(4 + 32 * 3); + }); +}); diff --git a/circuits/.yalc/@aztec/foundation/src/serialize/serializer.ts b/circuits/.yalc/@aztec/foundation/src/serialize/serializer.ts new file mode 100644 index 00000000000..8bebb7ada96 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/src/serialize/serializer.ts @@ -0,0 +1,66 @@ +import { serializeBufferArrayToVector } from './index.js'; +import { + boolToByte, + numToInt32BE, + numToUInt32BE, + serializeBigInt, + serializeBufferToVector, + serializeDate, +} from './free_funcs.js'; + +// export type DeserializeFn = (buf: Buffer, offset: number) => { elem: T; adv: number }; + +export class Serializer { + private buf: Buffer[] = []; + + constructor() {} + + public bool(bool: boolean) { + this.buf.push(boolToByte(bool)); + } + + public uInt32(num: number) { + this.buf.push(numToUInt32BE(num)); + } + + public int32(num: number) { + this.buf.push(numToInt32BE(num)); + } + + public bigInt(num: bigint) { + this.buf.push(serializeBigInt(num)); + } + + /** + * The given buffer is of variable length. Prefixes the buffer with its length. + */ + public vector(buf: Buffer) { + this.buf.push(serializeBufferToVector(buf)); + } + + /** + * Directly serializes a buffer that maybe of fixed, or variable length. + * It is assumed the corresponding deserialize function will handle variable length data, thus the length + * does not need to be prefixed here. + * If serializing a raw, variable length buffer, use vector(). + */ + public buffer(buf: Buffer) { + this.buf.push(buf); + } + + public string(str: string) { + this.vector(Buffer.from(str)); + } + + public date(date: Date) { + this.buf.push(serializeDate(date)); + } + + public getBuffer() { + return Buffer.concat(this.buf); + } + + public serializeArray(arr: T[]) { + this.buf.push(serializeBufferArrayToVector(arr.map((e: any) => e.toBuffer()))); + } +} diff --git a/circuits/.yalc/@aztec/foundation/src/sleep/index.ts b/circuits/.yalc/@aztec/foundation/src/sleep/index.ts new file mode 100644 index 00000000000..e7c672a4324 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/src/sleep/index.ts @@ -0,0 +1,28 @@ +import { InterruptError } from '../errors/index.js'; + +export class InterruptableSleep { + private interruptResolve: (shouldThrow: boolean) => void = () => {}; + private interruptPromise = new Promise(resolve => (this.interruptResolve = resolve)); + private timeouts: NodeJS.Timeout[] = []; + + public async sleep(ms: number) { + let timeout!: NodeJS.Timeout; + const promise = new Promise(resolve => (timeout = setTimeout(() => resolve(false), ms))); + this.timeouts.push(timeout); + const shouldThrow = await Promise.race([promise, this.interruptPromise]); + clearTimeout(timeout); + this.timeouts.splice(this.timeouts.indexOf(timeout), 1); + if (shouldThrow) { + throw new InterruptError('Interrupted.'); + } + } + + public interrupt(sleepShouldThrow = false) { + this.interruptResolve(sleepShouldThrow); + this.interruptPromise = new Promise(resolve => (this.interruptResolve = resolve)); + } +} + +export function sleep(ms: number) { + return new Promise(resolve => setTimeout(resolve, ms)); +} diff --git a/circuits/.yalc/@aztec/foundation/src/timer/index.ts b/circuits/.yalc/@aztec/foundation/src/timer/index.ts new file mode 100644 index 00000000000..fa3570d9933 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/src/timer/index.ts @@ -0,0 +1,2 @@ +export { TimeoutTask } from './timeout.js'; +export { Timer } from './timer.js'; diff --git a/circuits/.yalc/@aztec/foundation/src/timer/timeout.ts b/circuits/.yalc/@aztec/foundation/src/timer/timeout.ts new file mode 100644 index 00000000000..e1da77a8cc3 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/src/timer/timeout.ts @@ -0,0 +1,36 @@ +export class TimeoutTask { + private interruptPromise!: Promise; + private interrupt = () => {}; + private totalTime = 0; + + constructor(private fn: () => Promise, private timeout = 0, fnName = '') { + this.interruptPromise = new Promise((_, reject) => { + this.interrupt = () => reject(new Error(`Timeout${fnName ? ` running ${fnName}` : ''} after ${timeout}ms.`)); + }); + } + + public async exec() { + const interruptTimeout = !this.timeout ? 0 : setTimeout(this.interrupt, this.timeout); + try { + const start = Date.now(); + const result = await Promise.race([this.fn(), this.interruptPromise]); + this.totalTime = Date.now() - start; + return result; + } finally { + clearTimeout(interruptTimeout); + } + } + + public getInterruptPromise() { + return this.interruptPromise; + } + + public getTime() { + return this.totalTime; + } +} + +export const executeTimeout = async (fn: () => Promise, timeout = 0, fnName = '') => { + const task = new TimeoutTask(fn, timeout, fnName); + return await task.exec(); +}; diff --git a/circuits/.yalc/@aztec/foundation/src/timer/timer.ts b/circuits/.yalc/@aztec/foundation/src/timer/timer.ts new file mode 100644 index 00000000000..3e1aac7c0f6 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/src/timer/timer.ts @@ -0,0 +1,15 @@ +export class Timer { + private start: number; + + constructor() { + this.start = new Date().getTime(); + } + + public ms() { + return new Date().getTime() - this.start; + } + + public s() { + return (new Date().getTime() - this.start) / 1000; + } +} diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/browser/index.ts b/circuits/.yalc/@aztec/foundation/src/transport/browser/index.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/src/transport/browser/index.ts rename to circuits/.yalc/@aztec/foundation/src/transport/browser/index.ts diff --git a/circuits/ts/.yalc/@aztec/wasm/src/transport/browser/message_port_socket.ts b/circuits/.yalc/@aztec/foundation/src/transport/browser/message_port_socket.ts similarity index 62% rename from circuits/ts/.yalc/@aztec/wasm/src/transport/browser/message_port_socket.ts rename to circuits/.yalc/@aztec/foundation/src/transport/browser/message_port_socket.ts index f82a3e0865f..3047c9468a8 100644 --- a/circuits/ts/.yalc/@aztec/wasm/src/transport/browser/message_port_socket.ts +++ b/circuits/.yalc/@aztec/foundation/src/transport/browser/message_port_socket.ts @@ -4,33 +4,17 @@ import { Socket } from '../interface/socket.js'; * An implementation of a TransportSocket using MessagePorts. */ export class MessagePortSocket implements Socket { - /** - * Create a MessagePortSocket. - * @param port - MessagePort object to wrap. - */ constructor(private port: MessagePort) {} - /** - * Send a message over our message port. - * @param msg - The message. - * @param transfer - Objects to transfer ownership of. - */ send(msg: any, transfer: Transferable[] = []): Promise { this.port.postMessage(msg, transfer); return Promise.resolve(); } - /** - * Add a message handler. - * @param cb - The handler. - */ registerHandler(cb: (msg: any) => any): void { this.port.onmessage = event => cb(event.data); } - /** - * Close this message port. - */ close() { void this.send(undefined); this.port.onmessage = null; diff --git a/circuits/ts/.yalc/@aztec/wasm/src/transport/browser/shared_worker_connector.ts b/circuits/.yalc/@aztec/foundation/src/transport/browser/shared_worker_connector.ts similarity index 56% rename from circuits/ts/.yalc/@aztec/wasm/src/transport/browser/shared_worker_connector.ts rename to circuits/.yalc/@aztec/foundation/src/transport/browser/shared_worker_connector.ts index d6167961760..a33f5b11e18 100644 --- a/circuits/ts/.yalc/@aztec/wasm/src/transport/browser/shared_worker_connector.ts +++ b/circuits/.yalc/@aztec/foundation/src/transport/browser/shared_worker_connector.ts @@ -1,20 +1,9 @@ import { Connector } from '../interface/connector.js'; import { MessagePortSocket } from './message_port_socket.js'; -/** - * Connector implementation which wraps a SharedWorker. - */ export class SharedWorkerConnector implements Connector { - /** - * Create a SharedWorkerConnector. - * @param worker - A shared worker. - */ constructor(private worker: SharedWorker) {} - /** - * Create a Socket implementation with our mesage port. - * @returns The socket. - */ createSocket() { return Promise.resolve(new MessagePortSocket(this.worker.port)); } diff --git a/circuits/ts/.yalc/@aztec/wasm/src/transport/browser/shared_worker_listener.ts b/circuits/.yalc/@aztec/foundation/src/transport/browser/shared_worker_listener.ts similarity index 66% rename from circuits/ts/.yalc/@aztec/wasm/src/transport/browser/shared_worker_listener.ts rename to circuits/.yalc/@aztec/foundation/src/transport/browser/shared_worker_listener.ts index cafd280e6e6..85de4720a79 100644 --- a/circuits/ts/.yalc/@aztec/wasm/src/transport/browser/shared_worker_listener.ts +++ b/circuits/.yalc/@aztec/foundation/src/transport/browser/shared_worker_listener.ts @@ -2,46 +2,23 @@ import EventEmitter from 'events'; import { Listener } from '../interface/listener.js'; import { MessagePortSocket } from './message_port_socket.js'; -/** - * See https://developer.mozilla.org/en-US/docs/Web/API/SharedWorkerGlobalScope. - */ declare interface SharedWorkerGlobalScope { - /** - * Fired on shared workers when a new client connects. - */ - onconnect: any; + onconnect: (...args: any) => any; } -/** - * Listens for connections to a shared worker. - */ export class SharedWorkerListener extends EventEmitter implements Listener { - /** - * - * @param worker - */ constructor(private worker: SharedWorkerGlobalScope) { super(); } - /** - * - */ open() { this.worker.onconnect = this.handleMessageEvent; } - /** - * - */ close() { this.worker.onconnect = () => {}; } - /** - * - * @param event - */ private handleMessageEvent = (event: MessageEvent) => { const [port] = event.ports; if (!port) { diff --git a/circuits/ts/.yalc/@aztec/wasm/src/transport/browser/worker_connector.ts b/circuits/.yalc/@aztec/foundation/src/transport/browser/worker_connector.ts similarity index 86% rename from circuits/ts/.yalc/@aztec/wasm/src/transport/browser/worker_connector.ts rename to circuits/.yalc/@aztec/foundation/src/transport/browser/worker_connector.ts index fbfc7efd22e..b8939cbfcf3 100644 --- a/circuits/ts/.yalc/@aztec/wasm/src/transport/browser/worker_connector.ts +++ b/circuits/.yalc/@aztec/foundation/src/transport/browser/worker_connector.ts @@ -1,19 +1,9 @@ import { Connector } from '../interface/connector.js'; import { MessagePortSocket } from './message_port_socket.js'; -/** - * - */ export class WorkerConnector implements Connector { - /** - * - * @param worker - */ constructor(private worker: Worker) {} - /** - * - */ createSocket() { const channel = new MessageChannel(); this.worker.postMessage('', [channel.port2]); diff --git a/circuits/ts/.yalc/@aztec/wasm/src/transport/browser/worker_listener.ts b/circuits/.yalc/@aztec/foundation/src/transport/browser/worker_listener.ts similarity index 80% rename from circuits/ts/.yalc/@aztec/wasm/src/transport/browser/worker_listener.ts rename to circuits/.yalc/@aztec/foundation/src/transport/browser/worker_listener.ts index 201b3a68573..035ea2ecb6a 100644 --- a/circuits/ts/.yalc/@aztec/wasm/src/transport/browser/worker_listener.ts +++ b/circuits/.yalc/@aztec/foundation/src/transport/browser/worker_listener.ts @@ -2,46 +2,23 @@ import EventEmitter from 'events'; import { Listener } from '../interface/listener.js'; import { MessagePortSocket } from './message_port_socket.js'; -/** - * - */ declare interface DedicatedWorkerGlobalScope { - /** - * - */ - onmessage: any; + onmessage: (...args: any) => any; } -/** - * - */ export class WorkerListener extends EventEmitter implements Listener { - /** - * - * @param worker - */ constructor(private worker: DedicatedWorkerGlobalScope) { super(); } - /** - * - */ open() { this.worker.onmessage = this.handleMessageEvent; } - /** - * - */ close() { this.worker.onmessage = () => {}; } - /** - * - * @param event - */ private handleMessageEvent = (event: MessageEvent) => { const [port] = event.ports; if (!port) { diff --git a/circuits/ts/.yalc/@aztec/wasm/src/transport/dispatch/create_dispatch_fn.ts b/circuits/.yalc/@aztec/foundation/src/transport/dispatch/create_dispatch_fn.ts similarity index 85% rename from circuits/ts/.yalc/@aztec/wasm/src/transport/dispatch/create_dispatch_fn.ts rename to circuits/.yalc/@aztec/foundation/src/transport/dispatch/create_dispatch_fn.ts index 6e23e25a25f..77be5edbb11 100644 --- a/circuits/ts/.yalc/@aztec/wasm/src/transport/dispatch/create_dispatch_fn.ts +++ b/circuits/.yalc/@aztec/foundation/src/transport/dispatch/create_dispatch_fn.ts @@ -1,20 +1,8 @@ -/** - * - */ export interface DispatchMsg { - /** - * - */ fn: string; - /** - * - */ args: any[]; } -/** - * - */ export function createDispatchFn(targetFn: () => any, debug = console.error) { return async ({ fn, args }: DispatchMsg) => { const target = targetFn(); diff --git a/circuits/ts/.yalc/@aztec/wasm/src/transport/dispatch/create_dispatch_proxy.ts b/circuits/.yalc/@aztec/foundation/src/transport/dispatch/create_dispatch_proxy.ts similarity index 82% rename from circuits/ts/.yalc/@aztec/wasm/src/transport/dispatch/create_dispatch_proxy.ts rename to circuits/.yalc/@aztec/foundation/src/transport/dispatch/create_dispatch_proxy.ts index e9538448d3d..df6b3dab905 100644 --- a/circuits/ts/.yalc/@aztec/wasm/src/transport/dispatch/create_dispatch_proxy.ts +++ b/circuits/.yalc/@aztec/foundation/src/transport/dispatch/create_dispatch_proxy.ts @@ -4,18 +4,15 @@ import { EventEmitter } from 'events'; import { isTransferDescriptor, TransferDescriptor } from '../interface/transferable.js'; type FilterOutAttributes = { - [Key in keyof Base]: Base[Key] extends (...args: any) => any ? Base[Key] : never; + [Key in keyof Base]: Base[Key] extends (...any: any) => any ? Base[Key] : never; }; -type PromisifyFunction any> = (...args: Parameters) => Promise>; +type PromisifyFunction any> = (...args: Parameters) => Promise>; -type Promisify any }> = { +type Promisify any }> = { [Key in keyof Base]: ReturnType extends Promise ? Base[Key] : PromisifyFunction; }; -/** - * Unpack transfer types - */ type TransferTypes = { [Index in keyof Tuple]: Tuple[Index] | (Tuple[Index] extends Transferable ? TransferDescriptor : never); }; @@ -29,13 +26,13 @@ type TransferTypes = { * * type MakeFunctionTransferrable any> = ( * ...args: TransferTypes> - * ) => ReturnType;. + * ) => ReturnType; */ type MakeFunctionTransferrable any> = ( ...args: TFunction extends (...args: infer P) => any ? TransferTypes

: never ) => ReturnType; -type Transferrable any }> = { +type Transferrable any }> = { [Key in keyof Base]: MakeFunctionTransferrable; }; @@ -55,12 +52,6 @@ export function createDispatchProxyFromFn( return proxy; } -/** - * Create a proxy object of our class T that uses transportClient - * @param class_ - Our class T. - * @param transportClient - The transport infrastructure. - * @returns A proxy over T. - */ export function createDispatchProxy( class_: { new (...args: any[]): T }, transportClient: TransportClient, diff --git a/circuits/ts/.yalc/@aztec/wasm/src/transport/dispatch/messages.ts b/circuits/.yalc/@aztec/foundation/src/transport/dispatch/messages.ts similarity index 52% rename from circuits/ts/.yalc/@aztec/wasm/src/transport/dispatch/messages.ts rename to circuits/.yalc/@aztec/foundation/src/transport/dispatch/messages.ts index 49704dbde84..618d2d50d50 100644 --- a/circuits/ts/.yalc/@aztec/wasm/src/transport/dispatch/messages.ts +++ b/circuits/.yalc/@aztec/foundation/src/transport/dispatch/messages.ts @@ -1,49 +1,18 @@ -/** - * Represents a transport bus request. - */ export interface RequestMessage { - /** - * The message ID. - */ msgId: number; - /** - * The data. - */ payload: Payload; } -/** - * Represents a transport bus response. - */ export interface ResponseMessage { - /** - * The message ID. - */ msgId: number; - /** - * The data. - */ payload?: Payload; - /** - * The error, if any. - */ error?: string; } -/** - * A message stemming from an event. - */ export interface EventMessage { - /** - * The event data. - */ payload: Payload; } -/** - * Is this an event message? - * @returns If the msgId was blank. - */ export function isEventMessage( msg: ResponseMessage | EventMessage, ): msg is EventMessage { diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/index.ts b/circuits/.yalc/@aztec/foundation/src/transport/index.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/src/transport/index.ts rename to circuits/.yalc/@aztec/foundation/src/transport/index.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/interface/connector.ts b/circuits/.yalc/@aztec/foundation/src/transport/interface/connector.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/src/transport/interface/connector.ts rename to circuits/.yalc/@aztec/foundation/src/transport/interface/connector.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/interface/listener.ts b/circuits/.yalc/@aztec/foundation/src/transport/interface/listener.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/src/transport/interface/listener.ts rename to circuits/.yalc/@aztec/foundation/src/transport/interface/listener.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/interface/socket.ts b/circuits/.yalc/@aztec/foundation/src/transport/interface/socket.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/src/transport/interface/socket.ts rename to circuits/.yalc/@aztec/foundation/src/transport/interface/socket.ts diff --git a/circuits/ts/.yalc/@aztec/wasm/src/transport/interface/transferable.ts b/circuits/.yalc/@aztec/foundation/src/transport/interface/transferable.ts similarity index 71% rename from circuits/ts/.yalc/@aztec/wasm/src/transport/interface/transferable.ts rename to circuits/.yalc/@aztec/foundation/src/transport/interface/transferable.ts index 3ce8c59b320..a283c90fa48 100644 --- a/circuits/ts/.yalc/@aztec/wasm/src/transport/interface/transferable.ts +++ b/circuits/.yalc/@aztec/foundation/src/transport/interface/transferable.ts @@ -1,36 +1,17 @@ const $transferable = Symbol('thread.transferable'); -/** - * A descriptor representing a payload with transferable components. - * These components will have ownership transfered when published on an event bus. - */ export interface TransferDescriptor { - /** - * Marked as transferable. - */ [$transferable]: true; - /** - * The payload with the transferable objects. - */ send: T; - /** - * The objects to transfer. - */ transferables: Transferable[]; } -/** - * - */ function isTransferable(thing: any): thing is Transferable { if (!thing || typeof thing !== 'object') return false; // Don't check too thoroughly, since the list of transferable things in JS might grow over time return true; } -/** - * - */ export function isTransferDescriptor(thing: any): thing is TransferDescriptor { return thing && typeof thing === 'object' && thing[$transferable]; } @@ -48,8 +29,8 @@ export function isTransferDescriptor(thing: any): thing is TransferDescriptor { * The transferable object cannot be accessed by this thread again * unless the receiving thread transfers it back again! * - * @param transferable - Array buffer, message port or similar. - * @see https://developers.google.com/web/updates/2011/12/Transferable-Objects-Lightning-Fast + * @param transferable Array buffer, message port or similar. + * @see */ export function Transfer(transferable: Transferable): TransferDescriptor; @@ -67,17 +48,11 @@ export function Transfer(transferable: Transferable): TransferDescriptor; * The transferable object cannot be accessed by this thread again * unless the receiving thread transfers it back again! * - * @param transferable - Array buffer, message port or similar. - * @see https://developers.google.com/web/updates/2011/12/Transferable-Objects-Lightning-Fast + * @param transferable Array buffer, message port or similar. + * @see */ export function Transfer(payload: T, transferables: Transferable[]): TransferDescriptor; -/** - * Create a transfer descriptor, marking these as transferable. - * @param payload - The payload. - * @param transferables - The transferable objects. - * @returns The descriptor. - */ export function Transfer(payload: T, transferables?: Transferable[]): TransferDescriptor { if (!transferables) { if (!isTransferable(payload)) throw Error(); diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/node/index.ts b/circuits/.yalc/@aztec/foundation/src/transport/node/index.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/src/transport/node/index.ts rename to circuits/.yalc/@aztec/foundation/src/transport/node/index.ts diff --git a/circuits/ts/.yalc/@aztec/wasm/src/transport/node/node_connector.ts b/circuits/.yalc/@aztec/foundation/src/transport/node/node_connector.ts similarity index 71% rename from circuits/ts/.yalc/@aztec/wasm/src/transport/node/node_connector.ts rename to circuits/.yalc/@aztec/foundation/src/transport/node/node_connector.ts index bf74c2a5d72..36544c27ca2 100644 --- a/circuits/ts/.yalc/@aztec/wasm/src/transport/node/node_connector.ts +++ b/circuits/.yalc/@aztec/foundation/src/transport/node/node_connector.ts @@ -2,16 +2,9 @@ import { Worker } from 'worker_threads'; import { Connector } from '../interface/connector.js'; import { NodeConnectorSocket } from './node_connector_socket.js'; -/** - * Creates sockets backed by a Node worker. - */ export class NodeConnector implements Connector { constructor(private worker: Worker) {} - /** - * Creates a socket backed by a node worker. - * @returns The socket. - */ createSocket() { return Promise.resolve(new NodeConnectorSocket(this.worker)); } diff --git a/circuits/ts/.yalc/@aztec/wasm/src/transport/node/node_connector_socket.ts b/circuits/.yalc/@aztec/foundation/src/transport/node/node_connector_socket.ts similarity index 61% rename from circuits/ts/.yalc/@aztec/wasm/src/transport/node/node_connector_socket.ts rename to circuits/.yalc/@aztec/foundation/src/transport/node/node_connector_socket.ts index 39b1b2e04b4..0c115c754d1 100644 --- a/circuits/ts/.yalc/@aztec/wasm/src/transport/node/node_connector_socket.ts +++ b/circuits/.yalc/@aztec/foundation/src/transport/node/node_connector_socket.ts @@ -1,34 +1,18 @@ import { TransferListItem, Worker } from 'worker_threads'; import { Socket } from '../interface/socket.js'; -/** - * A socket implementation using a Node worker. - */ export class NodeConnectorSocket implements Socket { constructor(private worker: Worker) {} - /** - * Send a message. - * @param msg - The message. - * @param transfer - Objects to transfer ownership of. - * @returns A void promise. - */ send(msg: any, transfer: Transferable[] = []): Promise { this.worker.postMessage(msg, transfer as TransferListItem[]); return Promise.resolve(); } - /** - * Register a message handler. - * @param cb - The handler function. - */ registerHandler(cb: (msg: any) => any): void { this.worker.on('message', cb); } - /** - * Remove all listeners from our worker. - */ close() { void this.send(undefined); this.worker.removeAllListeners(); diff --git a/circuits/ts/.yalc/@aztec/wasm/src/transport/node/node_listener.ts b/circuits/.yalc/@aztec/foundation/src/transport/node/node_listener.ts similarity index 76% rename from circuits/ts/.yalc/@aztec/wasm/src/transport/node/node_listener.ts rename to circuits/.yalc/@aztec/foundation/src/transport/node/node_listener.ts index 92c753410fb..ad37279a576 100644 --- a/circuits/ts/.yalc/@aztec/wasm/src/transport/node/node_listener.ts +++ b/circuits/.yalc/@aztec/foundation/src/transport/node/node_listener.ts @@ -3,23 +3,14 @@ import EventEmitter from 'events'; import { Listener } from '../interface/listener.js'; import { NodeListenerSocket } from './node_listener_socket.js'; -/** - * A socket listener that works with Node. - */ export class NodeListener extends EventEmitter implements Listener { constructor() { super(); } - /** - * Open the listener. - */ open() { this.emit('new_socket', new NodeListenerSocket(parentPort as any)); } - /** - * Close the listener. - */ close() {} } diff --git a/circuits/ts/.yalc/@aztec/wasm/src/transport/node/node_listener_socket.ts b/circuits/.yalc/@aztec/foundation/src/transport/node/node_listener_socket.ts similarity index 70% rename from circuits/ts/.yalc/@aztec/wasm/src/transport/node/node_listener_socket.ts rename to circuits/.yalc/@aztec/foundation/src/transport/node/node_listener_socket.ts index d492d45c602..c2b134fe00f 100644 --- a/circuits/ts/.yalc/@aztec/wasm/src/transport/node/node_listener_socket.ts +++ b/circuits/.yalc/@aztec/foundation/src/transport/node/node_listener_socket.ts @@ -7,28 +7,15 @@ import { Socket } from '../interface/socket.js'; export class NodeListenerSocket implements Socket { constructor(private port: MessagePort) {} - /** - * Send a message over this port. - * @param msg - The message. - * @param transfer - Transferable objects. - * @returns A void promise. - */ send(msg: any, transfer: Transferable[] = []): Promise { this.port.postMessage(msg, transfer as TransferListItem[]); return Promise.resolve(); } - /** - * Add a handler to this port. - * @param cb - The handler function. - */ registerHandler(cb: (msg: any) => any): void { this.port.on('message', cb); } - /** - * Close this socket. - */ close() { void this.send(undefined); this.port.removeAllListeners(); diff --git a/circuits/ts/.yalc/@aztec/wasm/src/transport/transport_client.ts b/circuits/.yalc/@aztec/foundation/src/transport/transport_client.ts similarity index 80% rename from circuits/ts/.yalc/@aztec/wasm/src/transport/transport_client.ts rename to circuits/.yalc/@aztec/foundation/src/transport/transport_client.ts index 5577d7a5ed5..bcb04a28a2d 100644 --- a/circuits/ts/.yalc/@aztec/wasm/src/transport/transport_client.ts +++ b/circuits/.yalc/@aztec/foundation/src/transport/transport_client.ts @@ -1,26 +1,17 @@ -import { createDebugLogger } from '@aztec/log'; import EventEmitter from 'events'; import { EventMessage, isEventMessage, ResponseMessage } from './dispatch/messages.js'; import { Connector } from './interface/connector.js'; import { Socket } from './interface/socket.js'; +import { createDebugLogger } from '../log/index.js'; const debug = createDebugLogger('aztec:transport_client'); -/** - * A pending request. - */ interface PendingRequest { - /** - * The message ID. - */ msgId: number; resolve(data: any): void; reject(error: Error): void; } -/** - * Augments the TransportClient class with more precise EventEmitter types. - */ export interface TransportClient extends EventEmitter { on(name: 'event_msg', handler: (payload: Payload) => void): this; emit(name: 'event_msg', payload: Payload): boolean; @@ -41,29 +32,17 @@ export class TransportClient extends EventEmitter { super(); } - /** - * Create and register our socket using our Connector. - */ async open() { this.socket = await this.transportConnect.createSocket(); this.socket.registerHandler(msg => this.handleSocketMessage(msg)); } - /** - * Close this and stop listening for messages. - */ close() { this.socket?.close(); this.socket = undefined; this.removeAllListeners(); } - /** - * Queue a request. - * @param payload - The request payload. - * @param transfer - Objects to transfer ownership of. - * @returns A promise of the query result. - */ request(payload: Payload, transfer?: Transferable[]) { if (!this.socket) { throw new Error('Socket not open.'); @@ -77,10 +56,6 @@ export class TransportClient extends EventEmitter { }); } - /** - * Handle an incoming socket message. - * @param msg - The message. - */ private handleSocketMessage(msg: ResponseMessage | EventMessage | undefined) { if (msg === undefined) { // The remote socket closed. diff --git a/circuits/ts/.yalc/@aztec/wasm/src/transport/transport_server.ts b/circuits/.yalc/@aztec/foundation/src/transport/transport_server.ts similarity index 86% rename from circuits/ts/.yalc/@aztec/wasm/src/transport/transport_server.ts rename to circuits/.yalc/@aztec/foundation/src/transport/transport_server.ts index 0cb5aecf7e2..cf3338f7823 100644 --- a/circuits/ts/.yalc/@aztec/wasm/src/transport/transport_server.ts +++ b/circuits/.yalc/@aztec/foundation/src/transport/transport_server.ts @@ -11,9 +11,6 @@ export class TransportServer { constructor(private listener: Listener, private msgHandlerFn: (msg: Payload) => Promise) {} - /** - * Start accepting new connections. - */ start() { this.listener.on('new_socket', client => this.handleNewSocket(client)); this.listener.open(); @@ -27,18 +24,10 @@ export class TransportServer { this.listener.close(); } - /** - * Broadcast a message. - * @param msg - The message. - */ async broadcast(msg: Payload) { await Promise.all(this.sockets.map(s => s.send({ payload: msg }))); } - /** - * New socket registration. - * @param socket - The socket to register. - */ private handleNewSocket(socket: Socket) { socket.registerHandler(async msg => { if (msg === undefined) { @@ -56,8 +45,6 @@ export class TransportServer { /** * Detect the 'transferables' argument to our socket from our message * handler return type. - * @param data - The return object. - * @returns - The data and the. */ private getPayloadAndTransfers(data: any): [any, Transferable[]] { if (isTransferDescriptor(data)) { @@ -74,12 +61,6 @@ export class TransportServer { } return [data, []]; } - /** - * Handles a socket message from a listener. - * @param socket - The socket. - * @param requestMessage - The message to handle. - * @returns The socket response. - */ private async handleSocketMessage(socket: Socket, { msgId, payload }: RequestMessage) { try { const data = await this.msgHandlerFn(payload); diff --git a/circuits/ts/.yalc/@aztec/log/tsconfig.dest.json b/circuits/.yalc/@aztec/foundation/tsconfig.dest.json similarity index 100% rename from circuits/ts/.yalc/@aztec/log/tsconfig.dest.json rename to circuits/.yalc/@aztec/foundation/tsconfig.dest.json diff --git a/circuits/.yalc/@aztec/foundation/tsconfig.json b/circuits/.yalc/@aztec/foundation/tsconfig.json new file mode 100644 index 00000000000..41d839cd823 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "target": "es2020", + "lib": ["dom", "esnext", "es2017.object"], + "module": "NodeNext", + "strict": true, + "declaration": true, + "noUnusedLocals": true, + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "downlevelIteration": true, + "inlineSourceMap": true, + "declarationMap": true, + "importHelpers": true, + "resolveJsonModule": true, + "composite": true, + "outDir": "dest", + "rootDir": "src", + "tsBuildInfoFile": ".tsbuildinfo" + }, + "include": ["src"] +} diff --git a/circuits/.yalc/@aztec/foundation/yalc.sig b/circuits/.yalc/@aztec/foundation/yalc.sig new file mode 100644 index 00000000000..d44563d8600 --- /dev/null +++ b/circuits/.yalc/@aztec/foundation/yalc.sig @@ -0,0 +1 @@ +6fbabe5e1e3b5094c9842e160930d04a \ No newline at end of file diff --git a/circuits/ts/.yalc/@aztec/log/.eslintrc.cjs b/circuits/.yalc/@aztec/wasm/.eslintrc.cjs similarity index 100% rename from circuits/ts/.yalc/@aztec/log/.eslintrc.cjs rename to circuits/.yalc/@aztec/wasm/.eslintrc.cjs diff --git a/circuits/ts/.yalc/@aztec/wasm/.tsbuildinfo b/circuits/.yalc/@aztec/wasm/.tsbuildinfo similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm/.tsbuildinfo rename to circuits/.yalc/@aztec/wasm/.tsbuildinfo diff --git a/circuits/ts/.yalc/@aztec/wasm/Dockerfile b/circuits/.yalc/@aztec/wasm/Dockerfile similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm/Dockerfile rename to circuits/.yalc/@aztec/wasm/Dockerfile diff --git a/circuits/ts/.yalc/@aztec/wasm/README.md b/circuits/.yalc/@aztec/wasm/README.md similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm/README.md rename to circuits/.yalc/@aztec/wasm/README.md diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/index.d.ts b/circuits/.yalc/@aztec/wasm/dest/index.d.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm/dest/index.d.ts rename to circuits/.yalc/@aztec/wasm/dest/index.d.ts diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/index.d.ts.map b/circuits/.yalc/@aztec/wasm/dest/index.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm/dest/index.d.ts.map rename to circuits/.yalc/@aztec/wasm/dest/index.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/index.js b/circuits/.yalc/@aztec/wasm/dest/index.js similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm/dest/index.js rename to circuits/.yalc/@aztec/wasm/dest/index.js diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/memory_fifo.d.ts b/circuits/.yalc/@aztec/wasm/dest/memory_fifo.d.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/memory_fifo.d.ts rename to circuits/.yalc/@aztec/wasm/dest/memory_fifo.d.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/memory_fifo.d.ts.map b/circuits/.yalc/@aztec/wasm/dest/memory_fifo.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/memory_fifo.d.ts.map rename to circuits/.yalc/@aztec/wasm/dest/memory_fifo.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/memory_fifo.js b/circuits/.yalc/@aztec/wasm/dest/memory_fifo.js similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/memory_fifo.js rename to circuits/.yalc/@aztec/wasm/dest/memory_fifo.js diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/index.d.ts b/circuits/.yalc/@aztec/wasm/dest/transport/browser/index.d.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/index.d.ts rename to circuits/.yalc/@aztec/wasm/dest/transport/browser/index.d.ts diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/index.d.ts.map b/circuits/.yalc/@aztec/wasm/dest/transport/browser/index.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/index.d.ts.map rename to circuits/.yalc/@aztec/wasm/dest/transport/browser/index.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/index.js b/circuits/.yalc/@aztec/wasm/dest/transport/browser/index.js similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/browser/index.js rename to circuits/.yalc/@aztec/wasm/dest/transport/browser/index.js diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/message_port_socket.d.ts b/circuits/.yalc/@aztec/wasm/dest/transport/browser/message_port_socket.d.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/message_port_socket.d.ts rename to circuits/.yalc/@aztec/wasm/dest/transport/browser/message_port_socket.d.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/message_port_socket.d.ts.map b/circuits/.yalc/@aztec/wasm/dest/transport/browser/message_port_socket.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/message_port_socket.d.ts.map rename to circuits/.yalc/@aztec/wasm/dest/transport/browser/message_port_socket.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/message_port_socket.js b/circuits/.yalc/@aztec/wasm/dest/transport/browser/message_port_socket.js similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/message_port_socket.js rename to circuits/.yalc/@aztec/wasm/dest/transport/browser/message_port_socket.js diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/shared_worker_connector.d.ts b/circuits/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_connector.d.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/shared_worker_connector.d.ts rename to circuits/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_connector.d.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/shared_worker_connector.d.ts.map b/circuits/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_connector.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/shared_worker_connector.d.ts.map rename to circuits/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_connector.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/shared_worker_connector.js b/circuits/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_connector.js similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/shared_worker_connector.js rename to circuits/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_connector.js diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/shared_worker_listener.d.ts b/circuits/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_listener.d.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/shared_worker_listener.d.ts rename to circuits/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_listener.d.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/shared_worker_listener.d.ts.map b/circuits/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_listener.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/shared_worker_listener.d.ts.map rename to circuits/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_listener.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/shared_worker_listener.js b/circuits/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_listener.js similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/shared_worker_listener.js rename to circuits/.yalc/@aztec/wasm/dest/transport/browser/shared_worker_listener.js diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/worker_connector.d.ts b/circuits/.yalc/@aztec/wasm/dest/transport/browser/worker_connector.d.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/worker_connector.d.ts rename to circuits/.yalc/@aztec/wasm/dest/transport/browser/worker_connector.d.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/worker_connector.d.ts.map b/circuits/.yalc/@aztec/wasm/dest/transport/browser/worker_connector.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/worker_connector.d.ts.map rename to circuits/.yalc/@aztec/wasm/dest/transport/browser/worker_connector.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/worker_connector.js b/circuits/.yalc/@aztec/wasm/dest/transport/browser/worker_connector.js similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/worker_connector.js rename to circuits/.yalc/@aztec/wasm/dest/transport/browser/worker_connector.js diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/worker_listener.d.ts b/circuits/.yalc/@aztec/wasm/dest/transport/browser/worker_listener.d.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/worker_listener.d.ts rename to circuits/.yalc/@aztec/wasm/dest/transport/browser/worker_listener.d.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/worker_listener.d.ts.map b/circuits/.yalc/@aztec/wasm/dest/transport/browser/worker_listener.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/worker_listener.d.ts.map rename to circuits/.yalc/@aztec/wasm/dest/transport/browser/worker_listener.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/worker_listener.js b/circuits/.yalc/@aztec/wasm/dest/transport/browser/worker_listener.js similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/browser/worker_listener.js rename to circuits/.yalc/@aztec/wasm/dest/transport/browser/worker_listener.js diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/create_dispatch_fn.d.ts b/circuits/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_fn.d.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/create_dispatch_fn.d.ts rename to circuits/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_fn.d.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/create_dispatch_fn.d.ts.map b/circuits/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_fn.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/create_dispatch_fn.d.ts.map rename to circuits/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_fn.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/create_dispatch_fn.js b/circuits/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_fn.js similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/create_dispatch_fn.js rename to circuits/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_fn.js diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/create_dispatch_proxy.d.ts b/circuits/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_proxy.d.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/create_dispatch_proxy.d.ts rename to circuits/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_proxy.d.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/create_dispatch_proxy.d.ts.map b/circuits/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_proxy.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/create_dispatch_proxy.d.ts.map rename to circuits/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_proxy.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/create_dispatch_proxy.js b/circuits/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_proxy.js similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/create_dispatch_proxy.js rename to circuits/.yalc/@aztec/wasm/dest/transport/dispatch/create_dispatch_proxy.js diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/messages.d.ts b/circuits/.yalc/@aztec/wasm/dest/transport/dispatch/messages.d.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/messages.d.ts rename to circuits/.yalc/@aztec/wasm/dest/transport/dispatch/messages.d.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/messages.d.ts.map b/circuits/.yalc/@aztec/wasm/dest/transport/dispatch/messages.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/messages.d.ts.map rename to circuits/.yalc/@aztec/wasm/dest/transport/dispatch/messages.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/messages.js b/circuits/.yalc/@aztec/wasm/dest/transport/dispatch/messages.js similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/dispatch/messages.js rename to circuits/.yalc/@aztec/wasm/dest/transport/dispatch/messages.js diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/index.d.ts b/circuits/.yalc/@aztec/wasm/dest/transport/index.d.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/index.d.ts rename to circuits/.yalc/@aztec/wasm/dest/transport/index.d.ts diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/index.d.ts.map b/circuits/.yalc/@aztec/wasm/dest/transport/index.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/index.d.ts.map rename to circuits/.yalc/@aztec/wasm/dest/transport/index.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/index.js b/circuits/.yalc/@aztec/wasm/dest/transport/index.js similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/index.js rename to circuits/.yalc/@aztec/wasm/dest/transport/index.js diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/connector.d.ts b/circuits/.yalc/@aztec/wasm/dest/transport/interface/connector.d.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/connector.d.ts rename to circuits/.yalc/@aztec/wasm/dest/transport/interface/connector.d.ts diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/connector.d.ts.map b/circuits/.yalc/@aztec/wasm/dest/transport/interface/connector.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/connector.d.ts.map rename to circuits/.yalc/@aztec/wasm/dest/transport/interface/connector.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/connector.js b/circuits/.yalc/@aztec/wasm/dest/transport/interface/connector.js similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/connector.js rename to circuits/.yalc/@aztec/wasm/dest/transport/interface/connector.js diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/listener.d.ts b/circuits/.yalc/@aztec/wasm/dest/transport/interface/listener.d.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/listener.d.ts rename to circuits/.yalc/@aztec/wasm/dest/transport/interface/listener.d.ts diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/listener.d.ts.map b/circuits/.yalc/@aztec/wasm/dest/transport/interface/listener.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/listener.d.ts.map rename to circuits/.yalc/@aztec/wasm/dest/transport/interface/listener.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/listener.js b/circuits/.yalc/@aztec/wasm/dest/transport/interface/listener.js similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/listener.js rename to circuits/.yalc/@aztec/wasm/dest/transport/interface/listener.js diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/socket.d.ts b/circuits/.yalc/@aztec/wasm/dest/transport/interface/socket.d.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/socket.d.ts rename to circuits/.yalc/@aztec/wasm/dest/transport/interface/socket.d.ts diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/socket.d.ts.map b/circuits/.yalc/@aztec/wasm/dest/transport/interface/socket.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/socket.d.ts.map rename to circuits/.yalc/@aztec/wasm/dest/transport/interface/socket.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/socket.js b/circuits/.yalc/@aztec/wasm/dest/transport/interface/socket.js similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/interface/socket.js rename to circuits/.yalc/@aztec/wasm/dest/transport/interface/socket.js diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/transferable.d.ts b/circuits/.yalc/@aztec/wasm/dest/transport/interface/transferable.d.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/transferable.d.ts rename to circuits/.yalc/@aztec/wasm/dest/transport/interface/transferable.d.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/transferable.d.ts.map b/circuits/.yalc/@aztec/wasm/dest/transport/interface/transferable.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/transferable.d.ts.map rename to circuits/.yalc/@aztec/wasm/dest/transport/interface/transferable.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/transferable.js b/circuits/.yalc/@aztec/wasm/dest/transport/interface/transferable.js similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/interface/transferable.js rename to circuits/.yalc/@aztec/wasm/dest/transport/interface/transferable.js diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/index.d.ts b/circuits/.yalc/@aztec/wasm/dest/transport/node/index.d.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/node/index.d.ts rename to circuits/.yalc/@aztec/wasm/dest/transport/node/index.d.ts diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/index.d.ts.map b/circuits/.yalc/@aztec/wasm/dest/transport/node/index.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/node/index.d.ts.map rename to circuits/.yalc/@aztec/wasm/dest/transport/node/index.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/transport/node/index.js b/circuits/.yalc/@aztec/wasm/dest/transport/node/index.js similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm/dest/transport/node/index.js rename to circuits/.yalc/@aztec/wasm/dest/transport/node/index.js diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_connector.d.ts b/circuits/.yalc/@aztec/wasm/dest/transport/node/node_connector.d.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_connector.d.ts rename to circuits/.yalc/@aztec/wasm/dest/transport/node/node_connector.d.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_connector.d.ts.map b/circuits/.yalc/@aztec/wasm/dest/transport/node/node_connector.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_connector.d.ts.map rename to circuits/.yalc/@aztec/wasm/dest/transport/node/node_connector.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_connector.js b/circuits/.yalc/@aztec/wasm/dest/transport/node/node_connector.js similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_connector.js rename to circuits/.yalc/@aztec/wasm/dest/transport/node/node_connector.js diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_connector_socket.d.ts b/circuits/.yalc/@aztec/wasm/dest/transport/node/node_connector_socket.d.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_connector_socket.d.ts rename to circuits/.yalc/@aztec/wasm/dest/transport/node/node_connector_socket.d.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_connector_socket.d.ts.map b/circuits/.yalc/@aztec/wasm/dest/transport/node/node_connector_socket.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_connector_socket.d.ts.map rename to circuits/.yalc/@aztec/wasm/dest/transport/node/node_connector_socket.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_connector_socket.js b/circuits/.yalc/@aztec/wasm/dest/transport/node/node_connector_socket.js similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_connector_socket.js rename to circuits/.yalc/@aztec/wasm/dest/transport/node/node_connector_socket.js diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_listener.d.ts b/circuits/.yalc/@aztec/wasm/dest/transport/node/node_listener.d.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_listener.d.ts rename to circuits/.yalc/@aztec/wasm/dest/transport/node/node_listener.d.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_listener.d.ts.map b/circuits/.yalc/@aztec/wasm/dest/transport/node/node_listener.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_listener.d.ts.map rename to circuits/.yalc/@aztec/wasm/dest/transport/node/node_listener.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_listener.js b/circuits/.yalc/@aztec/wasm/dest/transport/node/node_listener.js similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_listener.js rename to circuits/.yalc/@aztec/wasm/dest/transport/node/node_listener.js diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_listener_socket.d.ts b/circuits/.yalc/@aztec/wasm/dest/transport/node/node_listener_socket.d.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_listener_socket.d.ts rename to circuits/.yalc/@aztec/wasm/dest/transport/node/node_listener_socket.d.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_listener_socket.d.ts.map b/circuits/.yalc/@aztec/wasm/dest/transport/node/node_listener_socket.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_listener_socket.d.ts.map rename to circuits/.yalc/@aztec/wasm/dest/transport/node/node_listener_socket.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_listener_socket.js b/circuits/.yalc/@aztec/wasm/dest/transport/node/node_listener_socket.js similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/node/node_listener_socket.js rename to circuits/.yalc/@aztec/wasm/dest/transport/node/node_listener_socket.js diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/transport_client.d.ts b/circuits/.yalc/@aztec/wasm/dest/transport/transport_client.d.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/transport_client.d.ts rename to circuits/.yalc/@aztec/wasm/dest/transport/transport_client.d.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/transport_client.d.ts.map b/circuits/.yalc/@aztec/wasm/dest/transport/transport_client.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/transport_client.d.ts.map rename to circuits/.yalc/@aztec/wasm/dest/transport/transport_client.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/transport_client.js b/circuits/.yalc/@aztec/wasm/dest/transport/transport_client.js similarity index 59% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/transport_client.js rename to circuits/.yalc/@aztec/wasm/dest/transport/transport_client.js index ee8579704b4..fa875f15109 100644 --- a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/transport_client.js +++ b/circuits/.yalc/@aztec/wasm/dest/transport/transport_client.js @@ -1,7 +1,7 @@ -import { createDebugLogger } from '@aztec/log'; -import EventEmitter from 'events'; -import { isEventMessage } from './dispatch/messages.js'; -const debug = createDebugLogger('aztec:transport_client'); +import { createDebugLogger } from "@aztec/foundation"; +import EventEmitter from "events"; +import { isEventMessage } from "./dispatch/messages.js"; +const debug = createDebugLogger("aztec:transport_client"); /** * A TransportClient provides a request/response and event api to a corresponding TransportServer. * If `broadcast` is called on TransportServer, TransportClients will emit an `event_msg`. @@ -9,71 +9,72 @@ const debug = createDebugLogger('aztec:transport_client'); * Request multiplexing is supported. */ export class TransportClient extends EventEmitter { - constructor(transportConnect) { - super(); - this.transportConnect = transportConnect; - this.msgId = 0; - this.pendingRequests = []; + constructor(transportConnect) { + super(); + this.transportConnect = transportConnect; + this.msgId = 0; + this.pendingRequests = []; + } + /** + * Create and register our socket using our Connector. + */ + async open() { + this.socket = await this.transportConnect.createSocket(); + this.socket.registerHandler((msg) => this.handleSocketMessage(msg)); + } + /** + * Close this and stop listening for messages. + */ + close() { + this.socket?.close(); + this.socket = undefined; + this.removeAllListeners(); + } + /** + * Queue a request. + * @param payload - The request payload. + * @param transfer - Objects to transfer ownership of. + * @returns A promise of the query result. + */ + request(payload, transfer) { + if (!this.socket) { + throw new Error("Socket not open."); } - /** - * Create and register our socket using our Connector. - */ - async open() { - this.socket = await this.transportConnect.createSocket(); - this.socket.registerHandler(msg => this.handleSocketMessage(msg)); + const msgId = this.msgId++; + const msg = { msgId, payload }; + debug(`->`, msg); + return new Promise((resolve, reject) => { + this.pendingRequests.push({ resolve, reject, msgId }); + this.socket.send(msg, transfer).catch(reject); + }); + } + /** + * Handle an incoming socket message. + * @param msg - The message. + */ + handleSocketMessage(msg) { + if (msg === undefined) { + // The remote socket closed. + this.close(); + return; } - /** - * Close this and stop listening for messages. - */ - close() { - this.socket?.close(); - this.socket = undefined; - this.removeAllListeners(); + debug(`<-`, msg); + if (isEventMessage(msg)) { + this.emit("event_msg", msg.payload); + return; } - /** - * Queue a request. - * @param payload - The request payload. - * @param transfer - Objects to transfer ownership of. - * @returns A promise of the query result. - */ - request(payload, transfer) { - if (!this.socket) { - throw new Error('Socket not open.'); - } - const msgId = this.msgId++; - const msg = { msgId, payload }; - debug(`->`, msg); - return new Promise((resolve, reject) => { - this.pendingRequests.push({ resolve, reject, msgId }); - this.socket.send(msg, transfer).catch(reject); - }); + const reqIndex = this.pendingRequests.findIndex( + (r) => r.msgId === msg.msgId + ); + if (reqIndex === -1) { + return; } - /** - * Handle an incoming socket message. - * @param msg - The message. - */ - handleSocketMessage(msg) { - if (msg === undefined) { - // The remote socket closed. - this.close(); - return; - } - debug(`<-`, msg); - if (isEventMessage(msg)) { - this.emit('event_msg', msg.payload); - return; - } - const reqIndex = this.pendingRequests.findIndex(r => r.msgId === msg.msgId); - if (reqIndex === -1) { - return; - } - const [pending] = this.pendingRequests.splice(reqIndex, 1); - if (msg.error) { - pending.reject(new Error(msg.error)); - } - else { - pending.resolve(msg.payload); - } + const [pending] = this.pendingRequests.splice(reqIndex, 1); + if (msg.error) { + pending.reject(new Error(msg.error)); + } else { + pending.resolve(msg.payload); } + } } -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhbnNwb3J0X2NsaWVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90cmFuc3BvcnQvdHJhbnNwb3J0X2NsaWVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFDL0MsT0FBTyxZQUFZLE1BQU0sUUFBUSxDQUFDO0FBQ2xDLE9BQU8sRUFBZ0IsY0FBYyxFQUFtQixNQUFNLHdCQUF3QixDQUFDO0FBSXZGLE1BQU0sS0FBSyxHQUFHLGlCQUFpQixDQUFDLHdCQUF3QixDQUFDLENBQUM7QUFzQjFEOzs7OztHQUtHO0FBQ0gsTUFBTSxPQUFPLGVBQXlCLFNBQVEsWUFBWTtJQUt4RCxZQUFvQixnQkFBMkI7UUFDN0MsS0FBSyxFQUFFLENBQUM7UUFEVSxxQkFBZ0IsR0FBaEIsZ0JBQWdCLENBQVc7UUFKdkMsVUFBSyxHQUFHLENBQUMsQ0FBQztRQUNWLG9CQUFlLEdBQXFCLEVBQUUsQ0FBQztJQUsvQyxDQUFDO0lBRUQ7O09BRUc7SUFDSCxLQUFLLENBQUMsSUFBSTtRQUNSLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxJQUFJLENBQUMsZ0JBQWdCLENBQUMsWUFBWSxFQUFFLENBQUM7UUFDekQsSUFBSSxDQUFDLE1BQU0sQ0FBQyxlQUFlLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsbUJBQW1CLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUNwRSxDQUFDO0lBRUQ7O09BRUc7SUFDSCxLQUFLO1FBQ0gsSUFBSSxDQUFDLE1BQU0sRUFBRSxLQUFLLEVBQUUsQ0FBQztRQUNyQixJQUFJLENBQUMsTUFBTSxHQUFHLFNBQVMsQ0FBQztRQUN4QixJQUFJLENBQUMsa0JBQWtCLEVBQUUsQ0FBQztJQUM1QixDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSCxPQUFPLENBQUMsT0FBZ0IsRUFBRSxRQUF5QjtRQUNqRCxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRTtZQUNoQixNQUFNLElBQUksS0FBSyxDQUFDLGtCQUFrQixDQUFDLENBQUM7U0FDckM7UUFDRCxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDM0IsTUFBTSxHQUFHLEdBQUcsRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFFLENBQUM7UUFDL0IsS0FBSyxDQUFDLElBQUksRUFBRSxHQUFHLENBQUMsQ0FBQztRQUNqQixPQUFPLElBQUksT0FBTyxDQUFNLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxFQUFFO1lBQzFDLElBQUksQ0FBQyxlQUFlLENBQUMsSUFBSSxDQUFDLEVBQUUsT0FBTyxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUsQ0FBQyxDQUFDO1lBQ3RELElBQUksQ0FBQyxNQUFPLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxRQUFRLENBQUMsQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDakQsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQ7OztPQUdHO0lBQ0ssbUJBQW1CLENBQUMsR0FBaUU7UUFDM0YsSUFBSSxHQUFHLEtBQUssU0FBUyxFQUFFO1lBQ3JCLDRCQUE0QjtZQUM1QixJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDYixPQUFPO1NBQ1I7UUFDRCxLQUFLLENBQUMsSUFBSSxFQUFFLEdBQUcsQ0FBQyxDQUFDO1FBQ2pCLElBQUksY0FBYyxDQUFDLEdBQUcsQ0FBQyxFQUFFO1lBQ3ZCLElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUNwQyxPQUFPO1NBQ1I7UUFDRCxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsZUFBZSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxLQUFLLEtBQUssR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzVFLElBQUksUUFBUSxLQUFLLENBQUMsQ0FBQyxFQUFFO1lBQ25CLE9BQU87U0FDUjtRQUNELE1BQU0sQ0FBQyxPQUFPLENBQUMsR0FBRyxJQUFJLENBQUMsZUFBZSxDQUFDLE1BQU0sQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFDM0QsSUFBSSxHQUFHLENBQUMsS0FBSyxFQUFFO1lBQ2IsT0FBTyxDQUFDLE1BQU0sQ0FBQyxJQUFJLEtBQUssQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztTQUN0QzthQUFNO1lBQ0wsT0FBTyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUM7U0FDOUI7SUFDSCxDQUFDO0NBQ0YifQ== \ No newline at end of file +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhbnNwb3J0X2NsaWVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90cmFuc3BvcnQvdHJhbnNwb3J0X2NsaWVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFDL0MsT0FBTyxZQUFZLE1BQU0sUUFBUSxDQUFDO0FBQ2xDLE9BQU8sRUFBZ0IsY0FBYyxFQUFtQixNQUFNLHdCQUF3QixDQUFDO0FBSXZGLE1BQU0sS0FBSyxHQUFHLGlCQUFpQixDQUFDLHdCQUF3QixDQUFDLENBQUM7QUFzQjFEOzs7OztHQUtHO0FBQ0gsTUFBTSxPQUFPLGVBQXlCLFNBQVEsWUFBWTtJQUt4RCxZQUFvQixnQkFBMkI7UUFDN0MsS0FBSyxFQUFFLENBQUM7UUFEVSxxQkFBZ0IsR0FBaEIsZ0JBQWdCLENBQVc7UUFKdkMsVUFBSyxHQUFHLENBQUMsQ0FBQztRQUNWLG9CQUFlLEdBQXFCLEVBQUUsQ0FBQztJQUsvQyxDQUFDO0lBRUQ7O09BRUc7SUFDSCxLQUFLLENBQUMsSUFBSTtRQUNSLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxJQUFJLENBQUMsZ0JBQWdCLENBQUMsWUFBWSxFQUFFLENBQUM7UUFDekQsSUFBSSxDQUFDLE1BQU0sQ0FBQyxlQUFlLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsbUJBQW1CLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUNwRSxDQUFDO0lBRUQ7O09BRUc7SUFDSCxLQUFLO1FBQ0gsSUFBSSxDQUFDLE1BQU0sRUFBRSxLQUFLLEVBQUUsQ0FBQztRQUNyQixJQUFJLENBQUMsTUFBTSxHQUFHLFNBQVMsQ0FBQztRQUN4QixJQUFJLENBQUMsa0JBQWtCLEVBQUUsQ0FBQztJQUM1QixDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSCxPQUFPLENBQUMsT0FBZ0IsRUFBRSxRQUF5QjtRQUNqRCxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRTtZQUNoQixNQUFNLElBQUksS0FBSyxDQUFDLGtCQUFrQixDQUFDLENBQUM7U0FDckM7UUFDRCxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDM0IsTUFBTSxHQUFHLEdBQUcsRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFFLENBQUM7UUFDL0IsS0FBSyxDQUFDLElBQUksRUFBRSxHQUFHLENBQUMsQ0FBQztRQUNqQixPQUFPLElBQUksT0FBTyxDQUFNLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxFQUFFO1lBQzFDLElBQUksQ0FBQyxlQUFlLENBQUMsSUFBSSxDQUFDLEVBQUUsT0FBTyxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUsQ0FBQyxDQUFDO1lBQ3RELElBQUksQ0FBQyxNQUFPLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxRQUFRLENBQUMsQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDakQsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQ7OztPQUdHO0lBQ0ssbUJBQW1CLENBQUMsR0FBaUU7UUFDM0YsSUFBSSxHQUFHLEtBQUssU0FBUyxFQUFFO1lBQ3JCLDRCQUE0QjtZQUM1QixJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDYixPQUFPO1NBQ1I7UUFDRCxLQUFLLENBQUMsSUFBSSxFQUFFLEdBQUcsQ0FBQyxDQUFDO1FBQ2pCLElBQUksY0FBYyxDQUFDLEdBQUcsQ0FBQyxFQUFFO1lBQ3ZCLElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUNwQyxPQUFPO1NBQ1I7UUFDRCxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsZUFBZSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxLQUFLLEtBQUssR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzVFLElBQUksUUFBUSxLQUFLLENBQUMsQ0FBQyxFQUFFO1lBQ25CLE9BQU87U0FDUjtRQUNELE1BQU0sQ0FBQyxPQUFPLENBQUMsR0FBRyxJQUFJLENBQUMsZUFBZSxDQUFDLE1BQU0sQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFDM0QsSUFBSSxHQUFHLENBQUMsS0FBSyxFQUFFO1lBQ2IsT0FBTyxDQUFDLE1BQU0sQ0FBQyxJQUFJLEtBQUssQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztTQUN0QzthQUFNO1lBQ0wsT0FBTyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUM7U0FDOUI7SUFDSCxDQUFDO0NBQ0YifQ== diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/transport_server.d.ts b/circuits/.yalc/@aztec/wasm/dest/transport/transport_server.d.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/transport_server.d.ts rename to circuits/.yalc/@aztec/wasm/dest/transport/transport_server.d.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/transport_server.d.ts.map b/circuits/.yalc/@aztec/wasm/dest/transport/transport_server.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/transport_server.d.ts.map rename to circuits/.yalc/@aztec/wasm/dest/transport/transport_server.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/transport_server.js b/circuits/.yalc/@aztec/wasm/dest/transport/transport_server.js similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/transport/transport_server.js rename to circuits/.yalc/@aztec/wasm/dest/transport/transport_server.js diff --git a/circuits/.yalc/@aztec/wasm/dest/wasm/async_call_state.d.ts b/circuits/.yalc/@aztec/wasm/dest/wasm/async_call_state.d.ts new file mode 100644 index 00000000000..e466ea48760 --- /dev/null +++ b/circuits/.yalc/@aztec/wasm/dest/wasm/async_call_state.d.ts @@ -0,0 +1,74 @@ +import { WasmModule } from "./wasm_module.js"; +/** + * The state of an asynchronous WASM function. + */ +export interface AsyncFnState { + /** + * Is this a contination? + */ + continuation: boolean; + /** + * A result, if one exists. + */ + result?: any; +} +/** + * To enable asynchronous callbacks from wasm to js, we leverage asyncify. + * Https://kripken.github.io/blog/wasm/2019/07/16/asyncify.html. + * + * This class holds state and logic specific to handling async calls from wasm to js. + * A single instance of this class is instantiated as part of BarretenbergWasm. + * It allocates some memory for the asyncify stack data and initialises it. + * + * To make an async call into the wasm, just call `call` the same as in BarretenbergWasm, only it returns a promise. + * + * To make an async import that will be called from the wasm, wrap a function with the signature: + * my_func(state: AsyncFnState, ...args) + * with a call to `wrapImportFn`. + * The arguments are whatever the original call arguments were. The addition of AsyncFnState as the first argument + * allows for the detection of wether the function is continuing after the the async call has completed. + * If `state.continuation` is false, the function should start its async operation and return the promise. + * If `state.continuation` is true, the function can get the result from `state.result` perform any finalisation, + * and return an (optional) value to the wasm. + */ +export declare class AsyncCallState { + private ASYNCIFY_DATA_SIZE; + private asyncifyDataAddr; + private asyncPromise?; + private wasm; + private state?; + private callExport; + /** + * Initialize the call hooks with a WasmModule. + * @param wasm - The module. + */ + init(wasm: WasmModule): void; + /** + * Log a message. + * @param args - The message arguments. + */ + private debug; + /** + * Free the data associated with async call states. + */ + destroy(): void; + /** + * We call the wasm function, that will in turn call back into js via callImport and set this.asyncPromise and + * enable the instrumented "record stack unwinding" code path. + * Once the stack has unwound out of the wasm call, we enter into a loop of resolving the promise set in the call + * to callImport, and calling back into the wasm to rewind the stack and continue execution. + * @param name - The function name. + * @param args - The function args. + * @returns The function result. + */ + call(name: string, ...args: any): Promise; + /** + * Wrap a WASM import function. + * @param fn - The function. + * @returns A wrapped version with asyncify calls. + */ + wrapImportFn( + fn: (state: AsyncFnState, ...args: any[]) => any + ): (...args: any[]) => any; +} +//# sourceMappingURL=async_call_state.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/async_call_state.d.ts.map b/circuits/.yalc/@aztec/wasm/dest/wasm/async_call_state.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/async_call_state.d.ts.map rename to circuits/.yalc/@aztec/wasm/dest/wasm/async_call_state.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/async_call_state.js b/circuits/.yalc/@aztec/wasm/dest/wasm/async_call_state.js similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/async_call_state.js rename to circuits/.yalc/@aztec/wasm/dest/wasm/async_call_state.js diff --git a/circuits/.yalc/@aztec/wasm/dest/wasm/empty_wasi_sdk.d.ts b/circuits/.yalc/@aztec/wasm/dest/wasm/empty_wasi_sdk.d.ts new file mode 100644 index 00000000000..8409a7022b6 --- /dev/null +++ b/circuits/.yalc/@aztec/wasm/dest/wasm/empty_wasi_sdk.d.ts @@ -0,0 +1,26 @@ +/** + * Dummy implementation of a necessary part of the wasi api: + * https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md + * We don't use these functions, but the environment expects them. + * TODO find a way to update off of wasi 12. + */ +export declare const getEmptyWasiSdk: ( + debug?: import("@aztec/foundation").DebugLogger +) => { + clock_time_get(): void; + environ_get(): void; + environ_sizes_get(): void; + fd_close(): void; + fd_read(): void; + fd_write(): void; + fd_seek(): void; + fd_fdstat_get(): void; + fd_fdstat_set_flags(): void; + fd_prestat_get(): number; + fd_prestat_dir_name(): number; + path_open(): void; + path_filestat_get(): void; + proc_exit(): number; + random_get(): number; +}; +//# sourceMappingURL=empty_wasi_sdk.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/empty_wasi_sdk.d.ts.map b/circuits/.yalc/@aztec/wasm/dest/wasm/empty_wasi_sdk.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/empty_wasi_sdk.d.ts.map rename to circuits/.yalc/@aztec/wasm/dest/wasm/empty_wasi_sdk.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/wasm/empty_wasi_sdk.js b/circuits/.yalc/@aztec/wasm/dest/wasm/empty_wasi_sdk.js similarity index 63% rename from circuits/ts/.yalc/@aztec/wasm/dest/wasm/empty_wasi_sdk.js rename to circuits/.yalc/@aztec/wasm/dest/wasm/empty_wasi_sdk.js index e40bba9f455..27f7a6436d2 100644 --- a/circuits/ts/.yalc/@aztec/wasm/dest/wasm/empty_wasi_sdk.js +++ b/circuits/.yalc/@aztec/wasm/dest/wasm/empty_wasi_sdk.js @@ -1,4 +1,4 @@ -import { createDebugLogger } from '@aztec/log'; +import { createDebugLogger } from "@aztec/foundation"; /** * Dummy implementation of a necessary part of the wasi api: * https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md @@ -7,55 +7,57 @@ import { createDebugLogger } from '@aztec/log'; */ /* eslint-disable camelcase */ /* eslint-disable jsdoc/require-jsdoc */ -export const getEmptyWasiSdk = (debug = createDebugLogger('wasm:empty_wasi_sdk')) => ({ - clock_time_get() { - debug('clock_time_get'); - }, - environ_get() { - debug('environ_get'); - }, - environ_sizes_get() { - debug('environ_sizes_get'); - }, - fd_close() { - debug('fd_close'); - }, - fd_read() { - debug('fd_read'); - }, - fd_write() { - debug('fd_write'); - }, - fd_seek() { - debug('fd_seek'); - }, - fd_fdstat_get() { - debug('fd_fdstat_get'); - }, - fd_fdstat_set_flags() { - debug('fd_fdstat_set_flags'); - }, - fd_prestat_get() { - debug('fd_prestat_get'); - return 8; - }, - fd_prestat_dir_name() { - debug('fd_prestat_dir_name'); - return 28; - }, - path_open() { - debug('path_open'); - }, - path_filestat_get() { - debug('path_filestat_get'); - }, - proc_exit() { - debug('proc_exit'); - return 52; - }, - random_get() { - debug('random_get'); - return 1; - }, +export const getEmptyWasiSdk = ( + debug = createDebugLogger("wasm:empty_wasi_sdk") +) => ({ + clock_time_get() { + debug("clock_time_get"); + }, + environ_get() { + debug("environ_get"); + }, + environ_sizes_get() { + debug("environ_sizes_get"); + }, + fd_close() { + debug("fd_close"); + }, + fd_read() { + debug("fd_read"); + }, + fd_write() { + debug("fd_write"); + }, + fd_seek() { + debug("fd_seek"); + }, + fd_fdstat_get() { + debug("fd_fdstat_get"); + }, + fd_fdstat_set_flags() { + debug("fd_fdstat_set_flags"); + }, + fd_prestat_get() { + debug("fd_prestat_get"); + return 8; + }, + fd_prestat_dir_name() { + debug("fd_prestat_dir_name"); + return 28; + }, + path_open() { + debug("path_open"); + }, + path_filestat_get() { + debug("path_filestat_get"); + }, + proc_exit() { + debug("proc_exit"); + return 52; + }, + random_get() { + debug("random_get"); + return 1; + }, }); -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW1wdHlfd2FzaV9zZGsuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvd2FzbS9lbXB0eV93YXNpX3Nkay50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFFL0M7Ozs7O0dBS0c7QUFDSCw4QkFBOEI7QUFDOUIsd0NBQXdDO0FBQ3hDLE1BQU0sQ0FBQyxNQUFNLGVBQWUsR0FBRyxDQUFDLEtBQUssR0FBRyxpQkFBaUIsQ0FBQyxxQkFBcUIsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQ3BGLGNBQWM7UUFDWixLQUFLLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztJQUMxQixDQUFDO0lBQ0QsV0FBVztRQUNULEtBQUssQ0FBQyxhQUFhLENBQUMsQ0FBQztJQUN2QixDQUFDO0lBQ0QsaUJBQWlCO1FBQ2YsS0FBSyxDQUFDLG1CQUFtQixDQUFDLENBQUM7SUFDN0IsQ0FBQztJQUNELFFBQVE7UUFDTixLQUFLLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDcEIsQ0FBQztJQUNELE9BQU87UUFDTCxLQUFLLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDbkIsQ0FBQztJQUNELFFBQVE7UUFDTixLQUFLLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDcEIsQ0FBQztJQUNELE9BQU87UUFDTCxLQUFLLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDbkIsQ0FBQztJQUNELGFBQWE7UUFDWCxLQUFLLENBQUMsZUFBZSxDQUFDLENBQUM7SUFDekIsQ0FBQztJQUNELG1CQUFtQjtRQUNqQixLQUFLLENBQUMscUJBQXFCLENBQUMsQ0FBQztJQUMvQixDQUFDO0lBQ0QsY0FBYztRQUNaLEtBQUssQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO1FBQ3hCLE9BQU8sQ0FBQyxDQUFDO0lBQ1gsQ0FBQztJQUNELG1CQUFtQjtRQUNqQixLQUFLLENBQUMscUJBQXFCLENBQUMsQ0FBQztRQUM3QixPQUFPLEVBQUUsQ0FBQztJQUNaLENBQUM7SUFDRCxTQUFTO1FBQ1AsS0FBSyxDQUFDLFdBQVcsQ0FBQyxDQUFDO0lBQ3JCLENBQUM7SUFDRCxpQkFBaUI7UUFDZixLQUFLLENBQUMsbUJBQW1CLENBQUMsQ0FBQztJQUM3QixDQUFDO0lBQ0QsU0FBUztRQUNQLEtBQUssQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUNuQixPQUFPLEVBQUUsQ0FBQztJQUNaLENBQUM7SUFDRCxVQUFVO1FBQ1IsS0FBSyxDQUFDLFlBQVksQ0FBQyxDQUFDO1FBQ3BCLE9BQU8sQ0FBQyxDQUFDO0lBQ1gsQ0FBQztDQUNGLENBQUMsQ0FBQyJ9 \ No newline at end of file +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW1wdHlfd2FzaV9zZGsuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvd2FzbS9lbXB0eV93YXNpX3Nkay50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFFL0M7Ozs7O0dBS0c7QUFDSCw4QkFBOEI7QUFDOUIsd0NBQXdDO0FBQ3hDLE1BQU0sQ0FBQyxNQUFNLGVBQWUsR0FBRyxDQUFDLEtBQUssR0FBRyxpQkFBaUIsQ0FBQyxxQkFBcUIsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQ3BGLGNBQWM7UUFDWixLQUFLLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztJQUMxQixDQUFDO0lBQ0QsV0FBVztRQUNULEtBQUssQ0FBQyxhQUFhLENBQUMsQ0FBQztJQUN2QixDQUFDO0lBQ0QsaUJBQWlCO1FBQ2YsS0FBSyxDQUFDLG1CQUFtQixDQUFDLENBQUM7SUFDN0IsQ0FBQztJQUNELFFBQVE7UUFDTixLQUFLLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDcEIsQ0FBQztJQUNELE9BQU87UUFDTCxLQUFLLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDbkIsQ0FBQztJQUNELFFBQVE7UUFDTixLQUFLLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDcEIsQ0FBQztJQUNELE9BQU87UUFDTCxLQUFLLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDbkIsQ0FBQztJQUNELGFBQWE7UUFDWCxLQUFLLENBQUMsZUFBZSxDQUFDLENBQUM7SUFDekIsQ0FBQztJQUNELG1CQUFtQjtRQUNqQixLQUFLLENBQUMscUJBQXFCLENBQUMsQ0FBQztJQUMvQixDQUFDO0lBQ0QsY0FBYztRQUNaLEtBQUssQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO1FBQ3hCLE9BQU8sQ0FBQyxDQUFDO0lBQ1gsQ0FBQztJQUNELG1CQUFtQjtRQUNqQixLQUFLLENBQUMscUJBQXFCLENBQUMsQ0FBQztRQUM3QixPQUFPLEVBQUUsQ0FBQztJQUNaLENBQUM7SUFDRCxTQUFTO1FBQ1AsS0FBSyxDQUFDLFdBQVcsQ0FBQyxDQUFDO0lBQ3JCLENBQUM7SUFDRCxpQkFBaUI7UUFDZixLQUFLLENBQUMsbUJBQW1CLENBQUMsQ0FBQztJQUM3QixDQUFDO0lBQ0QsU0FBUztRQUNQLEtBQUssQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUNuQixPQUFPLEVBQUUsQ0FBQztJQUNaLENBQUM7SUFDRCxVQUFVO1FBQ1IsS0FBSyxDQUFDLFlBQVksQ0FBQyxDQUFDO1FBQ3BCLE9BQU8sQ0FBQyxDQUFDO0lBQ1gsQ0FBQztDQUNGLENBQUMsQ0FBQyJ9 diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/index.d.ts b/circuits/.yalc/@aztec/wasm/dest/wasm/index.d.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/index.d.ts rename to circuits/.yalc/@aztec/wasm/dest/wasm/index.d.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/index.d.ts.map b/circuits/.yalc/@aztec/wasm/dest/wasm/index.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/index.d.ts.map rename to circuits/.yalc/@aztec/wasm/dest/wasm/index.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/index.js b/circuits/.yalc/@aztec/wasm/dest/wasm/index.js similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/wasm/index.js rename to circuits/.yalc/@aztec/wasm/dest/wasm/index.js diff --git a/circuits/.yalc/@aztec/wasm/dest/wasm/wasm_module.d.ts b/circuits/.yalc/@aztec/wasm/dest/wasm/wasm_module.d.ts new file mode 100644 index 00000000000..f46e4ec6577 --- /dev/null +++ b/circuits/.yalc/@aztec/wasm/dest/wasm/wasm_module.d.ts @@ -0,0 +1,110 @@ +/// +import { Buffer } from "buffer"; +/** + * WasmModule: + * Helper over a webassembly module. + * Assumes a few quirks. + * 1) the module expects wasi_snapshot_preview1 with the methods from getEmptyWasiSdk + * 2) of which the webassembly + * we instantiate only uses random_get (update this if more WASI sdk methods are needed). + */ +export declare class WasmModule { + private module; + private importFn; + private memory; + private heap; + private instance?; + private mutexQ; + private debug; + /** + * Create a wasm module. Should be followed by await init();. + * @param module - The module as a WebAssembly.Module or a Buffer. + * @param importFn - Imports expected by the WASM. + * @param loggerName - Optional, for debug logging. + */ + constructor( + module: WebAssembly.Module | Buffer, + importFn: (module: WasmModule) => any, + loggerName?: string + ); + /** + * Return the wasm source. + * @returns The source. + */ + getModule(): WebAssembly.Module | Buffer; + /** + * Initialize this wasm module. + * @param wasmImportEnv - Linked to a module called "env". Functions implementations referenced from e.g. C++. + * @param initial - 20 pages by default. 20*2**16 \> 1mb stack size plus other overheads. + * @param maximum - 8192 maximum by default. 512mb. + */ + init(initial?: number, maximum?: number): Promise; + /** + * The methods or objects exported by the WASM module. + * @returns An indexable object. + */ + exports(): any; + /** + * Get the current logger. + * @returns Logging function. + */ + getLogger(): any; + /** + * Add a logger. + * @param logger - Function to call when logging. + */ + addLogger(logger: any): void; + /** + * Calls into the WebAssembly. + * @param name - The method name. + * @param args - The arguments to the method. + * @returns The numeric method result. + */ + call(name: string, ...args: any): number; + /** + * Get the memory used by the WASM module. + * @returns A WebAssembly memory object. + */ + getRawMemory(): WebAssembly.Memory; + /** + * Get the memory used by the WASM module, as a byte array. + * @returns A Uint8Array view of the WASM module memory. + */ + getMemory(): Uint8Array; + /** + * The memory size in bytes. + * @returns Number of bytes. + */ + memSize(): number; + /** + * Get a slice of memory between two addresses. + * @param start - The start address. + * @param end - The end address. + * @returns A Uint8Array view of memory. + */ + getMemorySlice(start: number, end: number): Uint8Array; + /** + * Write data into the heap. + * @param offset - The address to write data at. + * @param arr - The data to write. + */ + writeMemory(offset: number, arr: Uint8Array): void; + /** + * Read WASM memory as a JS string. + * @param addr - The memory address. + * @returns A JS string. + */ + getMemoryAsString(addr: number): string; + /** + * When calling the wasm, sometimes a caller will require exclusive access over a series of calls. + * E.g. When a result is written to address 0, one cannot have another caller writing to the same address via + * writeMemory before the result is read via sliceMemory. + * Acquire() gets a single token from a fifo. The caller must call release() to add the token back. + */ + acquire(): Promise; + /** + * Release the mutex, letting another promise call acquire(). + */ + release(): void; +} +//# sourceMappingURL=wasm_module.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/wasm/wasm_module.d.ts.map b/circuits/.yalc/@aztec/wasm/dest/wasm/wasm_module.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm/dest/wasm/wasm_module.d.ts.map rename to circuits/.yalc/@aztec/wasm/dest/wasm/wasm_module.d.ts.map diff --git a/circuits/.yalc/@aztec/wasm/dest/wasm/wasm_module.js b/circuits/.yalc/@aztec/wasm/dest/wasm/wasm_module.js new file mode 100644 index 00000000000..852044bfd4d --- /dev/null +++ b/circuits/.yalc/@aztec/wasm/dest/wasm/wasm_module.js @@ -0,0 +1,206 @@ +import { createDebugLogger } from "@aztec/foundation"; +import { Buffer } from "buffer"; +import { MemoryFifo } from "../memory_fifo.js"; +import { getEmptyWasiSdk } from "./empty_wasi_sdk.js"; +import { randomBytes } from "crypto"; +/** + * WasmModule: + * Helper over a webassembly module. + * Assumes a few quirks. + * 1) the module expects wasi_snapshot_preview1 with the methods from getEmptyWasiSdk + * 2) of which the webassembly + * we instantiate only uses random_get (update this if more WASI sdk methods are needed). + */ +export class WasmModule { + /** + * Create a wasm module. Should be followed by await init();. + * @param module - The module as a WebAssembly.Module or a Buffer. + * @param importFn - Imports expected by the WASM. + * @param loggerName - Optional, for debug logging. + */ + constructor(module, importFn, loggerName = "wasm") { + this.module = module; + this.importFn = importFn; + this.mutexQ = new MemoryFifo(); + this.debug = createDebugLogger(loggerName); + this.mutexQ.put(true); + } + /** + * Return the wasm source. + * @returns The source. + */ + getModule() { + return this.module; + } + /** + * Initialize this wasm module. + * @param wasmImportEnv - Linked to a module called "env". Functions implementations referenced from e.g. C++. + * @param initial - 20 pages by default. 20*2**16 \> 1mb stack size plus other overheads. + * @param maximum - 8192 maximum by default. 512mb. + */ + async init(initial = 20, maximum = 8192) { + this.debug( + `initial mem: ${initial} pages, ${ + (initial * 2 ** 16) / (1024 * 1024) + }mb. max mem: ${maximum} pages, ${(maximum * 2 ** 16) / (1024 * 1024)}mb` + ); + this.memory = new WebAssembly.Memory({ initial, maximum }); + // Create a view over the memory buffer. + // We do this once here, as webkit *seems* bugged out and actually shows this as new memory, + // thus displaying double. It's only worse if we create views on demand. I haven't established yet if + // the bug is also exasperating the termination on mobile due to "excessive memory usage". It could be + // that the OS is actually getting an incorrect reading in the same way the memory profiler does... + // The view will have to be recreated if the memory is grown. See getMemory(). + this.heap = new Uint8Array(this.memory.buffer); + // We support the wasi 12 SDK, but only implement random_get + /* eslint-disable camelcase */ + const importObj = { + wasi_snapshot_preview1: { + ...getEmptyWasiSdk(this.debug), + random_get: (arr, length) => { + arr = arr >>> 0; + const heap = this.getMemory(); + const randomData = randomBytes(length); + for (let i = arr; i < arr + length; ++i) { + heap[i] = randomData[i - arr]; + } + }, + }, + env: this.importFn(this), + }; + if (this.module instanceof WebAssembly.Module) { + this.instance = await WebAssembly.instantiate(this.module, importObj); + } else { + const { instance } = await WebAssembly.instantiate( + this.module, + importObj + ); + this.instance = instance; + } + } + /** + * The methods or objects exported by the WASM module. + * @returns An indexable object. + */ + exports() { + if (!this.instance) { + throw new Error("WasmModule: not initialized!"); + } + return this.instance.exports; + } + /** + * Get the current logger. + * @returns Logging function. + */ + getLogger() { + return this.debug; + } + /** + * Add a logger. + * @param logger - Function to call when logging. + */ + addLogger(logger) { + const oldDebug = this.debug; + this.debug = (...args) => { + logger(...args); + oldDebug(...args); + }; + } + /** + * Calls into the WebAssembly. + * @param name - The method name. + * @param args - The arguments to the method. + * @returns The numeric method result. + */ + call(name, ...args) { + if (!this.exports()[name]) { + throw new Error(`WASM function ${name} not found.`); + } + try { + // When returning values from the WASM, use >>> operator to convert + // signed representation to unsigned representation. + return this.exports()[name](...args) >>> 0; + } catch (err) { + const message = `WASM function ${name} aborted, error: ${err}`; + this.debug(message); + this.debug(err.stack); + throw new Error(message); + } + } + /** + * Get the memory used by the WASM module. + * @returns A WebAssembly memory object. + */ + getRawMemory() { + return this.memory; + } + /** + * Get the memory used by the WASM module, as a byte array. + * @returns A Uint8Array view of the WASM module memory. + */ + getMemory() { + // If the memory is grown, our view over it will be lost. Recreate the view. + if (this.heap.length === 0) { + this.heap = new Uint8Array(this.memory.buffer); + } + return this.heap; + } + /** + * The memory size in bytes. + * @returns Number of bytes. + */ + memSize() { + return this.getMemory().length; + } + /** + * Get a slice of memory between two addresses. + * @param start - The start address. + * @param end - The end address. + * @returns A Uint8Array view of memory. + */ + getMemorySlice(start, end) { + return this.getMemory().slice(start, end); + } + /** + * Write data into the heap. + * @param offset - The address to write data at. + * @param arr - The data to write. + */ + writeMemory(offset, arr) { + const mem = this.getMemory(); + for (let i = 0; i < arr.length; i++) { + mem[i + offset] = arr[i]; + } + } + /** + * Read WASM memory as a JS string. + * @param addr - The memory address. + * @returns A JS string. + */ + getMemoryAsString(addr) { + addr = addr >>> 0; + const m = this.getMemory(); + let i = addr; + for (; m[i] !== 0; ++i); + return Buffer.from(m.slice(addr, i)).toString("ascii"); + } + /** + * When calling the wasm, sometimes a caller will require exclusive access over a series of calls. + * E.g. When a result is written to address 0, one cannot have another caller writing to the same address via + * writeMemory before the result is read via sliceMemory. + * Acquire() gets a single token from a fifo. The caller must call release() to add the token back. + */ + async acquire() { + await this.mutexQ.get(); + } + /** + * Release the mutex, letting another promise call acquire(). + */ + release() { + if (this.mutexQ.length() !== 0) { + throw new Error("Release called but not acquired."); + } + this.mutexQ.put(true); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2FzbV9tb2R1bGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvd2FzbS93YXNtX21vZHVsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsaUJBQWlCLEVBQWUsTUFBTSxZQUFZLENBQUM7QUFDNUQsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLFFBQVEsQ0FBQztBQUNoQyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDL0MsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ3RELE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxRQUFRLENBQUM7QUFFckM7Ozs7Ozs7R0FPRztBQUNILE1BQU0sT0FBTyxVQUFVO0lBT3JCOzs7OztPQUtHO0lBQ0gsWUFDVSxNQUFtQyxFQUNuQyxRQUFxQyxFQUM3QyxVQUFVLEdBQUcsTUFBTTtRQUZYLFdBQU0sR0FBTixNQUFNLENBQTZCO1FBQ25DLGFBQVEsR0FBUixRQUFRLENBQTZCO1FBWHZDLFdBQU0sR0FBRyxJQUFJLFVBQVUsRUFBVyxDQUFDO1FBY3pDLElBQUksQ0FBQyxLQUFLLEdBQUcsaUJBQWlCLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDM0MsSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDeEIsQ0FBQztJQUVEOzs7T0FHRztJQUNJLFNBQVM7UUFDZCxPQUFPLElBQUksQ0FBQyxNQUFNLENBQUM7SUFDckIsQ0FBQztJQUNEOzs7OztPQUtHO0lBQ0ksS0FBSyxDQUFDLElBQUksQ0FBQyxPQUFPLEdBQUcsRUFBRSxFQUFFLE9BQU8sR0FBRyxJQUFJO1FBQzVDLElBQUksQ0FBQyxLQUFLLENBQ1IsZ0JBQWdCLE9BQU8sV0FBVyxDQUFDLE9BQU8sR0FBRyxDQUFDLElBQUksRUFBRSxDQUFDLEdBQUcsQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDLGdCQUFnQixPQUFPLFdBQzFGLENB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 diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/index.d.ts b/circuits/.yalc/@aztec/wasm/dest/worker/browser/index.d.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/index.d.ts rename to circuits/.yalc/@aztec/wasm/dest/worker/browser/index.d.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/index.d.ts.map b/circuits/.yalc/@aztec/wasm/dest/worker/browser/index.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/index.d.ts.map rename to circuits/.yalc/@aztec/wasm/dest/worker/browser/index.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/index.js b/circuits/.yalc/@aztec/wasm/dest/worker/browser/index.js similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/index.js rename to circuits/.yalc/@aztec/wasm/dest/worker/browser/index.js diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/start_web_module.d.ts b/circuits/.yalc/@aztec/wasm/dest/worker/browser/start_web_module.d.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/start_web_module.d.ts rename to circuits/.yalc/@aztec/wasm/dest/worker/browser/start_web_module.d.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/start_web_module.d.ts.map b/circuits/.yalc/@aztec/wasm/dest/worker/browser/start_web_module.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/start_web_module.d.ts.map rename to circuits/.yalc/@aztec/wasm/dest/worker/browser/start_web_module.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/start_web_module.js b/circuits/.yalc/@aztec/wasm/dest/worker/browser/start_web_module.js similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/start_web_module.js rename to circuits/.yalc/@aztec/wasm/dest/worker/browser/start_web_module.js diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/web_data_store.d.ts b/circuits/.yalc/@aztec/wasm/dest/worker/browser/web_data_store.d.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/web_data_store.d.ts rename to circuits/.yalc/@aztec/wasm/dest/worker/browser/web_data_store.d.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/web_data_store.d.ts.map b/circuits/.yalc/@aztec/wasm/dest/worker/browser/web_data_store.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/web_data_store.d.ts.map rename to circuits/.yalc/@aztec/wasm/dest/worker/browser/web_data_store.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/web_data_store.js b/circuits/.yalc/@aztec/wasm/dest/worker/browser/web_data_store.js similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/browser/web_data_store.js rename to circuits/.yalc/@aztec/wasm/dest/worker/browser/web_data_store.js diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/web_worker.d.ts b/circuits/.yalc/@aztec/wasm/dest/worker/browser/web_worker.d.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/web_worker.d.ts rename to circuits/.yalc/@aztec/wasm/dest/worker/browser/web_worker.d.ts diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/web_worker.d.ts.map b/circuits/.yalc/@aztec/wasm/dest/worker/browser/web_worker.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/web_worker.d.ts.map rename to circuits/.yalc/@aztec/wasm/dest/worker/browser/web_worker.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/web_worker.js b/circuits/.yalc/@aztec/wasm/dest/worker/browser/web_worker.js similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm/dest/worker/browser/web_worker.js rename to circuits/.yalc/@aztec/wasm/dest/worker/browser/web_worker.js diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/data_store.d.ts b/circuits/.yalc/@aztec/wasm/dest/worker/data_store.d.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/data_store.d.ts rename to circuits/.yalc/@aztec/wasm/dest/worker/data_store.d.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/data_store.d.ts.map b/circuits/.yalc/@aztec/wasm/dest/worker/data_store.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/data_store.d.ts.map rename to circuits/.yalc/@aztec/wasm/dest/worker/data_store.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/data_store.js b/circuits/.yalc/@aztec/wasm/dest/worker/data_store.js similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/data_store.js rename to circuits/.yalc/@aztec/wasm/dest/worker/data_store.js diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/worker/index.d.ts b/circuits/.yalc/@aztec/wasm/dest/worker/index.d.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm/dest/worker/index.d.ts rename to circuits/.yalc/@aztec/wasm/dest/worker/index.d.ts diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/worker/index.d.ts.map b/circuits/.yalc/@aztec/wasm/dest/worker/index.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm/dest/worker/index.d.ts.map rename to circuits/.yalc/@aztec/wasm/dest/worker/index.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/worker/index.js b/circuits/.yalc/@aztec/wasm/dest/worker/index.js similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm/dest/worker/index.js rename to circuits/.yalc/@aztec/wasm/dest/worker/index.js diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/index.d.ts b/circuits/.yalc/@aztec/wasm/dest/worker/node/index.d.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/index.d.ts rename to circuits/.yalc/@aztec/wasm/dest/worker/node/index.d.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/index.d.ts.map b/circuits/.yalc/@aztec/wasm/dest/worker/node/index.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/index.d.ts.map rename to circuits/.yalc/@aztec/wasm/dest/worker/node/index.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/index.js b/circuits/.yalc/@aztec/wasm/dest/worker/node/index.js similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/index.js rename to circuits/.yalc/@aztec/wasm/dest/worker/node/index.js diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/node_data_store.d.ts b/circuits/.yalc/@aztec/wasm/dest/worker/node/node_data_store.d.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/node_data_store.d.ts rename to circuits/.yalc/@aztec/wasm/dest/worker/node/node_data_store.d.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/node_data_store.d.ts.map b/circuits/.yalc/@aztec/wasm/dest/worker/node/node_data_store.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/node_data_store.d.ts.map rename to circuits/.yalc/@aztec/wasm/dest/worker/node/node_data_store.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/node_data_store.js b/circuits/.yalc/@aztec/wasm/dest/worker/node/node_data_store.js similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/node_data_store.js rename to circuits/.yalc/@aztec/wasm/dest/worker/node/node_data_store.js diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/node_worker.d.ts b/circuits/.yalc/@aztec/wasm/dest/worker/node/node_worker.d.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/node_worker.d.ts rename to circuits/.yalc/@aztec/wasm/dest/worker/node/node_worker.d.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/node_worker.d.ts.map b/circuits/.yalc/@aztec/wasm/dest/worker/node/node_worker.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/node_worker.d.ts.map rename to circuits/.yalc/@aztec/wasm/dest/worker/node/node_worker.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/node_worker.js b/circuits/.yalc/@aztec/wasm/dest/worker/node/node_worker.js similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/node_worker.js rename to circuits/.yalc/@aztec/wasm/dest/worker/node/node_worker.js diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/start_node_module.d.ts b/circuits/.yalc/@aztec/wasm/dest/worker/node/start_node_module.d.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/start_node_module.d.ts rename to circuits/.yalc/@aztec/wasm/dest/worker/node/start_node_module.d.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/start_node_module.d.ts.map b/circuits/.yalc/@aztec/wasm/dest/worker/node/start_node_module.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/start_node_module.d.ts.map rename to circuits/.yalc/@aztec/wasm/dest/worker/node/start_node_module.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/start_node_module.js b/circuits/.yalc/@aztec/wasm/dest/worker/node/start_node_module.js similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/node/start_node_module.js rename to circuits/.yalc/@aztec/wasm/dest/worker/node/start_node_module.js diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/wasm_worker.d.ts b/circuits/.yalc/@aztec/wasm/dest/worker/wasm_worker.d.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/wasm_worker.d.ts rename to circuits/.yalc/@aztec/wasm/dest/worker/wasm_worker.d.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/wasm_worker.d.ts.map b/circuits/.yalc/@aztec/wasm/dest/worker/wasm_worker.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/wasm_worker.d.ts.map rename to circuits/.yalc/@aztec/wasm/dest/worker/wasm_worker.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/wasm_worker.js b/circuits/.yalc/@aztec/wasm/dest/worker/wasm_worker.js similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/wasm_worker.js rename to circuits/.yalc/@aztec/wasm/dest/worker/wasm_worker.js diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/worker_pool.d.ts b/circuits/.yalc/@aztec/wasm/dest/worker/worker_pool.d.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/worker_pool.d.ts rename to circuits/.yalc/@aztec/wasm/dest/worker/worker_pool.d.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/worker_pool.d.ts.map b/circuits/.yalc/@aztec/wasm/dest/worker/worker_pool.d.ts.map similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/dest/worker/worker_pool.d.ts.map rename to circuits/.yalc/@aztec/wasm/dest/worker/worker_pool.d.ts.map diff --git a/circuits/ts/.yalc/@aztec/wasm/dest/worker/worker_pool.js b/circuits/.yalc/@aztec/wasm/dest/worker/worker_pool.js similarity index 70% rename from circuits/ts/.yalc/@aztec/wasm/dest/worker/worker_pool.js rename to circuits/.yalc/@aztec/wasm/dest/worker/worker_pool.js index bddeb77620d..e98199d3de2 100644 --- a/circuits/ts/.yalc/@aztec/wasm/dest/worker/worker_pool.js +++ b/circuits/.yalc/@aztec/wasm/dest/worker/worker_pool.js @@ -1,48 +1,56 @@ -import { createDebugLogger } from '@aztec/log'; -const debug = createDebugLogger('bb:worker_pool'); +import { createDebugLogger } from "@aztec/foundation"; +const debug = createDebugLogger("bb:worker_pool"); /** * Allocates a pool of WasmWorker's. * Worker 0 is allocated MAX_PAGES memory pages. This is because worker 0 will need to hold the proving key * (i.e. Has state), whereas the others are pure compute (they hold a little crs state). */ export class WorkerPool { - constructor() { - /** - * The workers in the pool. - */ - this.workers = []; - } + constructor() { /** - * Create an instance and initialize the workers. - * @param createWorker - Worker factory. - * @param poolSize - Pool size. - * @returns An initialized WorkerPool. + * The workers in the pool. */ - static async new(createWorker, poolSize) { - const pool = new WorkerPool(); - await pool.init(createWorker, poolSize); - return pool; - } - /** - * Initialize the workers. - * @param createWorker - Worker factory(). - * @param poolSize - Pool size. - * @param maxMem - Max memory pages. - */ - async init(createWorker, poolSize, maxMem = WorkerPool.MAX_PAGES) { - debug(`creating ${poolSize} workers...`); - const start = new Date().getTime(); - this.workers = await Promise.all(Array(poolSize) - .fill(0) - .map((_, i) => createWorker(`${i}`, i === 0 ? Math.min(WorkerPool.MAX_PAGES, maxMem) : 768, maxMem))); - debug(`created workers: ${new Date().getTime() - start}ms`); - } - /** - * Tell all workers in the pool to stop processing. - */ - async destroy() { - await Promise.all(this.workers.map(w => w.destroyWorker())); - } + this.workers = []; + } + /** + * Create an instance and initialize the workers. + * @param createWorker - Worker factory. + * @param poolSize - Pool size. + * @returns An initialized WorkerPool. + */ + static async new(createWorker, poolSize) { + const pool = new WorkerPool(); + await pool.init(createWorker, poolSize); + return pool; + } + /** + * Initialize the workers. + * @param createWorker - Worker factory(). + * @param poolSize - Pool size. + * @param maxMem - Max memory pages. + */ + async init(createWorker, poolSize, maxMem = WorkerPool.MAX_PAGES) { + debug(`creating ${poolSize} workers...`); + const start = new Date().getTime(); + this.workers = await Promise.all( + Array(poolSize) + .fill(0) + .map((_, i) => + createWorker( + `${i}`, + i === 0 ? Math.min(WorkerPool.MAX_PAGES, maxMem) : 768, + maxMem + ) + ) + ); + debug(`created workers: ${new Date().getTime() - start}ms`); + } + /** + * Tell all workers in the pool to stop processing. + */ + async destroy() { + await Promise.all(this.workers.map((w) => w.destroyWorker())); + } } // TODO(AD): Revisit what this means in aztec 3 context // -- @@ -59,4 +67,4 @@ export class WorkerPool { * The maximum number of memory pages to be used by the webassembly. */ WorkerPool.MAX_PAGES = 8192; -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid29ya2VyX3Bvb2wuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvd29ya2VyL3dvcmtlcl9wb29sLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLFlBQVksQ0FBQztBQUcvQyxNQUFNLEtBQUssR0FBRyxpQkFBaUIsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO0FBT2xEOzs7O0dBSUc7QUFDSCxNQUFNLE9BQU8sVUFBVTtJQUF2QjtRQWdCRTs7V0FFRztRQUNLLFlBQU8sR0FBaUIsRUFBRSxDQUFDO0lBc0NyQyxDQUFDO0lBcENDOzs7OztPQUtHO0lBQ0gsTUFBTSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsWUFBMEIsRUFBRSxRQUFnQjtRQUMzRCxNQUFNLElBQUksR0FBRyxJQUFJLFVBQVUsRUFBRSxDQUFDO1FBQzlCLE1BQU0sSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLEVBQUUsUUFBUSxDQUFDLENBQUM7UUFDeEMsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSSxLQUFLLENBQUMsSUFBSSxDQUFDLFlBQTBCLEVBQUUsUUFBZ0IsRUFBRSxNQUFNLEdBQUcsVUFBVSxDQUFDLFNBQVM7UUFDM0YsS0FBSyxDQUFDLFlBQVksUUFBUSxhQUFhLENBQUMsQ0FBQztRQUN6QyxNQUFNLEtBQUssR0FBRyxJQUFJLElBQUksRUFBRSxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ25DLElBQUksQ0FBQyxPQUFPLEdBQUcsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUM5QixLQUFLLENBQUMsUUFBUSxDQUFDO2FBQ1osSUFBSSxDQUFDLENBQUMsQ0FBQzthQUNQLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLFlBQVksQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLFNBQVMsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQ3ZHLENBQUM7UUFFRixLQUFLLENBQUMsb0JBQW9CLElBQUksSUFBSSxFQUFFLENBQUMsT0FBTyxFQUFFLEdBQUcsS0FBSyxJQUFJLENBQUMsQ0FBQztJQUM5RCxDQUFDO0lBRUQ7O09BRUc7SUFDSSxLQUFLLENBQUMsT0FBTztRQUNsQixNQUFNLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsYUFBYSxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQzlELENBQUM7O0FBdkRELHVEQUF1RDtBQUN2RCxLQUFLO0FBQ0wsc0hBQXNIO0FBQ3RILGdIQUFnSDtBQUNoSCxpSEFBaUg7QUFDakgscUdBQXFHO0FBQ3JHLDREQUE0RDtBQUM1RCxrR0FBa0c7QUFDbEcsMEZBQTBGO0FBQzFGLDZHQUE2RztBQUM3RyxrQ0FBa0M7QUFDbEM7O0dBRUc7QUFDVyxvQkFBUyxHQUFHLElBQUksQ0FBQyJ9 \ No newline at end of file +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid29ya2VyX3Bvb2wuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvd29ya2VyL3dvcmtlcl9wb29sLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLFlBQVksQ0FBQztBQUcvQyxNQUFNLEtBQUssR0FBRyxpQkFBaUIsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO0FBT2xEOzs7O0dBSUc7QUFDSCxNQUFNLE9BQU8sVUFBVTtJQUF2QjtRQWdCRTs7V0FFRztRQUNLLFlBQU8sR0FBaUIsRUFBRSxDQUFDO0lBc0NyQyxDQUFDO0lBcENDOzs7OztPQUtHO0lBQ0gsTUFBTSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsWUFBMEIsRUFBRSxRQUFnQjtRQUMzRCxNQUFNLElBQUksR0FBRyxJQUFJLFVBQVUsRUFBRSxDQUFDO1FBQzlCLE1BQU0sSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLEVBQUUsUUFBUSxDQUFDLENBQUM7UUFDeEMsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSSxLQUFLLENBQUMsSUFBSSxDQUFDLFlBQTBCLEVBQUUsUUFBZ0IsRUFBRSxNQUFNLEdBQUcsVUFBVSxDQUFDLFNBQVM7UUFDM0YsS0FBSyxDQUFDLFlBQVksUUFBUSxhQUFhLENBQUMsQ0FBQztRQUN6QyxNQUFNLEtBQUssR0FBRyxJQUFJLElBQUksRUFBRSxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ25DLElBQUksQ0FBQyxPQUFPLEdBQUcsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUM5QixLQUFLLENBQUMsUUFBUSxDQUFDO2FBQ1osSUFBSSxDQUFDLENBQUMsQ0FBQzthQUNQLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLFlBQVksQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLFNBQVMsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQ3ZHLENBQUM7UUFFRixLQUFLLENBQUMsb0JBQW9CLElBQUksSUFBSSxFQUFFLENBQUMsT0FBTyxFQUFFLEdBQUcsS0FBSyxJQUFJLENBQUMsQ0FBQztJQUM5RCxDQUFDO0lBRUQ7O09BRUc7SUFDSSxLQUFLLENBQUMsT0FBTztRQUNsQixNQUFNLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsYUFBYSxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQzlELENBQUM7O0FBdkRELHVEQUF1RDtBQUN2RCxLQUFLO0FBQ0wsc0hBQXNIO0FBQ3RILGdIQUFnSDtBQUNoSCxpSEFBaUg7QUFDakgscUdBQXFHO0FBQ3JHLDREQUE0RDtBQUM1RCxrR0FBa0c7QUFDbEcsMEZBQTBGO0FBQzFGLDZHQUE2RztBQUM3RyxrQ0FBa0M7QUFDbEM7O0dBRUc7QUFDVyxvQkFBUyxHQUFHLElBQUksQ0FBQyJ9 diff --git a/circuits/ts/.yalc/@aztec/wasm/package.json b/circuits/.yalc/@aztec/wasm/package.json similarity index 96% rename from circuits/ts/.yalc/@aztec/wasm/package.json rename to circuits/.yalc/@aztec/wasm/package.json index 46b6958376e..8a766b2290d 100644 --- a/circuits/ts/.yalc/@aztec/wasm/package.json +++ b/circuits/.yalc/@aztec/wasm/package.json @@ -30,7 +30,7 @@ "rootDir": "./src" }, "dependencies": { - "@aztec/log": "*", + "@aztec/foundation": "workspace:^", "@types/leveldown": "^4.0.3", "detect-node": "^2.1.0", "leveldown": "^6.1.1", diff --git a/circuits/ts/.yalc/@aztec/wasm/src/index.ts b/circuits/.yalc/@aztec/wasm/src/index.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm/src/index.ts rename to circuits/.yalc/@aztec/wasm/src/index.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/memory_fifo.ts b/circuits/.yalc/@aztec/wasm/src/memory_fifo.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/src/memory_fifo.ts rename to circuits/.yalc/@aztec/wasm/src/memory_fifo.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/test/gcd.wasm b/circuits/.yalc/@aztec/wasm/src/test/gcd.wasm similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/src/test/gcd.wasm rename to circuits/.yalc/@aztec/wasm/src/test/gcd.wasm diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/test/gcd.wat b/circuits/.yalc/@aztec/wasm/src/test/gcd.wat similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/src/test/gcd.wat rename to circuits/.yalc/@aztec/wasm/src/test/gcd.wat diff --git a/circuits/ts/.yalc/@aztec/wasm/src/transport/browser/index.ts b/circuits/.yalc/@aztec/wasm/src/transport/browser/index.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm/src/transport/browser/index.ts rename to circuits/.yalc/@aztec/wasm/src/transport/browser/index.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/browser/message_port_socket.ts b/circuits/.yalc/@aztec/wasm/src/transport/browser/message_port_socket.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/src/transport/browser/message_port_socket.ts rename to circuits/.yalc/@aztec/wasm/src/transport/browser/message_port_socket.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/browser/shared_worker_connector.ts b/circuits/.yalc/@aztec/wasm/src/transport/browser/shared_worker_connector.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/src/transport/browser/shared_worker_connector.ts rename to circuits/.yalc/@aztec/wasm/src/transport/browser/shared_worker_connector.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/browser/shared_worker_listener.ts b/circuits/.yalc/@aztec/wasm/src/transport/browser/shared_worker_listener.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/src/transport/browser/shared_worker_listener.ts rename to circuits/.yalc/@aztec/wasm/src/transport/browser/shared_worker_listener.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/browser/worker_connector.ts b/circuits/.yalc/@aztec/wasm/src/transport/browser/worker_connector.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/src/transport/browser/worker_connector.ts rename to circuits/.yalc/@aztec/wasm/src/transport/browser/worker_connector.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/browser/worker_listener.ts b/circuits/.yalc/@aztec/wasm/src/transport/browser/worker_listener.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/src/transport/browser/worker_listener.ts rename to circuits/.yalc/@aztec/wasm/src/transport/browser/worker_listener.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/dispatch/create_dispatch_fn.ts b/circuits/.yalc/@aztec/wasm/src/transport/dispatch/create_dispatch_fn.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/src/transport/dispatch/create_dispatch_fn.ts rename to circuits/.yalc/@aztec/wasm/src/transport/dispatch/create_dispatch_fn.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/dispatch/create_dispatch_proxy.ts b/circuits/.yalc/@aztec/wasm/src/transport/dispatch/create_dispatch_proxy.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/src/transport/dispatch/create_dispatch_proxy.ts rename to circuits/.yalc/@aztec/wasm/src/transport/dispatch/create_dispatch_proxy.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/dispatch/messages.ts b/circuits/.yalc/@aztec/wasm/src/transport/dispatch/messages.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/src/transport/dispatch/messages.ts rename to circuits/.yalc/@aztec/wasm/src/transport/dispatch/messages.ts diff --git a/circuits/ts/.yalc/@aztec/wasm/src/transport/index.ts b/circuits/.yalc/@aztec/wasm/src/transport/index.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm/src/transport/index.ts rename to circuits/.yalc/@aztec/wasm/src/transport/index.ts diff --git a/circuits/ts/.yalc/@aztec/wasm/src/transport/interface/connector.ts b/circuits/.yalc/@aztec/wasm/src/transport/interface/connector.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm/src/transport/interface/connector.ts rename to circuits/.yalc/@aztec/wasm/src/transport/interface/connector.ts diff --git a/circuits/ts/.yalc/@aztec/wasm/src/transport/interface/listener.ts b/circuits/.yalc/@aztec/wasm/src/transport/interface/listener.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm/src/transport/interface/listener.ts rename to circuits/.yalc/@aztec/wasm/src/transport/interface/listener.ts diff --git a/circuits/ts/.yalc/@aztec/wasm/src/transport/interface/socket.ts b/circuits/.yalc/@aztec/wasm/src/transport/interface/socket.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm/src/transport/interface/socket.ts rename to circuits/.yalc/@aztec/wasm/src/transport/interface/socket.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/interface/transferable.ts b/circuits/.yalc/@aztec/wasm/src/transport/interface/transferable.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/src/transport/interface/transferable.ts rename to circuits/.yalc/@aztec/wasm/src/transport/interface/transferable.ts diff --git a/circuits/ts/.yalc/@aztec/wasm/src/transport/node/index.ts b/circuits/.yalc/@aztec/wasm/src/transport/node/index.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm/src/transport/node/index.ts rename to circuits/.yalc/@aztec/wasm/src/transport/node/index.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/node/node_connector.ts b/circuits/.yalc/@aztec/wasm/src/transport/node/node_connector.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/src/transport/node/node_connector.ts rename to circuits/.yalc/@aztec/wasm/src/transport/node/node_connector.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/node/node_connector_socket.ts b/circuits/.yalc/@aztec/wasm/src/transport/node/node_connector_socket.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/src/transport/node/node_connector_socket.ts rename to circuits/.yalc/@aztec/wasm/src/transport/node/node_connector_socket.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/node/node_listener.ts b/circuits/.yalc/@aztec/wasm/src/transport/node/node_listener.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/src/transport/node/node_listener.ts rename to circuits/.yalc/@aztec/wasm/src/transport/node/node_listener.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/node/node_listener_socket.ts b/circuits/.yalc/@aztec/wasm/src/transport/node/node_listener_socket.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/src/transport/node/node_listener_socket.ts rename to circuits/.yalc/@aztec/wasm/src/transport/node/node_listener_socket.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/transport_client.ts b/circuits/.yalc/@aztec/wasm/src/transport/transport_client.ts similarity index 73% rename from circuits/ts/.yalc/@aztec/wasm-worker/src/transport/transport_client.ts rename to circuits/.yalc/@aztec/wasm/src/transport/transport_client.ts index 5577d7a5ed5..9140f199a7d 100644 --- a/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/transport_client.ts +++ b/circuits/.yalc/@aztec/wasm/src/transport/transport_client.ts @@ -1,10 +1,14 @@ -import { createDebugLogger } from '@aztec/log'; -import EventEmitter from 'events'; -import { EventMessage, isEventMessage, ResponseMessage } from './dispatch/messages.js'; -import { Connector } from './interface/connector.js'; -import { Socket } from './interface/socket.js'; +import { createDebugLogger } from "@aztec/foundation"; +import EventEmitter from "events"; +import { + EventMessage, + isEventMessage, + ResponseMessage, +} from "./dispatch/messages.js"; +import { Connector } from "./interface/connector.js"; +import { Socket } from "./interface/socket.js"; -const debug = createDebugLogger('aztec:transport_client'); +const debug = createDebugLogger("aztec:transport_client"); /** * A pending request. @@ -22,8 +26,8 @@ interface PendingRequest { * Augments the TransportClient class with more precise EventEmitter types. */ export interface TransportClient extends EventEmitter { - on(name: 'event_msg', handler: (payload: Payload) => void): this; - emit(name: 'event_msg', payload: Payload): boolean; + on(name: "event_msg", handler: (payload: Payload) => void): this; + emit(name: "event_msg", payload: Payload): boolean; } /** @@ -46,7 +50,7 @@ export class TransportClient extends EventEmitter { */ async open() { this.socket = await this.transportConnect.createSocket(); - this.socket.registerHandler(msg => this.handleSocketMessage(msg)); + this.socket.registerHandler((msg) => this.handleSocketMessage(msg)); } /** @@ -66,7 +70,7 @@ export class TransportClient extends EventEmitter { */ request(payload: Payload, transfer?: Transferable[]) { if (!this.socket) { - throw new Error('Socket not open.'); + throw new Error("Socket not open."); } const msgId = this.msgId++; const msg = { msgId, payload }; @@ -81,7 +85,9 @@ export class TransportClient extends EventEmitter { * Handle an incoming socket message. * @param msg - The message. */ - private handleSocketMessage(msg: ResponseMessage | EventMessage | undefined) { + private handleSocketMessage( + msg: ResponseMessage | EventMessage | undefined + ) { if (msg === undefined) { // The remote socket closed. this.close(); @@ -89,10 +95,12 @@ export class TransportClient extends EventEmitter { } debug(`<-`, msg); if (isEventMessage(msg)) { - this.emit('event_msg', msg.payload); + this.emit("event_msg", msg.payload); return; } - const reqIndex = this.pendingRequests.findIndex(r => r.msgId === msg.msgId); + const reqIndex = this.pendingRequests.findIndex( + (r) => r.msgId === msg.msgId + ); if (reqIndex === -1) { return; } diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/transport/transport_server.ts b/circuits/.yalc/@aztec/wasm/src/transport/transport_server.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/src/transport/transport_server.ts rename to circuits/.yalc/@aztec/wasm/src/transport/transport_server.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/wasm/async_call_state.ts b/circuits/.yalc/@aztec/wasm/src/wasm/async_call_state.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/src/wasm/async_call_state.ts rename to circuits/.yalc/@aztec/wasm/src/wasm/async_call_state.ts diff --git a/circuits/ts/.yalc/@aztec/wasm/src/wasm/empty_wasi_sdk.ts b/circuits/.yalc/@aztec/wasm/src/wasm/empty_wasi_sdk.ts similarity index 57% rename from circuits/ts/.yalc/@aztec/wasm/src/wasm/empty_wasi_sdk.ts rename to circuits/.yalc/@aztec/wasm/src/wasm/empty_wasi_sdk.ts index 5d475696ca5..36ccfd3e0ec 100644 --- a/circuits/ts/.yalc/@aztec/wasm/src/wasm/empty_wasi_sdk.ts +++ b/circuits/.yalc/@aztec/wasm/src/wasm/empty_wasi_sdk.ts @@ -1,4 +1,4 @@ -import { createDebugLogger } from '@aztec/log'; +import { createDebugLogger } from "@aztec/foundation"; /** * Dummy implementation of a necessary part of the wasi api: @@ -8,54 +8,56 @@ import { createDebugLogger } from '@aztec/log'; */ /* eslint-disable camelcase */ /* eslint-disable jsdoc/require-jsdoc */ -export const getEmptyWasiSdk = (debug = createDebugLogger('wasm:empty_wasi_sdk')) => ({ +export const getEmptyWasiSdk = ( + debug = createDebugLogger("wasm:empty_wasi_sdk") +) => ({ clock_time_get() { - debug('clock_time_get'); + debug("clock_time_get"); }, environ_get() { - debug('environ_get'); + debug("environ_get"); }, environ_sizes_get() { - debug('environ_sizes_get'); + debug("environ_sizes_get"); }, fd_close() { - debug('fd_close'); + debug("fd_close"); }, fd_read() { - debug('fd_read'); + debug("fd_read"); }, fd_write() { - debug('fd_write'); + debug("fd_write"); }, fd_seek() { - debug('fd_seek'); + debug("fd_seek"); }, fd_fdstat_get() { - debug('fd_fdstat_get'); + debug("fd_fdstat_get"); }, fd_fdstat_set_flags() { - debug('fd_fdstat_set_flags'); + debug("fd_fdstat_set_flags"); }, fd_prestat_get() { - debug('fd_prestat_get'); + debug("fd_prestat_get"); return 8; }, fd_prestat_dir_name() { - debug('fd_prestat_dir_name'); + debug("fd_prestat_dir_name"); return 28; }, path_open() { - debug('path_open'); + debug("path_open"); }, path_filestat_get() { - debug('path_filestat_get'); + debug("path_filestat_get"); }, proc_exit() { - debug('proc_exit'); + debug("proc_exit"); return 52; }, random_get() { - debug('random_get'); + debug("random_get"); return 1; }, }); diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/wasm/index.ts b/circuits/.yalc/@aztec/wasm/src/wasm/index.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/src/wasm/index.ts rename to circuits/.yalc/@aztec/wasm/src/wasm/index.ts diff --git a/circuits/ts/.yalc/@aztec/wasm/src/wasm/wasm_module.test.ts b/circuits/.yalc/@aztec/wasm/src/wasm/wasm_module.test.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm/src/wasm/wasm_module.test.ts rename to circuits/.yalc/@aztec/wasm/src/wasm/wasm_module.test.ts diff --git a/circuits/ts/.yalc/@aztec/wasm/src/wasm/wasm_module.ts b/circuits/.yalc/@aztec/wasm/src/wasm/wasm_module.ts similarity index 89% rename from circuits/ts/.yalc/@aztec/wasm/src/wasm/wasm_module.ts rename to circuits/.yalc/@aztec/wasm/src/wasm/wasm_module.ts index abcec5ef385..890ed1d5b89 100644 --- a/circuits/ts/.yalc/@aztec/wasm/src/wasm/wasm_module.ts +++ b/circuits/.yalc/@aztec/wasm/src/wasm/wasm_module.ts @@ -1,8 +1,8 @@ -import { createDebugLogger, DebugLogger } from '@aztec/log'; -import { Buffer } from 'buffer'; -import { MemoryFifo } from '../memory_fifo.js'; -import { getEmptyWasiSdk } from './empty_wasi_sdk.js'; -import { randomBytes } from 'crypto'; +import { createDebugLogger, DebugLogger } from "@aztec/foundation"; +import { Buffer } from "buffer"; +import { MemoryFifo } from "../memory_fifo.js"; +import { getEmptyWasiSdk } from "./empty_wasi_sdk.js"; +import { randomBytes } from "crypto"; /** * WasmModule: @@ -28,7 +28,7 @@ export class WasmModule { constructor( private module: WebAssembly.Module | Buffer, private importFn: (module: WasmModule) => any, - loggerName = 'wasm', + loggerName = "wasm" ) { this.debug = createDebugLogger(loggerName); this.mutexQ.put(true); @@ -49,9 +49,9 @@ export class WasmModule { */ public async init(initial = 20, maximum = 8192) { this.debug( - `initial mem: ${initial} pages, ${(initial * 2 ** 16) / (1024 * 1024)}mb. max mem: ${maximum} pages, ${ - (maximum * 2 ** 16) / (1024 * 1024) - }mb`, + `initial mem: ${initial} pages, ${ + (initial * 2 ** 16) / (1024 * 1024) + }mb. max mem: ${maximum} pages, ${(maximum * 2 ** 16) / (1024 * 1024)}mb` ); this.memory = new WebAssembly.Memory({ initial, maximum }); // Create a view over the memory buffer. @@ -82,7 +82,10 @@ export class WasmModule { if (this.module instanceof WebAssembly.Module) { this.instance = await WebAssembly.instantiate(this.module, importObj); } else { - const { instance } = await WebAssembly.instantiate(this.module, importObj); + const { instance } = await WebAssembly.instantiate( + this.module, + importObj + ); this.instance = instance; } } @@ -93,7 +96,7 @@ export class WasmModule { */ public exports(): any { if (!this.instance) { - throw new Error('WasmModule: not initialized!'); + throw new Error("WasmModule: not initialized!"); } return this.instance.exports; } @@ -198,7 +201,7 @@ export class WasmModule { const m = this.getMemory(); let i = addr; for (; m[i] !== 0; ++i); - return Buffer.from(m.slice(addr, i)).toString('ascii'); + return Buffer.from(m.slice(addr, i)).toString("ascii"); } /** @@ -216,7 +219,7 @@ export class WasmModule { */ public release() { if (this.mutexQ.length() !== 0) { - throw new Error('Release called but not acquired.'); + throw new Error("Release called but not acquired."); } this.mutexQ.put(true); } diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/browser/index.ts b/circuits/.yalc/@aztec/wasm/src/worker/browser/index.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/src/worker/browser/index.ts rename to circuits/.yalc/@aztec/wasm/src/worker/browser/index.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/browser/start_web_module.ts b/circuits/.yalc/@aztec/wasm/src/worker/browser/start_web_module.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/src/worker/browser/start_web_module.ts rename to circuits/.yalc/@aztec/wasm/src/worker/browser/start_web_module.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/browser/web_data_store.ts b/circuits/.yalc/@aztec/wasm/src/worker/browser/web_data_store.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/src/worker/browser/web_data_store.ts rename to circuits/.yalc/@aztec/wasm/src/worker/browser/web_data_store.ts diff --git a/circuits/ts/.yalc/@aztec/wasm/src/worker/browser/web_worker.ts b/circuits/.yalc/@aztec/wasm/src/worker/browser/web_worker.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm/src/worker/browser/web_worker.ts rename to circuits/.yalc/@aztec/wasm/src/worker/browser/web_worker.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/data_store.ts b/circuits/.yalc/@aztec/wasm/src/worker/data_store.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/src/worker/data_store.ts rename to circuits/.yalc/@aztec/wasm/src/worker/data_store.ts diff --git a/circuits/ts/.yalc/@aztec/wasm/src/worker/index.ts b/circuits/.yalc/@aztec/wasm/src/worker/index.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm/src/worker/index.ts rename to circuits/.yalc/@aztec/wasm/src/worker/index.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/node/index.ts b/circuits/.yalc/@aztec/wasm/src/worker/node/index.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/src/worker/node/index.ts rename to circuits/.yalc/@aztec/wasm/src/worker/node/index.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/node/node_data_store.ts b/circuits/.yalc/@aztec/wasm/src/worker/node/node_data_store.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/src/worker/node/node_data_store.ts rename to circuits/.yalc/@aztec/wasm/src/worker/node/node_data_store.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/node/node_worker.ts b/circuits/.yalc/@aztec/wasm/src/worker/node/node_worker.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/src/worker/node/node_worker.ts rename to circuits/.yalc/@aztec/wasm/src/worker/node/node_worker.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/node/start_node_module.ts b/circuits/.yalc/@aztec/wasm/src/worker/node/start_node_module.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/src/worker/node/start_node_module.ts rename to circuits/.yalc/@aztec/wasm/src/worker/node/start_node_module.ts diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/src/worker/wasm_worker.ts b/circuits/.yalc/@aztec/wasm/src/worker/wasm_worker.ts similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/src/worker/wasm_worker.ts rename to circuits/.yalc/@aztec/wasm/src/worker/wasm_worker.ts diff --git a/circuits/ts/.yalc/@aztec/wasm/src/worker/worker_pool.ts b/circuits/.yalc/@aztec/wasm/src/worker/worker_pool.ts similarity index 79% rename from circuits/ts/.yalc/@aztec/wasm/src/worker/worker_pool.ts rename to circuits/.yalc/@aztec/wasm/src/worker/worker_pool.ts index 7ac278ba571..04d2a2eba60 100644 --- a/circuits/ts/.yalc/@aztec/wasm/src/worker/worker_pool.ts +++ b/circuits/.yalc/@aztec/wasm/src/worker/worker_pool.ts @@ -1,13 +1,17 @@ -import { createDebugLogger } from '@aztec/log'; -import { WasmWorker } from './wasm_worker.js'; +import { createDebugLogger } from "@aztec/foundation"; +import { WasmWorker } from "./wasm_worker.js"; -const debug = createDebugLogger('bb:worker_pool'); +const debug = createDebugLogger("bb:worker_pool"); /** * Type of a worker factory. * Used to customize WorkerPool worker construction. */ -export type CreateWorker = (name: string, minMem: number, maxMem: number) => WasmWorker; +export type CreateWorker = ( + name: string, + minMem: number, + maxMem: number +) => WasmWorker; /** * Allocates a pool of WasmWorker's. * Worker 0 is allocated MAX_PAGES memory pages. This is because worker 0 will need to hold the proving key @@ -52,13 +56,23 @@ export class WorkerPool { * @param poolSize - Pool size. * @param maxMem - Max memory pages. */ - public async init(createWorker: CreateWorker, poolSize: number, maxMem = WorkerPool.MAX_PAGES) { + public async init( + createWorker: CreateWorker, + poolSize: number, + maxMem = WorkerPool.MAX_PAGES + ) { debug(`creating ${poolSize} workers...`); const start = new Date().getTime(); this.workers = await Promise.all( Array(poolSize) .fill(0) - .map((_, i) => createWorker(`${i}`, i === 0 ? Math.min(WorkerPool.MAX_PAGES, maxMem) : 768, maxMem)), + .map((_, i) => + createWorker( + `${i}`, + i === 0 ? Math.min(WorkerPool.MAX_PAGES, maxMem) : 768, + maxMem + ) + ) ); debug(`created workers: ${new Date().getTime() - start}ms`); @@ -68,6 +82,6 @@ export class WorkerPool { * Tell all workers in the pool to stop processing. */ public async destroy() { - await Promise.all(this.workers.map(w => w.destroyWorker())); + await Promise.all(this.workers.map((w) => w.destroyWorker())); } } diff --git a/circuits/ts/.yalc/@aztec/wasm-worker/tsconfig.dest.json b/circuits/.yalc/@aztec/wasm/tsconfig.dest.json similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm-worker/tsconfig.dest.json rename to circuits/.yalc/@aztec/wasm/tsconfig.dest.json diff --git a/circuits/ts/.yalc/@aztec/log/tsconfig.json b/circuits/.yalc/@aztec/wasm/tsconfig.json similarity index 100% rename from circuits/ts/.yalc/@aztec/log/tsconfig.json rename to circuits/.yalc/@aztec/wasm/tsconfig.json diff --git a/circuits/ts/.yalc/@aztec/wasm/yalc.sig b/circuits/.yalc/@aztec/wasm/yalc.sig similarity index 100% rename from circuits/ts/.yalc/@aztec/wasm/yalc.sig rename to circuits/.yalc/@aztec/wasm/yalc.sig diff --git a/circuits/.yarn/install-state.gz b/circuits/.yarn/install-state.gz new file mode 100644 index 0000000000000000000000000000000000000000..c44a6350e3ded26775596585692858e6c6eaa00f GIT binary patch literal 509645 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­uPVOj>-!l6&|*mQZw7pkww)Qv~<3m{^L`t26Q+~ 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

->kN^eoMMYhlCLS-6*6GB^NzO5` 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

)8&&1Nl%lHODehmt1sqsoPp+MZrg;xQX> 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 uwi^z7rD^@Zj>gslQZYR3bqMGrN9Ea>qzSgND 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

2A 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
)^* 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 z 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

@8wlY0Ov#o6D=qxlViGcyQy# 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 literal 0 HcmV?d00001 diff --git a/circuits/.yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs b/circuits/.yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs new file mode 100644 index 00000000000..4e89c7c352c --- /dev/null +++ b/circuits/.yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs @@ -0,0 +1,28 @@ +/* eslint-disable */ +//prettier-ignore +module.exports = { +name: "@yarnpkg/plugin-workspace-tools", +factory: function (require) { +var plugin=(()=>{var yr=Object.create;var we=Object.defineProperty;var _r=Object.getOwnPropertyDescriptor;var Er=Object.getOwnPropertyNames;var br=Object.getPrototypeOf,xr=Object.prototype.hasOwnProperty;var W=(e=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(r,t)=>(typeof require<"u"?require:r)[t]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw new Error('Dynamic require of "'+e+'" is not supported')});var q=(e,r)=>()=>(r||e((r={exports:{}}).exports,r),r.exports),Cr=(e,r)=>{for(var t in r)we(e,t,{get:r[t],enumerable:!0})},Je=(e,r,t,n)=>{if(r&&typeof r=="object"||typeof r=="function")for(let s of Er(r))!xr.call(e,s)&&s!==t&&we(e,s,{get:()=>r[s],enumerable:!(n=_r(r,s))||n.enumerable});return e};var Be=(e,r,t)=>(t=e!=null?yr(br(e)):{},Je(r||!e||!e.__esModule?we(t,"default",{value:e,enumerable:!0}):t,e)),wr=e=>Je(we({},"__esModule",{value:!0}),e);var ve=q(ee=>{"use strict";ee.isInteger=e=>typeof e=="number"?Number.isInteger(e):typeof e=="string"&&e.trim()!==""?Number.isInteger(Number(e)):!1;ee.find=(e,r)=>e.nodes.find(t=>t.type===r);ee.exceedsLimit=(e,r,t=1,n)=>n===!1||!ee.isInteger(e)||!ee.isInteger(r)?!1:(Number(r)-Number(e))/Number(t)>=n;ee.escapeNode=(e,r=0,t)=>{let n=e.nodes[r];!n||(t&&n.type===t||n.type==="open"||n.type==="close")&&n.escaped!==!0&&(n.value="\\"+n.value,n.escaped=!0)};ee.encloseBrace=e=>e.type!=="brace"?!1:e.commas>>0+e.ranges>>0===0?(e.invalid=!0,!0):!1;ee.isInvalidBrace=e=>e.type!=="brace"?!1:e.invalid===!0||e.dollar?!0:e.commas>>0+e.ranges>>0===0||e.open!==!0||e.close!==!0?(e.invalid=!0,!0):!1;ee.isOpenOrClose=e=>e.type==="open"||e.type==="close"?!0:e.open===!0||e.close===!0;ee.reduce=e=>e.reduce((r,t)=>(t.type==="text"&&r.push(t.value),t.type==="range"&&(t.type="text"),r),[]);ee.flatten=(...e)=>{let r=[],t=n=>{for(let s=0;s{"use strict";var tt=ve();rt.exports=(e,r={})=>{let t=(n,s={})=>{let i=r.escapeInvalid&&tt.isInvalidBrace(s),a=n.invalid===!0&&r.escapeInvalid===!0,c="";if(n.value)return(i||a)&&tt.isOpenOrClose(n)?"\\"+n.value:n.value;if(n.value)return n.value;if(n.nodes)for(let p of n.nodes)c+=t(p);return c};return t(e)}});var st=q((Vn,nt)=>{"use strict";nt.exports=function(e){return typeof e=="number"?e-e===0:typeof e=="string"&&e.trim()!==""?Number.isFinite?Number.isFinite(+e):isFinite(+e):!1}});var ht=q((Jn,pt)=>{"use strict";var at=st(),le=(e,r,t)=>{if(at(e)===!1)throw new TypeError("toRegexRange: expected the first argument to be a number");if(r===void 0||e===r)return String(e);if(at(r)===!1)throw new TypeError("toRegexRange: expected the second argument to be a number.");let n={relaxZeros:!0,...t};typeof n.strictZeros=="boolean"&&(n.relaxZeros=n.strictZeros===!1);let s=String(n.relaxZeros),i=String(n.shorthand),a=String(n.capture),c=String(n.wrap),p=e+":"+r+"="+s+i+a+c;if(le.cache.hasOwnProperty(p))return le.cache[p].result;let m=Math.min(e,r),h=Math.max(e,r);if(Math.abs(m-h)===1){let y=e+"|"+r;return n.capture?`(${y})`:n.wrap===!1?y:`(?:${y})`}let R=ft(e)||ft(r),f={min:e,max:r,a:m,b:h},$=[],_=[];if(R&&(f.isPadded=R,f.maxLen=String(f.max).length),m<0){let y=h<0?Math.abs(h):1;_=it(y,Math.abs(m),f,n),m=f.a=0}return h>=0&&($=it(m,h,f,n)),f.negatives=_,f.positives=$,f.result=Sr(_,$,n),n.capture===!0?f.result=`(${f.result})`:n.wrap!==!1&&$.length+_.length>1&&(f.result=`(?:${f.result})`),le.cache[p]=f,f.result};function Sr(e,r,t){let n=Pe(e,r,"-",!1,t)||[],s=Pe(r,e,"",!1,t)||[],i=Pe(e,r,"-?",!0,t)||[];return n.concat(i).concat(s).join("|")}function vr(e,r){let t=1,n=1,s=ut(e,t),i=new Set([r]);for(;e<=s&&s<=r;)i.add(s),t+=1,s=ut(e,t);for(s=ct(r+1,n)-1;e1&&c.count.pop(),c.count.push(h.count[0]),c.string=c.pattern+lt(c.count),a=m+1;continue}t.isPadded&&(R=Lr(m,t,n)),h.string=R+h.pattern+lt(h.count),i.push(h),a=m+1,c=h}return i}function Pe(e,r,t,n,s){let i=[];for(let a of e){let{string:c}=a;!n&&!ot(r,"string",c)&&i.push(t+c),n&&ot(r,"string",c)&&i.push(t+c)}return i}function $r(e,r){let t=[];for(let n=0;nr?1:r>e?-1:0}function ot(e,r,t){return e.some(n=>n[r]===t)}function ut(e,r){return Number(String(e).slice(0,-r)+"9".repeat(r))}function ct(e,r){return e-e%Math.pow(10,r)}function lt(e){let[r=0,t=""]=e;return t||r>1?`{${r+(t?","+t:"")}}`:""}function kr(e,r,t){return`[${e}${r-e===1?"":"-"}${r}]`}function ft(e){return/^-?(0+)\d/.test(e)}function Lr(e,r,t){if(!r.isPadded)return e;let n=Math.abs(r.maxLen-String(e).length),s=t.relaxZeros!==!1;switch(n){case 0:return"";case 1:return s?"0?":"0";case 2:return s?"0{0,2}":"00";default:return s?`0{0,${n}}`:`0{${n}}`}}le.cache={};le.clearCache=()=>le.cache={};pt.exports=le});var Ue=q((es,Et)=>{"use strict";var Or=W("util"),At=ht(),dt=e=>e!==null&&typeof e=="object"&&!Array.isArray(e),Nr=e=>r=>e===!0?Number(r):String(r),Me=e=>typeof e=="number"||typeof e=="string"&&e!=="",Ae=e=>Number.isInteger(+e),De=e=>{let r=`${e}`,t=-1;if(r[0]==="-"&&(r=r.slice(1)),r==="0")return!1;for(;r[++t]==="0";);return t>0},Ir=(e,r,t)=>typeof e=="string"||typeof r=="string"?!0:t.stringify===!0,Br=(e,r,t)=>{if(r>0){let n=e[0]==="-"?"-":"";n&&(e=e.slice(1)),e=n+e.padStart(n?r-1:r,"0")}return t===!1?String(e):e},gt=(e,r)=>{let t=e[0]==="-"?"-":"";for(t&&(e=e.slice(1),r--);e.length{e.negatives.sort((a,c)=>ac?1:0),e.positives.sort((a,c)=>ac?1:0);let t=r.capture?"":"?:",n="",s="",i;return e.positives.length&&(n=e.positives.join("|")),e.negatives.length&&(s=`-(${t}${e.negatives.join("|")})`),n&&s?i=`${n}|${s}`:i=n||s,r.wrap?`(${t}${i})`:i},mt=(e,r,t,n)=>{if(t)return At(e,r,{wrap:!1,...n});let s=String.fromCharCode(e);if(e===r)return s;let i=String.fromCharCode(r);return`[${s}-${i}]`},Rt=(e,r,t)=>{if(Array.isArray(e)){let n=t.wrap===!0,s=t.capture?"":"?:";return n?`(${s}${e.join("|")})`:e.join("|")}return At(e,r,t)},yt=(...e)=>new RangeError("Invalid range arguments: "+Or.inspect(...e)),_t=(e,r,t)=>{if(t.strictRanges===!0)throw yt([e,r]);return[]},Mr=(e,r)=>{if(r.strictRanges===!0)throw new TypeError(`Expected step "${e}" to be a number`);return[]},Dr=(e,r,t=1,n={})=>{let s=Number(e),i=Number(r);if(!Number.isInteger(s)||!Number.isInteger(i)){if(n.strictRanges===!0)throw yt([e,r]);return[]}s===0&&(s=0),i===0&&(i=0);let a=s>i,c=String(e),p=String(r),m=String(t);t=Math.max(Math.abs(t),1);let h=De(c)||De(p)||De(m),R=h?Math.max(c.length,p.length,m.length):0,f=h===!1&&Ir(e,r,n)===!1,$=n.transform||Nr(f);if(n.toRegex&&t===1)return mt(gt(e,R),gt(r,R),!0,n);let _={negatives:[],positives:[]},y=T=>_[T<0?"negatives":"positives"].push(Math.abs(T)),E=[],S=0;for(;a?s>=i:s<=i;)n.toRegex===!0&&t>1?y(s):E.push(Br($(s,S),R,f)),s=a?s-t:s+t,S++;return n.toRegex===!0?t>1?Pr(_,n):Rt(E,null,{wrap:!1,...n}):E},Ur=(e,r,t=1,n={})=>{if(!Ae(e)&&e.length>1||!Ae(r)&&r.length>1)return _t(e,r,n);let s=n.transform||(f=>String.fromCharCode(f)),i=`${e}`.charCodeAt(0),a=`${r}`.charCodeAt(0),c=i>a,p=Math.min(i,a),m=Math.max(i,a);if(n.toRegex&&t===1)return mt(p,m,!1,n);let h=[],R=0;for(;c?i>=a:i<=a;)h.push(s(i,R)),i=c?i-t:i+t,R++;return n.toRegex===!0?Rt(h,null,{wrap:!1,options:n}):h},$e=(e,r,t,n={})=>{if(r==null&&Me(e))return[e];if(!Me(e)||!Me(r))return _t(e,r,n);if(typeof t=="function")return $e(e,r,1,{transform:t});if(dt(t))return $e(e,r,0,t);let s={...n};return s.capture===!0&&(s.wrap=!0),t=t||s.step||1,Ae(t)?Ae(e)&&Ae(r)?Dr(e,r,t,s):Ur(e,r,Math.max(Math.abs(t),1),s):t!=null&&!dt(t)?Mr(t,s):$e(e,r,1,t)};Et.exports=$e});var Ct=q((ts,xt)=>{"use strict";var Gr=Ue(),bt=ve(),qr=(e,r={})=>{let t=(n,s={})=>{let i=bt.isInvalidBrace(s),a=n.invalid===!0&&r.escapeInvalid===!0,c=i===!0||a===!0,p=r.escapeInvalid===!0?"\\":"",m="";if(n.isOpen===!0||n.isClose===!0)return p+n.value;if(n.type==="open")return c?p+n.value:"(";if(n.type==="close")return c?p+n.value:")";if(n.type==="comma")return n.prev.type==="comma"?"":c?n.value:"|";if(n.value)return n.value;if(n.nodes&&n.ranges>0){let h=bt.reduce(n.nodes),R=Gr(...h,{...r,wrap:!1,toRegex:!0});if(R.length!==0)return h.length>1&&R.length>1?`(${R})`:R}if(n.nodes)for(let h of n.nodes)m+=t(h,n);return m};return t(e)};xt.exports=qr});var vt=q((rs,St)=>{"use strict";var Kr=Ue(),wt=He(),he=ve(),fe=(e="",r="",t=!1)=>{let n=[];if(e=[].concat(e),r=[].concat(r),!r.length)return e;if(!e.length)return t?he.flatten(r).map(s=>`{${s}}`):r;for(let s of e)if(Array.isArray(s))for(let i of s)n.push(fe(i,r,t));else for(let i of r)t===!0&&typeof i=="string"&&(i=`{${i}}`),n.push(Array.isArray(i)?fe(s,i,t):s+i);return he.flatten(n)},Wr=(e,r={})=>{let t=r.rangeLimit===void 0?1e3:r.rangeLimit,n=(s,i={})=>{s.queue=[];let a=i,c=i.queue;for(;a.type!=="brace"&&a.type!=="root"&&a.parent;)a=a.parent,c=a.queue;if(s.invalid||s.dollar){c.push(fe(c.pop(),wt(s,r)));return}if(s.type==="brace"&&s.invalid!==!0&&s.nodes.length===2){c.push(fe(c.pop(),["{}"]));return}if(s.nodes&&s.ranges>0){let R=he.reduce(s.nodes);if(he.exceedsLimit(...R,r.step,t))throw new RangeError("expanded array length exceeds range limit. Use options.rangeLimit to increase or disable the limit.");let f=Kr(...R,r);f.length===0&&(f=wt(s,r)),c.push(fe(c.pop(),f)),s.nodes=[];return}let p=he.encloseBrace(s),m=s.queue,h=s;for(;h.type!=="brace"&&h.type!=="root"&&h.parent;)h=h.parent,m=h.queue;for(let R=0;R{"use strict";Ht.exports={MAX_LENGTH:1024*64,CHAR_0:"0",CHAR_9:"9",CHAR_UPPERCASE_A:"A",CHAR_LOWERCASE_A:"a",CHAR_UPPERCASE_Z:"Z",CHAR_LOWERCASE_Z:"z",CHAR_LEFT_PARENTHESES:"(",CHAR_RIGHT_PARENTHESES:")",CHAR_ASTERISK:"*",CHAR_AMPERSAND:"&",CHAR_AT:"@",CHAR_BACKSLASH:"\\",CHAR_BACKTICK:"`",CHAR_CARRIAGE_RETURN:"\r",CHAR_CIRCUMFLEX_ACCENT:"^",CHAR_COLON:":",CHAR_COMMA:",",CHAR_DOLLAR:"$",CHAR_DOT:".",CHAR_DOUBLE_QUOTE:'"',CHAR_EQUAL:"=",CHAR_EXCLAMATION_MARK:"!",CHAR_FORM_FEED:"\f",CHAR_FORWARD_SLASH:"/",CHAR_HASH:"#",CHAR_HYPHEN_MINUS:"-",CHAR_LEFT_ANGLE_BRACKET:"<",CHAR_LEFT_CURLY_BRACE:"{",CHAR_LEFT_SQUARE_BRACKET:"[",CHAR_LINE_FEED:` +`,CHAR_NO_BREAK_SPACE:"\xA0",CHAR_PERCENT:"%",CHAR_PLUS:"+",CHAR_QUESTION_MARK:"?",CHAR_RIGHT_ANGLE_BRACKET:">",CHAR_RIGHT_CURLY_BRACE:"}",CHAR_RIGHT_SQUARE_BRACKET:"]",CHAR_SEMICOLON:";",CHAR_SINGLE_QUOTE:"'",CHAR_SPACE:" ",CHAR_TAB:" ",CHAR_UNDERSCORE:"_",CHAR_VERTICAL_LINE:"|",CHAR_ZERO_WIDTH_NOBREAK_SPACE:"\uFEFF"}});var Nt=q((ss,Ot)=>{"use strict";var jr=He(),{MAX_LENGTH:Tt,CHAR_BACKSLASH:Ge,CHAR_BACKTICK:Fr,CHAR_COMMA:Qr,CHAR_DOT:Xr,CHAR_LEFT_PARENTHESES:Zr,CHAR_RIGHT_PARENTHESES:Yr,CHAR_LEFT_CURLY_BRACE:zr,CHAR_RIGHT_CURLY_BRACE:Vr,CHAR_LEFT_SQUARE_BRACKET:kt,CHAR_RIGHT_SQUARE_BRACKET:Lt,CHAR_DOUBLE_QUOTE:Jr,CHAR_SINGLE_QUOTE:en,CHAR_NO_BREAK_SPACE:tn,CHAR_ZERO_WIDTH_NOBREAK_SPACE:rn}=$t(),nn=(e,r={})=>{if(typeof e!="string")throw new TypeError("Expected a string");let t=r||{},n=typeof t.maxLength=="number"?Math.min(Tt,t.maxLength):Tt;if(e.length>n)throw new SyntaxError(`Input length (${e.length}), exceeds max characters (${n})`);let s={type:"root",input:e,nodes:[]},i=[s],a=s,c=s,p=0,m=e.length,h=0,R=0,f,$={},_=()=>e[h++],y=E=>{if(E.type==="text"&&c.type==="dot"&&(c.type="text"),c&&c.type==="text"&&E.type==="text"){c.value+=E.value;return}return a.nodes.push(E),E.parent=a,E.prev=c,c=E,E};for(y({type:"bos"});h0){if(a.ranges>0){a.ranges=0;let E=a.nodes.shift();a.nodes=[E,{type:"text",value:jr(a)}]}y({type:"comma",value:f}),a.commas++;continue}if(f===Xr&&R>0&&a.commas===0){let E=a.nodes;if(R===0||E.length===0){y({type:"text",value:f});continue}if(c.type==="dot"){if(a.range=[],c.value+=f,c.type="range",a.nodes.length!==3&&a.nodes.length!==5){a.invalid=!0,a.ranges=0,c.type="text";continue}a.ranges++,a.args=[];continue}if(c.type==="range"){E.pop();let S=E[E.length-1];S.value+=c.value+f,c=S,a.ranges--;continue}y({type:"dot",value:f});continue}y({type:"text",value:f})}do if(a=i.pop(),a.type!=="root"){a.nodes.forEach(T=>{T.nodes||(T.type==="open"&&(T.isOpen=!0),T.type==="close"&&(T.isClose=!0),T.nodes||(T.type="text"),T.invalid=!0)});let E=i[i.length-1],S=E.nodes.indexOf(a);E.nodes.splice(S,1,...a.nodes)}while(i.length>0);return y({type:"eos"}),s};Ot.exports=nn});var Pt=q((as,Bt)=>{"use strict";var It=He(),sn=Ct(),an=vt(),on=Nt(),Z=(e,r={})=>{let t=[];if(Array.isArray(e))for(let n of e){let s=Z.create(n,r);Array.isArray(s)?t.push(...s):t.push(s)}else t=[].concat(Z.create(e,r));return r&&r.expand===!0&&r.nodupes===!0&&(t=[...new Set(t)]),t};Z.parse=(e,r={})=>on(e,r);Z.stringify=(e,r={})=>It(typeof e=="string"?Z.parse(e,r):e,r);Z.compile=(e,r={})=>(typeof e=="string"&&(e=Z.parse(e,r)),sn(e,r));Z.expand=(e,r={})=>{typeof e=="string"&&(e=Z.parse(e,r));let t=an(e,r);return r.noempty===!0&&(t=t.filter(Boolean)),r.nodupes===!0&&(t=[...new Set(t)]),t};Z.create=(e,r={})=>e===""||e.length<3?[e]:r.expand!==!0?Z.compile(e,r):Z.expand(e,r);Bt.exports=Z});var me=q((is,qt)=>{"use strict";var un=W("path"),se="\\\\/",Mt=`[^${se}]`,ie="\\.",cn="\\+",ln="\\?",Te="\\/",fn="(?=.)",Dt="[^/]",qe=`(?:${Te}|$)`,Ut=`(?:^|${Te})`,Ke=`${ie}{1,2}${qe}`,pn=`(?!${ie})`,hn=`(?!${Ut}${Ke})`,dn=`(?!${ie}{0,1}${qe})`,gn=`(?!${Ke})`,An=`[^.${Te}]`,mn=`${Dt}*?`,Gt={DOT_LITERAL:ie,PLUS_LITERAL:cn,QMARK_LITERAL:ln,SLASH_LITERAL:Te,ONE_CHAR:fn,QMARK:Dt,END_ANCHOR:qe,DOTS_SLASH:Ke,NO_DOT:pn,NO_DOTS:hn,NO_DOT_SLASH:dn,NO_DOTS_SLASH:gn,QMARK_NO_DOT:An,STAR:mn,START_ANCHOR:Ut},Rn={...Gt,SLASH_LITERAL:`[${se}]`,QMARK:Mt,STAR:`${Mt}*?`,DOTS_SLASH:`${ie}{1,2}(?:[${se}]|$)`,NO_DOT:`(?!${ie})`,NO_DOTS:`(?!(?:^|[${se}])${ie}{1,2}(?:[${se}]|$))`,NO_DOT_SLASH:`(?!${ie}{0,1}(?:[${se}]|$))`,NO_DOTS_SLASH:`(?!${ie}{1,2}(?:[${se}]|$))`,QMARK_NO_DOT:`[^.${se}]`,START_ANCHOR:`(?:^|[${se}])`,END_ANCHOR:`(?:[${se}]|$)`},yn={alnum:"a-zA-Z0-9",alpha:"a-zA-Z",ascii:"\\x00-\\x7F",blank:" \\t",cntrl:"\\x00-\\x1F\\x7F",digit:"0-9",graph:"\\x21-\\x7E",lower:"a-z",print:"\\x20-\\x7E ",punct:"\\-!\"#$%&'()\\*+,./:;<=>?@[\\]^_`{|}~",space:" \\t\\r\\n\\v\\f",upper:"A-Z",word:"A-Za-z0-9_",xdigit:"A-Fa-f0-9"};qt.exports={MAX_LENGTH:1024*64,POSIX_REGEX_SOURCE:yn,REGEX_BACKSLASH:/\\(?![*+?^${}(|)[\]])/g,REGEX_NON_SPECIAL_CHARS:/^[^@![\].,$*+?^{}()|\\/]+/,REGEX_SPECIAL_CHARS:/[-*+?.^${}(|)[\]]/,REGEX_SPECIAL_CHARS_BACKREF:/(\\?)((\W)(\3*))/g,REGEX_SPECIAL_CHARS_GLOBAL:/([-*+?.^${}(|)[\]])/g,REGEX_REMOVE_BACKSLASH:/(?:\[.*?[^\\]\]|\\(?=.))/g,REPLACEMENTS:{"***":"*","**/**":"**","**/**/**":"**"},CHAR_0:48,CHAR_9:57,CHAR_UPPERCASE_A:65,CHAR_LOWERCASE_A:97,CHAR_UPPERCASE_Z:90,CHAR_LOWERCASE_Z:122,CHAR_LEFT_PARENTHESES:40,CHAR_RIGHT_PARENTHESES:41,CHAR_ASTERISK:42,CHAR_AMPERSAND:38,CHAR_AT:64,CHAR_BACKWARD_SLASH:92,CHAR_CARRIAGE_RETURN:13,CHAR_CIRCUMFLEX_ACCENT:94,CHAR_COLON:58,CHAR_COMMA:44,CHAR_DOT:46,CHAR_DOUBLE_QUOTE:34,CHAR_EQUAL:61,CHAR_EXCLAMATION_MARK:33,CHAR_FORM_FEED:12,CHAR_FORWARD_SLASH:47,CHAR_GRAVE_ACCENT:96,CHAR_HASH:35,CHAR_HYPHEN_MINUS:45,CHAR_LEFT_ANGLE_BRACKET:60,CHAR_LEFT_CURLY_BRACE:123,CHAR_LEFT_SQUARE_BRACKET:91,CHAR_LINE_FEED:10,CHAR_NO_BREAK_SPACE:160,CHAR_PERCENT:37,CHAR_PLUS:43,CHAR_QUESTION_MARK:63,CHAR_RIGHT_ANGLE_BRACKET:62,CHAR_RIGHT_CURLY_BRACE:125,CHAR_RIGHT_SQUARE_BRACKET:93,CHAR_SEMICOLON:59,CHAR_SINGLE_QUOTE:39,CHAR_SPACE:32,CHAR_TAB:9,CHAR_UNDERSCORE:95,CHAR_VERTICAL_LINE:124,CHAR_ZERO_WIDTH_NOBREAK_SPACE:65279,SEP:un.sep,extglobChars(e){return{"!":{type:"negate",open:"(?:(?!(?:",close:`))${e.STAR})`},"?":{type:"qmark",open:"(?:",close:")?"},"+":{type:"plus",open:"(?:",close:")+"},"*":{type:"star",open:"(?:",close:")*"},"@":{type:"at",open:"(?:",close:")"}}},globChars(e){return e===!0?Rn:Gt}}});var Re=q(Q=>{"use strict";var _n=W("path"),En=process.platform==="win32",{REGEX_BACKSLASH:bn,REGEX_REMOVE_BACKSLASH:xn,REGEX_SPECIAL_CHARS:Cn,REGEX_SPECIAL_CHARS_GLOBAL:wn}=me();Q.isObject=e=>e!==null&&typeof e=="object"&&!Array.isArray(e);Q.hasRegexChars=e=>Cn.test(e);Q.isRegexChar=e=>e.length===1&&Q.hasRegexChars(e);Q.escapeRegex=e=>e.replace(wn,"\\$1");Q.toPosixSlashes=e=>e.replace(bn,"/");Q.removeBackslashes=e=>e.replace(xn,r=>r==="\\"?"":r);Q.supportsLookbehinds=()=>{let e=process.version.slice(1).split(".").map(Number);return e.length===3&&e[0]>=9||e[0]===8&&e[1]>=10};Q.isWindows=e=>e&&typeof e.windows=="boolean"?e.windows:En===!0||_n.sep==="\\";Q.escapeLast=(e,r,t)=>{let n=e.lastIndexOf(r,t);return n===-1?e:e[n-1]==="\\"?Q.escapeLast(e,r,n-1):`${e.slice(0,n)}\\${e.slice(n)}`};Q.removePrefix=(e,r={})=>{let t=e;return t.startsWith("./")&&(t=t.slice(2),r.prefix="./"),t};Q.wrapOutput=(e,r={},t={})=>{let n=t.contains?"":"^",s=t.contains?"":"$",i=`${n}(?:${e})${s}`;return r.negated===!0&&(i=`(?:^(?!${i}).*$)`),i}});var Yt=q((us,Zt)=>{"use strict";var Kt=Re(),{CHAR_ASTERISK:We,CHAR_AT:Sn,CHAR_BACKWARD_SLASH:ye,CHAR_COMMA:vn,CHAR_DOT:je,CHAR_EXCLAMATION_MARK:Fe,CHAR_FORWARD_SLASH:Xt,CHAR_LEFT_CURLY_BRACE:Qe,CHAR_LEFT_PARENTHESES:Xe,CHAR_LEFT_SQUARE_BRACKET:Hn,CHAR_PLUS:$n,CHAR_QUESTION_MARK:Wt,CHAR_RIGHT_CURLY_BRACE:Tn,CHAR_RIGHT_PARENTHESES:jt,CHAR_RIGHT_SQUARE_BRACKET:kn}=me(),Ft=e=>e===Xt||e===ye,Qt=e=>{e.isPrefix!==!0&&(e.depth=e.isGlobstar?1/0:1)},Ln=(e,r)=>{let t=r||{},n=e.length-1,s=t.parts===!0||t.scanToEnd===!0,i=[],a=[],c=[],p=e,m=-1,h=0,R=0,f=!1,$=!1,_=!1,y=!1,E=!1,S=!1,T=!1,L=!1,z=!1,I=!1,re=0,K,g,v={value:"",depth:0,isGlob:!1},k=()=>m>=n,l=()=>p.charCodeAt(m+1),H=()=>(K=g,p.charCodeAt(++m));for(;m0&&(B=p.slice(0,h),p=p.slice(h),R-=h),w&&_===!0&&R>0?(w=p.slice(0,R),o=p.slice(R)):_===!0?(w="",o=p):w=p,w&&w!==""&&w!=="/"&&w!==p&&Ft(w.charCodeAt(w.length-1))&&(w=w.slice(0,-1)),t.unescape===!0&&(o&&(o=Kt.removeBackslashes(o)),w&&T===!0&&(w=Kt.removeBackslashes(w)));let u={prefix:B,input:e,start:h,base:w,glob:o,isBrace:f,isBracket:$,isGlob:_,isExtglob:y,isGlobstar:E,negated:L,negatedExtglob:z};if(t.tokens===!0&&(u.maxDepth=0,Ft(g)||a.push(v),u.tokens=a),t.parts===!0||t.tokens===!0){let P;for(let b=0;b{"use strict";var ke=me(),Y=Re(),{MAX_LENGTH:Le,POSIX_REGEX_SOURCE:On,REGEX_NON_SPECIAL_CHARS:Nn,REGEX_SPECIAL_CHARS_BACKREF:In,REPLACEMENTS:zt}=ke,Bn=(e,r)=>{if(typeof r.expandRange=="function")return r.expandRange(...e,r);e.sort();let t=`[${e.join("-")}]`;try{new RegExp(t)}catch{return e.map(s=>Y.escapeRegex(s)).join("..")}return t},de=(e,r)=>`Missing ${e}: "${r}" - use "\\\\${r}" to match literal characters`,Vt=(e,r)=>{if(typeof e!="string")throw new TypeError("Expected a string");e=zt[e]||e;let t={...r},n=typeof t.maxLength=="number"?Math.min(Le,t.maxLength):Le,s=e.length;if(s>n)throw new SyntaxError(`Input length: ${s}, exceeds maximum allowed length: ${n}`);let i={type:"bos",value:"",output:t.prepend||""},a=[i],c=t.capture?"":"?:",p=Y.isWindows(r),m=ke.globChars(p),h=ke.extglobChars(m),{DOT_LITERAL:R,PLUS_LITERAL:f,SLASH_LITERAL:$,ONE_CHAR:_,DOTS_SLASH:y,NO_DOT:E,NO_DOT_SLASH:S,NO_DOTS_SLASH:T,QMARK:L,QMARK_NO_DOT:z,STAR:I,START_ANCHOR:re}=m,K=A=>`(${c}(?:(?!${re}${A.dot?y:R}).)*?)`,g=t.dot?"":E,v=t.dot?L:z,k=t.bash===!0?K(t):I;t.capture&&(k=`(${k})`),typeof t.noext=="boolean"&&(t.noextglob=t.noext);let l={input:e,index:-1,start:0,dot:t.dot===!0,consumed:"",output:"",prefix:"",backtrack:!1,negated:!1,brackets:0,braces:0,parens:0,quotes:0,globstar:!1,tokens:a};e=Y.removePrefix(e,l),s=e.length;let H=[],w=[],B=[],o=i,u,P=()=>l.index===s-1,b=l.peek=(A=1)=>e[l.index+A],V=l.advance=()=>e[++l.index]||"",J=()=>e.slice(l.index+1),X=(A="",O=0)=>{l.consumed+=A,l.index+=O},Ee=A=>{l.output+=A.output!=null?A.output:A.value,X(A.value)},mr=()=>{let A=1;for(;b()==="!"&&(b(2)!=="("||b(3)==="?");)V(),l.start++,A++;return A%2===0?!1:(l.negated=!0,l.start++,!0)},be=A=>{l[A]++,B.push(A)},oe=A=>{l[A]--,B.pop()},C=A=>{if(o.type==="globstar"){let O=l.braces>0&&(A.type==="comma"||A.type==="brace"),d=A.extglob===!0||H.length&&(A.type==="pipe"||A.type==="paren");A.type!=="slash"&&A.type!=="paren"&&!O&&!d&&(l.output=l.output.slice(0,-o.output.length),o.type="star",o.value="*",o.output=k,l.output+=o.output)}if(H.length&&A.type!=="paren"&&(H[H.length-1].inner+=A.value),(A.value||A.output)&&Ee(A),o&&o.type==="text"&&A.type==="text"){o.value+=A.value,o.output=(o.output||"")+A.value;return}A.prev=o,a.push(A),o=A},xe=(A,O)=>{let d={...h[O],conditions:1,inner:""};d.prev=o,d.parens=l.parens,d.output=l.output;let x=(t.capture?"(":"")+d.open;be("parens"),C({type:A,value:O,output:l.output?"":_}),C({type:"paren",extglob:!0,value:V(),output:x}),H.push(d)},Rr=A=>{let O=A.close+(t.capture?")":""),d;if(A.type==="negate"){let x=k;A.inner&&A.inner.length>1&&A.inner.includes("/")&&(x=K(t)),(x!==k||P()||/^\)+$/.test(J()))&&(O=A.close=`)$))${x}`),A.inner.includes("*")&&(d=J())&&/^\.[^\\/.]+$/.test(d)&&(O=A.close=`)${d})${x})`),A.prev.type==="bos"&&(l.negatedExtglob=!0)}C({type:"paren",extglob:!0,value:u,output:O}),oe("parens")};if(t.fastpaths!==!1&&!/(^[*!]|[/()[\]{}"])/.test(e)){let A=!1,O=e.replace(In,(d,x,M,j,G,Ie)=>j==="\\"?(A=!0,d):j==="?"?x?x+j+(G?L.repeat(G.length):""):Ie===0?v+(G?L.repeat(G.length):""):L.repeat(M.length):j==="."?R.repeat(M.length):j==="*"?x?x+j+(G?k:""):k:x?d:`\\${d}`);return A===!0&&(t.unescape===!0?O=O.replace(/\\/g,""):O=O.replace(/\\+/g,d=>d.length%2===0?"\\\\":d?"\\":"")),O===e&&t.contains===!0?(l.output=e,l):(l.output=Y.wrapOutput(O,l,r),l)}for(;!P();){if(u=V(),u==="\0")continue;if(u==="\\"){let d=b();if(d==="/"&&t.bash!==!0||d==="."||d===";")continue;if(!d){u+="\\",C({type:"text",value:u});continue}let x=/^\\+/.exec(J()),M=0;if(x&&x[0].length>2&&(M=x[0].length,l.index+=M,M%2!==0&&(u+="\\")),t.unescape===!0?u=V():u+=V(),l.brackets===0){C({type:"text",value:u});continue}}if(l.brackets>0&&(u!=="]"||o.value==="["||o.value==="[^")){if(t.posix!==!1&&u===":"){let d=o.value.slice(1);if(d.includes("[")&&(o.posix=!0,d.includes(":"))){let x=o.value.lastIndexOf("["),M=o.value.slice(0,x),j=o.value.slice(x+2),G=On[j];if(G){o.value=M+G,l.backtrack=!0,V(),!i.output&&a.indexOf(o)===1&&(i.output=_);continue}}}(u==="["&&b()!==":"||u==="-"&&b()==="]")&&(u=`\\${u}`),u==="]"&&(o.value==="["||o.value==="[^")&&(u=`\\${u}`),t.posix===!0&&u==="!"&&o.value==="["&&(u="^"),o.value+=u,Ee({value:u});continue}if(l.quotes===1&&u!=='"'){u=Y.escapeRegex(u),o.value+=u,Ee({value:u});continue}if(u==='"'){l.quotes=l.quotes===1?0:1,t.keepQuotes===!0&&C({type:"text",value:u});continue}if(u==="("){be("parens"),C({type:"paren",value:u});continue}if(u===")"){if(l.parens===0&&t.strictBrackets===!0)throw new SyntaxError(de("opening","("));let d=H[H.length-1];if(d&&l.parens===d.parens+1){Rr(H.pop());continue}C({type:"paren",value:u,output:l.parens?")":"\\)"}),oe("parens");continue}if(u==="["){if(t.nobracket===!0||!J().includes("]")){if(t.nobracket!==!0&&t.strictBrackets===!0)throw new SyntaxError(de("closing","]"));u=`\\${u}`}else be("brackets");C({type:"bracket",value:u});continue}if(u==="]"){if(t.nobracket===!0||o&&o.type==="bracket"&&o.value.length===1){C({type:"text",value:u,output:`\\${u}`});continue}if(l.brackets===0){if(t.strictBrackets===!0)throw new SyntaxError(de("opening","["));C({type:"text",value:u,output:`\\${u}`});continue}oe("brackets");let d=o.value.slice(1);if(o.posix!==!0&&d[0]==="^"&&!d.includes("/")&&(u=`/${u}`),o.value+=u,Ee({value:u}),t.literalBrackets===!1||Y.hasRegexChars(d))continue;let x=Y.escapeRegex(o.value);if(l.output=l.output.slice(0,-o.value.length),t.literalBrackets===!0){l.output+=x,o.value=x;continue}o.value=`(${c}${x}|${o.value})`,l.output+=o.value;continue}if(u==="{"&&t.nobrace!==!0){be("braces");let d={type:"brace",value:u,output:"(",outputIndex:l.output.length,tokensIndex:l.tokens.length};w.push(d),C(d);continue}if(u==="}"){let d=w[w.length-1];if(t.nobrace===!0||!d){C({type:"text",value:u,output:u});continue}let x=")";if(d.dots===!0){let M=a.slice(),j=[];for(let G=M.length-1;G>=0&&(a.pop(),M[G].type!=="brace");G--)M[G].type!=="dots"&&j.unshift(M[G].value);x=Bn(j,t),l.backtrack=!0}if(d.comma!==!0&&d.dots!==!0){let M=l.output.slice(0,d.outputIndex),j=l.tokens.slice(d.tokensIndex);d.value=d.output="\\{",u=x="\\}",l.output=M;for(let G of j)l.output+=G.output||G.value}C({type:"brace",value:u,output:x}),oe("braces"),w.pop();continue}if(u==="|"){H.length>0&&H[H.length-1].conditions++,C({type:"text",value:u});continue}if(u===","){let d=u,x=w[w.length-1];x&&B[B.length-1]==="braces"&&(x.comma=!0,d="|"),C({type:"comma",value:u,output:d});continue}if(u==="/"){if(o.type==="dot"&&l.index===l.start+1){l.start=l.index+1,l.consumed="",l.output="",a.pop(),o=i;continue}C({type:"slash",value:u,output:$});continue}if(u==="."){if(l.braces>0&&o.type==="dot"){o.value==="."&&(o.output=R);let d=w[w.length-1];o.type="dots",o.output+=u,o.value+=u,d.dots=!0;continue}if(l.braces+l.parens===0&&o.type!=="bos"&&o.type!=="slash"){C({type:"text",value:u,output:R});continue}C({type:"dot",value:u,output:R});continue}if(u==="?"){if(!(o&&o.value==="(")&&t.noextglob!==!0&&b()==="("&&b(2)!=="?"){xe("qmark",u);continue}if(o&&o.type==="paren"){let x=b(),M=u;if(x==="<"&&!Y.supportsLookbehinds())throw new Error("Node.js v10 or higher is required for regex lookbehinds");(o.value==="("&&!/[!=<:]/.test(x)||x==="<"&&!/<([!=]|\w+>)/.test(J()))&&(M=`\\${u}`),C({type:"text",value:u,output:M});continue}if(t.dot!==!0&&(o.type==="slash"||o.type==="bos")){C({type:"qmark",value:u,output:z});continue}C({type:"qmark",value:u,output:L});continue}if(u==="!"){if(t.noextglob!==!0&&b()==="("&&(b(2)!=="?"||!/[!=<:]/.test(b(3)))){xe("negate",u);continue}if(t.nonegate!==!0&&l.index===0){mr();continue}}if(u==="+"){if(t.noextglob!==!0&&b()==="("&&b(2)!=="?"){xe("plus",u);continue}if(o&&o.value==="("||t.regex===!1){C({type:"plus",value:u,output:f});continue}if(o&&(o.type==="bracket"||o.type==="paren"||o.type==="brace")||l.parens>0){C({type:"plus",value:u});continue}C({type:"plus",value:f});continue}if(u==="@"){if(t.noextglob!==!0&&b()==="("&&b(2)!=="?"){C({type:"at",extglob:!0,value:u,output:""});continue}C({type:"text",value:u});continue}if(u!=="*"){(u==="$"||u==="^")&&(u=`\\${u}`);let d=Nn.exec(J());d&&(u+=d[0],l.index+=d[0].length),C({type:"text",value:u});continue}if(o&&(o.type==="globstar"||o.star===!0)){o.type="star",o.star=!0,o.value+=u,o.output=k,l.backtrack=!0,l.globstar=!0,X(u);continue}let A=J();if(t.noextglob!==!0&&/^\([^?]/.test(A)){xe("star",u);continue}if(o.type==="star"){if(t.noglobstar===!0){X(u);continue}let d=o.prev,x=d.prev,M=d.type==="slash"||d.type==="bos",j=x&&(x.type==="star"||x.type==="globstar");if(t.bash===!0&&(!M||A[0]&&A[0]!=="/")){C({type:"star",value:u,output:""});continue}let G=l.braces>0&&(d.type==="comma"||d.type==="brace"),Ie=H.length&&(d.type==="pipe"||d.type==="paren");if(!M&&d.type!=="paren"&&!G&&!Ie){C({type:"star",value:u,output:""});continue}for(;A.slice(0,3)==="/**";){let Ce=e[l.index+4];if(Ce&&Ce!=="/")break;A=A.slice(3),X("/**",3)}if(d.type==="bos"&&P()){o.type="globstar",o.value+=u,o.output=K(t),l.output=o.output,l.globstar=!0,X(u);continue}if(d.type==="slash"&&d.prev.type!=="bos"&&!j&&P()){l.output=l.output.slice(0,-(d.output+o.output).length),d.output=`(?:${d.output}`,o.type="globstar",o.output=K(t)+(t.strictSlashes?")":"|$)"),o.value+=u,l.globstar=!0,l.output+=d.output+o.output,X(u);continue}if(d.type==="slash"&&d.prev.type!=="bos"&&A[0]==="/"){let Ce=A[1]!==void 0?"|$":"";l.output=l.output.slice(0,-(d.output+o.output).length),d.output=`(?:${d.output}`,o.type="globstar",o.output=`${K(t)}${$}|${$}${Ce})`,o.value+=u,l.output+=d.output+o.output,l.globstar=!0,X(u+V()),C({type:"slash",value:"/",output:""});continue}if(d.type==="bos"&&A[0]==="/"){o.type="globstar",o.value+=u,o.output=`(?:^|${$}|${K(t)}${$})`,l.output=o.output,l.globstar=!0,X(u+V()),C({type:"slash",value:"/",output:""});continue}l.output=l.output.slice(0,-o.output.length),o.type="globstar",o.output=K(t),o.value+=u,l.output+=o.output,l.globstar=!0,X(u);continue}let O={type:"star",value:u,output:k};if(t.bash===!0){O.output=".*?",(o.type==="bos"||o.type==="slash")&&(O.output=g+O.output),C(O);continue}if(o&&(o.type==="bracket"||o.type==="paren")&&t.regex===!0){O.output=u,C(O);continue}(l.index===l.start||o.type==="slash"||o.type==="dot")&&(o.type==="dot"?(l.output+=S,o.output+=S):t.dot===!0?(l.output+=T,o.output+=T):(l.output+=g,o.output+=g),b()!=="*"&&(l.output+=_,o.output+=_)),C(O)}for(;l.brackets>0;){if(t.strictBrackets===!0)throw new SyntaxError(de("closing","]"));l.output=Y.escapeLast(l.output,"["),oe("brackets")}for(;l.parens>0;){if(t.strictBrackets===!0)throw new SyntaxError(de("closing",")"));l.output=Y.escapeLast(l.output,"("),oe("parens")}for(;l.braces>0;){if(t.strictBrackets===!0)throw new SyntaxError(de("closing","}"));l.output=Y.escapeLast(l.output,"{"),oe("braces")}if(t.strictSlashes!==!0&&(o.type==="star"||o.type==="bracket")&&C({type:"maybe_slash",value:"",output:`${$}?`}),l.backtrack===!0){l.output="";for(let A of l.tokens)l.output+=A.output!=null?A.output:A.value,A.suffix&&(l.output+=A.suffix)}return l};Vt.fastpaths=(e,r)=>{let t={...r},n=typeof t.maxLength=="number"?Math.min(Le,t.maxLength):Le,s=e.length;if(s>n)throw new SyntaxError(`Input length: ${s}, exceeds maximum allowed length: ${n}`);e=zt[e]||e;let i=Y.isWindows(r),{DOT_LITERAL:a,SLASH_LITERAL:c,ONE_CHAR:p,DOTS_SLASH:m,NO_DOT:h,NO_DOTS:R,NO_DOTS_SLASH:f,STAR:$,START_ANCHOR:_}=ke.globChars(i),y=t.dot?R:h,E=t.dot?f:h,S=t.capture?"":"?:",T={negated:!1,prefix:""},L=t.bash===!0?".*?":$;t.capture&&(L=`(${L})`);let z=g=>g.noglobstar===!0?L:`(${S}(?:(?!${_}${g.dot?m:a}).)*?)`,I=g=>{switch(g){case"*":return`${y}${p}${L}`;case".*":return`${a}${p}${L}`;case"*.*":return`${y}${L}${a}${p}${L}`;case"*/*":return`${y}${L}${c}${p}${E}${L}`;case"**":return y+z(t);case"**/*":return`(?:${y}${z(t)}${c})?${E}${p}${L}`;case"**/*.*":return`(?:${y}${z(t)}${c})?${E}${L}${a}${p}${L}`;case"**/.*":return`(?:${y}${z(t)}${c})?${a}${p}${L}`;default:{let v=/^(.*?)\.(\w+)$/.exec(g);if(!v)return;let k=I(v[1]);return k?k+a+v[2]:void 0}}},re=Y.removePrefix(e,T),K=I(re);return K&&t.strictSlashes!==!0&&(K+=`${c}?`),K};Jt.exports=Vt});var rr=q((ls,tr)=>{"use strict";var Pn=W("path"),Mn=Yt(),Ze=er(),Ye=Re(),Dn=me(),Un=e=>e&&typeof e=="object"&&!Array.isArray(e),D=(e,r,t=!1)=>{if(Array.isArray(e)){let h=e.map(f=>D(f,r,t));return f=>{for(let $ of h){let _=$(f);if(_)return _}return!1}}let n=Un(e)&&e.tokens&&e.input;if(e===""||typeof e!="string"&&!n)throw new TypeError("Expected pattern to be a non-empty string");let s=r||{},i=Ye.isWindows(r),a=n?D.compileRe(e,r):D.makeRe(e,r,!1,!0),c=a.state;delete a.state;let p=()=>!1;if(s.ignore){let h={...r,ignore:null,onMatch:null,onResult:null};p=D(s.ignore,h,t)}let m=(h,R=!1)=>{let{isMatch:f,match:$,output:_}=D.test(h,a,r,{glob:e,posix:i}),y={glob:e,state:c,regex:a,posix:i,input:h,output:_,match:$,isMatch:f};return typeof s.onResult=="function"&&s.onResult(y),f===!1?(y.isMatch=!1,R?y:!1):p(h)?(typeof s.onIgnore=="function"&&s.onIgnore(y),y.isMatch=!1,R?y:!1):(typeof s.onMatch=="function"&&s.onMatch(y),R?y:!0)};return t&&(m.state=c),m};D.test=(e,r,t,{glob:n,posix:s}={})=>{if(typeof e!="string")throw new TypeError("Expected input to be a string");if(e==="")return{isMatch:!1,output:""};let i=t||{},a=i.format||(s?Ye.toPosixSlashes:null),c=e===n,p=c&&a?a(e):e;return c===!1&&(p=a?a(e):e,c=p===n),(c===!1||i.capture===!0)&&(i.matchBase===!0||i.basename===!0?c=D.matchBase(e,r,t,s):c=r.exec(p)),{isMatch:Boolean(c),match:c,output:p}};D.matchBase=(e,r,t,n=Ye.isWindows(t))=>(r instanceof RegExp?r:D.makeRe(r,t)).test(Pn.basename(e));D.isMatch=(e,r,t)=>D(r,t)(e);D.parse=(e,r)=>Array.isArray(e)?e.map(t=>D.parse(t,r)):Ze(e,{...r,fastpaths:!1});D.scan=(e,r)=>Mn(e,r);D.compileRe=(e,r,t=!1,n=!1)=>{if(t===!0)return e.output;let s=r||{},i=s.contains?"":"^",a=s.contains?"":"$",c=`${i}(?:${e.output})${a}`;e&&e.negated===!0&&(c=`^(?!${c}).*$`);let p=D.toRegex(c,r);return n===!0&&(p.state=e),p};D.makeRe=(e,r={},t=!1,n=!1)=>{if(!e||typeof e!="string")throw new TypeError("Expected a non-empty string");let s={negated:!1,fastpaths:!0};return r.fastpaths!==!1&&(e[0]==="."||e[0]==="*")&&(s.output=Ze.fastpaths(e,r)),s.output||(s=Ze(e,r)),D.compileRe(s,r,t,n)};D.toRegex=(e,r)=>{try{let t=r||{};return new RegExp(e,t.flags||(t.nocase?"i":""))}catch(t){if(r&&r.debug===!0)throw t;return/$^/}};D.constants=Dn;tr.exports=D});var sr=q((fs,nr)=>{"use strict";nr.exports=rr()});var cr=q((ps,ur)=>{"use strict";var ir=W("util"),or=Pt(),ae=sr(),ze=Re(),ar=e=>e===""||e==="./",N=(e,r,t)=>{r=[].concat(r),e=[].concat(e);let n=new Set,s=new Set,i=new Set,a=0,c=h=>{i.add(h.output),t&&t.onResult&&t.onResult(h)};for(let h=0;h!n.has(h));if(t&&m.length===0){if(t.failglob===!0)throw new Error(`No matches found for "${r.join(", ")}"`);if(t.nonull===!0||t.nullglob===!0)return t.unescape?r.map(h=>h.replace(/\\/g,"")):r}return m};N.match=N;N.matcher=(e,r)=>ae(e,r);N.isMatch=(e,r,t)=>ae(r,t)(e);N.any=N.isMatch;N.not=(e,r,t={})=>{r=[].concat(r).map(String);let n=new Set,s=[],a=N(e,r,{...t,onResult:c=>{t.onResult&&t.onResult(c),s.push(c.output)}});for(let c of s)a.includes(c)||n.add(c);return[...n]};N.contains=(e,r,t)=>{if(typeof e!="string")throw new TypeError(`Expected a string: "${ir.inspect(e)}"`);if(Array.isArray(r))return r.some(n=>N.contains(e,n,t));if(typeof r=="string"){if(ar(e)||ar(r))return!1;if(e.includes(r)||e.startsWith("./")&&e.slice(2).includes(r))return!0}return N.isMatch(e,r,{...t,contains:!0})};N.matchKeys=(e,r,t)=>{if(!ze.isObject(e))throw new TypeError("Expected the first argument to be an object");let n=N(Object.keys(e),r,t),s={};for(let i of n)s[i]=e[i];return s};N.some=(e,r,t)=>{let n=[].concat(e);for(let s of[].concat(r)){let i=ae(String(s),t);if(n.some(a=>i(a)))return!0}return!1};N.every=(e,r,t)=>{let n=[].concat(e);for(let s of[].concat(r)){let i=ae(String(s),t);if(!n.every(a=>i(a)))return!1}return!0};N.all=(e,r,t)=>{if(typeof e!="string")throw new TypeError(`Expected a string: "${ir.inspect(e)}"`);return[].concat(r).every(n=>ae(n,t)(e))};N.capture=(e,r,t)=>{let n=ze.isWindows(t),i=ae.makeRe(String(e),{...t,capture:!0}).exec(n?ze.toPosixSlashes(r):r);if(i)return i.slice(1).map(a=>a===void 0?"":a)};N.makeRe=(...e)=>ae.makeRe(...e);N.scan=(...e)=>ae.scan(...e);N.parse=(e,r)=>{let t=[];for(let n of[].concat(e||[]))for(let s of or(String(n),r))t.push(ae.parse(s,r));return t};N.braces=(e,r)=>{if(typeof e!="string")throw new TypeError("Expected a string");return r&&r.nobrace===!0||!/\{.*\}/.test(e)?[e]:or(e,r)};N.braceExpand=(e,r)=>{if(typeof e!="string")throw new TypeError("Expected a string");return N.braces(e,{...r,expand:!0})};ur.exports=N});var fr=q((hs,lr)=>{"use strict";lr.exports=(e,...r)=>new Promise(t=>{t(e(...r))})});var hr=q((ds,Ve)=>{"use strict";var Gn=fr(),pr=e=>{if(e<1)throw new TypeError("Expected `concurrency` to be a number from 1 and up");let r=[],t=0,n=()=>{t--,r.length>0&&r.shift()()},s=(c,p,...m)=>{t++;let h=Gn(c,...m);p(h),h.then(n,n)},i=(c,p,...m)=>{tnew Promise(m=>i(c,m,...p));return Object.defineProperties(a,{activeCount:{get:()=>t},pendingCount:{get:()=>r.length}}),a};Ve.exports=pr;Ve.exports.default=pr});var jn={};Cr(jn,{default:()=>Wn});var Se=W("@yarnpkg/cli"),ne=W("@yarnpkg/core"),et=W("@yarnpkg/core"),ue=W("clipanion"),ce=class extends Se.BaseCommand{constructor(){super(...arguments);this.json=ue.Option.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.production=ue.Option.Boolean("--production",!1,{description:"Only install regular dependencies by omitting dev dependencies"});this.all=ue.Option.Boolean("-A,--all",!1,{description:"Install the entire project"});this.workspaces=ue.Option.Rest()}async execute(){let t=await ne.Configuration.find(this.context.cwd,this.context.plugins),{project:n,workspace:s}=await ne.Project.find(t,this.context.cwd),i=await ne.Cache.find(t);await n.restoreInstallState({restoreResolutions:!1});let a;if(this.all)a=new Set(n.workspaces);else if(this.workspaces.length===0){if(!s)throw new Se.WorkspaceRequiredError(n.cwd,this.context.cwd);a=new Set([s])}else a=new Set(this.workspaces.map(p=>n.getWorkspaceByIdent(et.structUtils.parseIdent(p))));for(let p of a)for(let m of this.production?["dependencies"]:ne.Manifest.hardDependencies)for(let h of p.manifest.getForScope(m).values()){let R=n.tryWorkspaceByDescriptor(h);R!==null&&a.add(R)}for(let p of n.workspaces)a.has(p)?this.production&&p.manifest.devDependencies.clear():(p.manifest.installConfig=p.manifest.installConfig||{},p.manifest.installConfig.selfReferences=!1,p.manifest.dependencies.clear(),p.manifest.devDependencies.clear(),p.manifest.peerDependencies.clear(),p.manifest.scripts.clear());return(await ne.StreamReport.start({configuration:t,json:this.json,stdout:this.context.stdout,includeLogs:!0},async p=>{await n.install({cache:i,report:p,persistProject:!1})})).exitCode()}};ce.paths=[["workspaces","focus"]],ce.usage=ue.Command.Usage({category:"Workspace-related commands",description:"install a single workspace and its dependencies",details:"\n This command will run an install as if the specified workspaces (and all other workspaces they depend on) were the only ones in the project. If no workspaces are explicitly listed, the active one will be assumed.\n\n Note that this command is only very moderately useful when using zero-installs, since the cache will contain all the packages anyway - meaning that the only difference between a full install and a focused install would just be a few extra lines in the `.pnp.cjs` file, at the cost of introducing an extra complexity.\n\n If the `-A,--all` flag is set, the entire project will be installed. Combine with `--production` to replicate the old `yarn install --production`.\n "});var Ne=W("@yarnpkg/cli"),ge=W("@yarnpkg/core"),_e=W("@yarnpkg/core"),F=W("@yarnpkg/core"),gr=W("@yarnpkg/plugin-git"),U=W("clipanion"),Oe=Be(cr()),Ar=Be(hr()),te=Be(W("typanion")),pe=class extends Ne.BaseCommand{constructor(){super(...arguments);this.recursive=U.Option.Boolean("-R,--recursive",!1,{description:"Find packages via dependencies/devDependencies instead of using the workspaces field"});this.from=U.Option.Array("--from",[],{description:"An array of glob pattern idents from which to base any recursion"});this.all=U.Option.Boolean("-A,--all",!1,{description:"Run the command on all workspaces of a project"});this.verbose=U.Option.Boolean("-v,--verbose",!1,{description:"Prefix each output line with the name of the originating workspace"});this.parallel=U.Option.Boolean("-p,--parallel",!1,{description:"Run the commands in parallel"});this.interlaced=U.Option.Boolean("-i,--interlaced",!1,{description:"Print the output of commands in real-time instead of buffering it"});this.jobs=U.Option.String("-j,--jobs",{description:"The maximum number of parallel tasks that the execution will be limited to; or `unlimited`",validator:te.isOneOf([te.isEnum(["unlimited"]),te.applyCascade(te.isNumber(),[te.isInteger(),te.isAtLeast(1)])])});this.topological=U.Option.Boolean("-t,--topological",!1,{description:"Run the command after all workspaces it depends on (regular) have finished"});this.topologicalDev=U.Option.Boolean("--topological-dev",!1,{description:"Run the command after all workspaces it depends on (regular + dev) have finished"});this.include=U.Option.Array("--include",[],{description:"An array of glob pattern idents; only matching workspaces will be traversed"});this.exclude=U.Option.Array("--exclude",[],{description:"An array of glob pattern idents; matching workspaces won't be traversed"});this.publicOnly=U.Option.Boolean("--no-private",{description:"Avoid running the command on private workspaces"});this.since=U.Option.String("--since",{description:"Only include workspaces that have been changed since the specified ref.",tolerateBoolean:!0});this.commandName=U.Option.String();this.args=U.Option.Proxy()}async execute(){let t=await ge.Configuration.find(this.context.cwd,this.context.plugins),{project:n,workspace:s}=await ge.Project.find(t,this.context.cwd);if(!this.all&&!s)throw new Ne.WorkspaceRequiredError(n.cwd,this.context.cwd);await n.restoreInstallState();let i=this.cli.process([this.commandName,...this.args]),a=i.path.length===1&&i.path[0]==="run"&&typeof i.scriptName<"u"?i.scriptName:null;if(i.path.length===0)throw new U.UsageError("Invalid subcommand name for iteration - use the 'run' keyword if you wish to execute a script");let c=this.all?n.topLevelWorkspace:s,p=this.since?Array.from(await gr.gitUtils.fetchChangedWorkspaces({ref:this.since,project:n})):[c,...this.from.length>0?c.getRecursiveWorkspaceChildren():[]],m=g=>Oe.default.isMatch(F.structUtils.stringifyIdent(g.locator),this.from),h=this.from.length>0?p.filter(m):p,R=new Set([...h,...h.map(g=>[...this.recursive?this.since?g.getRecursiveWorkspaceDependents():g.getRecursiveWorkspaceDependencies():g.getRecursiveWorkspaceChildren()]).flat()]),f=[],$=!1;if(a!=null&&a.includes(":")){for(let g of n.workspaces)if(g.manifest.scripts.has(a)&&($=!$,$===!1))break}for(let g of R)a&&!g.manifest.scripts.has(a)&&!$&&!(await ge.scriptUtils.getWorkspaceAccessibleBinaries(g)).has(a)||a===process.env.npm_lifecycle_event&&g.cwd===s.cwd||this.include.length>0&&!Oe.default.isMatch(F.structUtils.stringifyIdent(g.locator),this.include)||this.exclude.length>0&&Oe.default.isMatch(F.structUtils.stringifyIdent(g.locator),this.exclude)||this.publicOnly&&g.manifest.private===!0||f.push(g);let _=this.parallel?this.jobs==="unlimited"?1/0:Number(this.jobs)||Math.ceil(F.nodeUtils.availableParallelism()/2):1,y=_===1?!1:this.parallel,E=y?this.interlaced:!0,S=(0,Ar.default)(_),T=new Map,L=new Set,z=0,I=null,re=!1,K=await _e.StreamReport.start({configuration:t,stdout:this.context.stdout,includePrefix:!1},async g=>{let v=async(k,{commandIndex:l})=>{if(re)return-1;!y&&this.verbose&&l>1&&g.reportSeparator();let H=qn(k,{configuration:t,verbose:this.verbose,commandIndex:l}),[w,B]=dr(g,{prefix:H,interlaced:E}),[o,u]=dr(g,{prefix:H,interlaced:E});try{this.verbose&&g.reportInfo(null,`${H} Process started`);let P=Date.now(),b=await this.cli.run([this.commandName,...this.args],{cwd:k.cwd,stdout:w,stderr:o})||0;w.end(),o.end(),await B,await u;let V=Date.now();if(this.verbose){let J=t.get("enableTimers")?`, completed in ${F.formatUtils.pretty(t,V-P,F.formatUtils.Type.DURATION)}`:"";g.reportInfo(null,`${H} Process exited (exit code ${b})${J}`)}return b===130&&(re=!0,I=b),b}catch(P){throw w.end(),o.end(),await B,await u,P}};for(let k of f)T.set(k.anchoredLocator.locatorHash,k);for(;T.size>0&&!g.hasErrors();){let k=[];for(let[w,B]of T){if(L.has(B.anchoredDescriptor.descriptorHash))continue;let o=!0;if(this.topological||this.topologicalDev){let u=this.topologicalDev?new Map([...B.manifest.dependencies,...B.manifest.devDependencies]):B.manifest.dependencies;for(let P of u.values()){let b=n.tryWorkspaceByDescriptor(P);if(o=b===null||!T.has(b.anchoredLocator.locatorHash),!o)break}}if(!!o&&(L.add(B.anchoredDescriptor.descriptorHash),k.push(S(async()=>{let u=await v(B,{commandIndex:++z});return T.delete(w),L.delete(B.anchoredDescriptor.descriptorHash),u})),!y))break}if(k.length===0){let w=Array.from(T.values()).map(B=>F.structUtils.prettyLocator(t,B.anchoredLocator)).join(", ");g.reportError(_e.MessageName.CYCLIC_DEPENDENCIES,`Dependency cycle detected (${w})`);return}let H=(await Promise.all(k)).find(w=>w!==0);I===null&&(I=typeof H<"u"?1:I),(this.topological||this.topologicalDev)&&typeof H<"u"&&g.reportError(_e.MessageName.UNNAMED,"The command failed for workspaces that are depended upon by other workspaces; can't satisfy the dependency graph")}});return I!==null?I:K.exitCode()}};pe.paths=[["workspaces","foreach"]],pe.usage=U.Command.Usage({category:"Workspace-related commands",description:"run a command on all workspaces",details:"\n This command will run a given sub-command on current and all its descendant workspaces. Various flags can alter the exact behavior of the command:\n\n - If `-p,--parallel` is set, the commands will be ran in parallel; they'll by default be limited to a number of parallel tasks roughly equal to half your core number, but that can be overridden via `-j,--jobs`, or disabled by setting `-j unlimited`.\n\n - If `-p,--parallel` and `-i,--interlaced` are both set, Yarn will print the lines from the output as it receives them. If `-i,--interlaced` wasn't set, it would instead buffer the output from each process and print the resulting buffers only after their source processes have exited.\n\n - If `-t,--topological` is set, Yarn will only run the command after all workspaces that it depends on through the `dependencies` field have successfully finished executing. If `--topological-dev` is set, both the `dependencies` and `devDependencies` fields will be considered when figuring out the wait points.\n\n - If `-A,--all` is set, Yarn will run the command on all the workspaces of a project. By default yarn runs the command only on current and all its descendant workspaces.\n\n - If `-R,--recursive` is set, Yarn will find workspaces to run the command on by recursively evaluating `dependencies` and `devDependencies` fields, instead of looking at the `workspaces` fields.\n\n - If `--from` is set, Yarn will use the packages matching the 'from' glob as the starting point for any recursive search.\n\n - If `--since` is set, Yarn will only run the command on workspaces that have been modified since the specified ref. By default Yarn will use the refs specified by the `changesetBaseRefs` configuration option.\n\n - The command may apply to only some workspaces through the use of `--include` which acts as a whitelist. The `--exclude` flag will do the opposite and will be a list of packages that mustn't execute the script. Both flags accept glob patterns (if valid Idents and supported by [micromatch](https://github.com/micromatch/micromatch)). Make sure to escape the patterns, to prevent your own shell from trying to expand them.\n\n Adding the `-v,--verbose` flag will cause Yarn to print more information; in particular the name of the workspace that generated the output will be printed at the front of each line.\n\n If the command is `run` and the script being run does not exist the child workspace will be skipped without error.\n ",examples:[["Publish current and all descendant packages","yarn workspaces foreach npm publish --tolerate-republish"],["Run build script on current and all descendant packages","yarn workspaces foreach run build"],["Run build script on current and all descendant packages in parallel, building package dependencies first","yarn workspaces foreach -pt run build"],["Run build script on several packages and all their dependencies, building dependencies first","yarn workspaces foreach -ptR --from '{workspace-a,workspace-b}' run build"]]});function dr(e,{prefix:r,interlaced:t}){let n=e.createStreamReporter(r),s=new F.miscUtils.DefaultStream;s.pipe(n,{end:!1}),s.on("finish",()=>{n.end()});let i=new Promise(c=>{n.on("finish",()=>{c(s.active)})});if(t)return[s,i];let a=new F.miscUtils.BufferStream;return a.pipe(s,{end:!1}),a.on("finish",()=>{s.end()}),[a,i]}function qn(e,{configuration:r,commandIndex:t,verbose:n}){if(!n)return null;let i=`[${F.structUtils.stringifyIdent(e.locator)}]:`,a=["#2E86AB","#A23B72","#F18F01","#C73E1D","#CCE2A3"],c=a[t%a.length];return F.formatUtils.pretty(r,i,c)}var Kn={commands:[ce,pe]},Wn=Kn;return wr(jn);})(); +/*! + * fill-range + * + * Copyright (c) 2014-present, Jon Schlinkert. + * Licensed under the MIT License. + */ +/*! + * is-number + * + * Copyright (c) 2014-present, Jon Schlinkert. + * Released under the MIT License. + */ +/*! + * to-regex-range + * + * Copyright (c) 2015-present, Jon Schlinkert. + * Released under the MIT License. + */ +return plugin; +} +}; diff --git a/circuits/.yarn/releases/yarn-3.4.1.cjs b/circuits/.yarn/releases/yarn-3.4.1.cjs new file mode 100755 index 00000000000..2bdb752d860 --- /dev/null +++ b/circuits/.yarn/releases/yarn-3.4.1.cjs @@ -0,0 +1,873 @@ +#!/usr/bin/env node +/* eslint-disable */ +//prettier-ignore +(()=>{var Mue=Object.create;var Wb=Object.defineProperty;var Kue=Object.getOwnPropertyDescriptor;var Uue=Object.getOwnPropertyNames;var Hue=Object.getPrototypeOf,Gue=Object.prototype.hasOwnProperty;var J=(r=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(r,{get:(e,t)=>(typeof require<"u"?require:e)[t]}):r)(function(r){if(typeof require<"u")return require.apply(this,arguments);throw new Error('Dynamic require of "'+r+'" is not supported')});var Yue=(r,e)=>()=>(r&&(e=r(r=0)),e);var w=(r,e)=>()=>(e||r((e={exports:{}}).exports,e),e.exports),ut=(r,e)=>{for(var t in e)Wb(r,t,{get:e[t],enumerable:!0})},jue=(r,e,t,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of Uue(e))!Gue.call(r,n)&&n!==t&&Wb(r,n,{get:()=>e[n],enumerable:!(i=Kue(e,n))||i.enumerable});return r};var Pe=(r,e,t)=>(t=r!=null?Mue(Hue(r)):{},jue(e||!r||!r.__esModule?Wb(t,"default",{value:r,enumerable:!0}):t,r));var _1=w((O7e,X1)=>{X1.exports=V1;V1.sync=uge;var W1=J("fs");function cge(r,e){var t=e.pathExt!==void 0?e.pathExt:process.env.PATHEXT;if(!t||(t=t.split(";"),t.indexOf("")!==-1))return!0;for(var i=0;i{tK.exports=$1;$1.sync=gge;var Z1=J("fs");function $1(r,e,t){Z1.stat(r,function(i,n){t(i,i?!1:eK(n,e))})}function gge(r,e){return eK(Z1.statSync(r),e)}function eK(r,e){return r.isFile()&&fge(r,e)}function fge(r,e){var t=r.mode,i=r.uid,n=r.gid,s=e.uid!==void 0?e.uid:process.getuid&&process.getuid(),o=e.gid!==void 0?e.gid:process.getgid&&process.getgid(),a=parseInt("100",8),l=parseInt("010",8),c=parseInt("001",8),u=a|l,g=t&c||t&l&&n===o||t&a&&i===s||t&u&&s===0;return g}});var nK=w((U7e,iK)=>{var K7e=J("fs"),_E;process.platform==="win32"||global.TESTING_WINDOWS?_E=_1():_E=rK();iK.exports=uS;uS.sync=hge;function uS(r,e,t){if(typeof e=="function"&&(t=e,e={}),!t){if(typeof Promise!="function")throw new TypeError("callback not provided");return new Promise(function(i,n){uS(r,e||{},function(s,o){s?n(s):i(o)})})}_E(r,e||{},function(i,n){i&&(i.code==="EACCES"||e&&e.ignoreErrors)&&(i=null,n=!1),t(i,n)})}function hge(r,e){try{return _E.sync(r,e||{})}catch(t){if(e&&e.ignoreErrors||t.code==="EACCES")return!1;throw t}}});var uK=w((H7e,cK)=>{var Ig=process.platform==="win32"||process.env.OSTYPE==="cygwin"||process.env.OSTYPE==="msys",sK=J("path"),pge=Ig?";":":",oK=nK(),aK=r=>Object.assign(new Error(`not found: ${r}`),{code:"ENOENT"}),AK=(r,e)=>{let t=e.colon||pge,i=r.match(/\//)||Ig&&r.match(/\\/)?[""]:[...Ig?[process.cwd()]:[],...(e.path||process.env.PATH||"").split(t)],n=Ig?e.pathExt||process.env.PATHEXT||".EXE;.CMD;.BAT;.COM":"",s=Ig?n.split(t):[""];return Ig&&r.indexOf(".")!==-1&&s[0]!==""&&s.unshift(""),{pathEnv:i,pathExt:s,pathExtExe:n}},lK=(r,e,t)=>{typeof e=="function"&&(t=e,e={}),e||(e={});let{pathEnv:i,pathExt:n,pathExtExe:s}=AK(r,e),o=[],a=c=>new Promise((u,g)=>{if(c===i.length)return e.all&&o.length?u(o):g(aK(r));let f=i[c],h=/^".*"$/.test(f)?f.slice(1,-1):f,p=sK.join(h,r),C=!h&&/^\.[\\\/]/.test(r)?r.slice(0,2)+p:p;u(l(C,c,0))}),l=(c,u,g)=>new Promise((f,h)=>{if(g===n.length)return f(a(u+1));let p=n[g];oK(c+p,{pathExt:s},(C,y)=>{if(!C&&y)if(e.all)o.push(c+p);else return f(c+p);return f(l(c,u,g+1))})});return t?a(0).then(c=>t(null,c),t):a(0)},dge=(r,e)=>{e=e||{};let{pathEnv:t,pathExt:i,pathExtExe:n}=AK(r,e),s=[];for(let o=0;o{"use strict";var gK=(r={})=>{let e=r.env||process.env;return(r.platform||process.platform)!=="win32"?"PATH":Object.keys(e).reverse().find(i=>i.toUpperCase()==="PATH")||"Path"};gS.exports=gK;gS.exports.default=gK});var CK=w((Y7e,dK)=>{"use strict";var hK=J("path"),Cge=uK(),mge=fK();function pK(r,e){let t=r.options.env||process.env,i=process.cwd(),n=r.options.cwd!=null,s=n&&process.chdir!==void 0&&!process.chdir.disabled;if(s)try{process.chdir(r.options.cwd)}catch{}let o;try{o=Cge.sync(r.command,{path:t[mge({env:t})],pathExt:e?hK.delimiter:void 0})}catch{}finally{s&&process.chdir(i)}return o&&(o=hK.resolve(n?r.options.cwd:"",o)),o}function Ege(r){return pK(r)||pK(r,!0)}dK.exports=Ege});var mK=w((j7e,hS)=>{"use strict";var fS=/([()\][%!^"`<>&|;, *?])/g;function Ige(r){return r=r.replace(fS,"^$1"),r}function yge(r,e){return r=`${r}`,r=r.replace(/(\\*)"/g,'$1$1\\"'),r=r.replace(/(\\*)$/,"$1$1"),r=`"${r}"`,r=r.replace(fS,"^$1"),e&&(r=r.replace(fS,"^$1")),r}hS.exports.command=Ige;hS.exports.argument=yge});var IK=w((q7e,EK)=>{"use strict";EK.exports=/^#!(.*)/});var wK=w((J7e,yK)=>{"use strict";var wge=IK();yK.exports=(r="")=>{let e=r.match(wge);if(!e)return null;let[t,i]=e[0].replace(/#! ?/,"").split(" "),n=t.split("/").pop();return n==="env"?i:i?`${n} ${i}`:n}});var QK=w((W7e,BK)=>{"use strict";var pS=J("fs"),Bge=wK();function Qge(r){let t=Buffer.alloc(150),i;try{i=pS.openSync(r,"r"),pS.readSync(i,t,0,150,0),pS.closeSync(i)}catch{}return Bge(t.toString())}BK.exports=Qge});var xK=w((z7e,vK)=>{"use strict";var bge=J("path"),bK=CK(),SK=mK(),Sge=QK(),vge=process.platform==="win32",xge=/\.(?:com|exe)$/i,Pge=/node_modules[\\/].bin[\\/][^\\/]+\.cmd$/i;function Dge(r){r.file=bK(r);let e=r.file&&Sge(r.file);return e?(r.args.unshift(r.file),r.command=e,bK(r)):r.file}function kge(r){if(!vge)return r;let e=Dge(r),t=!xge.test(e);if(r.options.forceShell||t){let i=Pge.test(e);r.command=bge.normalize(r.command),r.command=SK.command(r.command),r.args=r.args.map(s=>SK.argument(s,i));let n=[r.command].concat(r.args).join(" ");r.args=["/d","/s","/c",`"${n}"`],r.command=process.env.comspec||"cmd.exe",r.options.windowsVerbatimArguments=!0}return r}function Rge(r,e,t){e&&!Array.isArray(e)&&(t=e,e=null),e=e?e.slice(0):[],t=Object.assign({},t);let i={command:r,args:e,options:t,file:void 0,original:{command:r,args:e}};return t.shell?i:kge(i)}vK.exports=Rge});var kK=w((V7e,DK)=>{"use strict";var dS=process.platform==="win32";function CS(r,e){return Object.assign(new Error(`${e} ${r.command} ENOENT`),{code:"ENOENT",errno:"ENOENT",syscall:`${e} ${r.command}`,path:r.command,spawnargs:r.args})}function Fge(r,e){if(!dS)return;let t=r.emit;r.emit=function(i,n){if(i==="exit"){let s=PK(n,e,"spawn");if(s)return t.call(r,"error",s)}return t.apply(r,arguments)}}function PK(r,e){return dS&&r===1&&!e.file?CS(e.original,"spawn"):null}function Nge(r,e){return dS&&r===1&&!e.file?CS(e.original,"spawnSync"):null}DK.exports={hookChildProcess:Fge,verifyENOENT:PK,verifyENOENTSync:Nge,notFoundError:CS}});var IS=w((X7e,yg)=>{"use strict";var RK=J("child_process"),mS=xK(),ES=kK();function FK(r,e,t){let i=mS(r,e,t),n=RK.spawn(i.command,i.args,i.options);return ES.hookChildProcess(n,i),n}function Lge(r,e,t){let i=mS(r,e,t),n=RK.spawnSync(i.command,i.args,i.options);return n.error=n.error||ES.verifyENOENTSync(n.status,i),n}yg.exports=FK;yg.exports.spawn=FK;yg.exports.sync=Lge;yg.exports._parse=mS;yg.exports._enoent=ES});var LK=w((_7e,NK)=>{"use strict";function Tge(r,e){function t(){this.constructor=r}t.prototype=e.prototype,r.prototype=new t}function Ml(r,e,t,i){this.message=r,this.expected=e,this.found=t,this.location=i,this.name="SyntaxError",typeof Error.captureStackTrace=="function"&&Error.captureStackTrace(this,Ml)}Tge(Ml,Error);Ml.buildMessage=function(r,e){var t={literal:function(c){return'"'+n(c.text)+'"'},class:function(c){var u="",g;for(g=0;g0){for(g=1,f=1;g>",ie=me(">>",!1),de=">&",tt=me(">&",!1),Pt=">",It=me(">",!1),Or="<<<",ii=me("<<<",!1),gi="<&",hr=me("<&",!1),fi="<",ni=me("<",!1),Ls=function(m){return{type:"argument",segments:[].concat(...m)}},pr=function(m){return m},Ei="$'",_n=me("$'",!1),oa="'",aA=me("'",!1),eg=function(m){return[{type:"text",text:m}]},Zn='""',AA=me('""',!1),aa=function(){return{type:"text",text:""}},up='"',lA=me('"',!1),cA=function(m){return m},wr=function(m){return{type:"arithmetic",arithmetic:m,quoted:!0}},wl=function(m){return{type:"shell",shell:m,quoted:!0}},tg=function(m){return{type:"variable",...m,quoted:!0}},po=function(m){return{type:"text",text:m}},rg=function(m){return{type:"arithmetic",arithmetic:m,quoted:!1}},gp=function(m){return{type:"shell",shell:m,quoted:!1}},fp=function(m){return{type:"variable",...m,quoted:!1}},vr=function(m){return{type:"glob",pattern:m}},se=/^[^']/,Co=Je(["'"],!0,!1),Dn=function(m){return m.join("")},ig=/^[^$"]/,Qt=Je(["$",'"'],!0,!1),Bl=`\\ +`,kn=me(`\\ +`,!1),$n=function(){return""},es="\\",gt=me("\\",!1),mo=/^[\\$"`]/,At=Je(["\\","$",'"',"`"],!1,!1),an=function(m){return m},S="\\a",Tt=me("\\a",!1),ng=function(){return"a"},Ql="\\b",hp=me("\\b",!1),pp=function(){return"\b"},dp=/^[Ee]/,Cp=Je(["E","e"],!1,!1),mp=function(){return"\x1B"},G="\\f",yt=me("\\f",!1),uA=function(){return"\f"},ji="\\n",bl=me("\\n",!1),Xe=function(){return` +`},Aa="\\r",sg=me("\\r",!1),bE=function(){return"\r"},Ep="\\t",SE=me("\\t",!1),ar=function(){return" "},Rn="\\v",Sl=me("\\v",!1),Ip=function(){return"\v"},Ts=/^[\\'"?]/,la=Je(["\\","'",'"',"?"],!1,!1),An=function(m){return String.fromCharCode(parseInt(m,16))},Te="\\x",og=me("\\x",!1),vl="\\u",Os=me("\\u",!1),xl="\\U",gA=me("\\U",!1),ag=function(m){return String.fromCodePoint(parseInt(m,16))},Ag=/^[0-7]/,ca=Je([["0","7"]],!1,!1),ua=/^[0-9a-fA-f]/,rt=Je([["0","9"],["a","f"],["A","f"]],!1,!1),Eo=nt(),fA="-",Pl=me("-",!1),Ms="+",Dl=me("+",!1),vE=".",yp=me(".",!1),lg=function(m,b,N){return{type:"number",value:(m==="-"?-1:1)*parseFloat(b.join("")+"."+N.join(""))}},wp=function(m,b){return{type:"number",value:(m==="-"?-1:1)*parseInt(b.join(""))}},xE=function(m){return{type:"variable",...m}},kl=function(m){return{type:"variable",name:m}},PE=function(m){return m},cg="*",hA=me("*",!1),Rr="/",DE=me("/",!1),Ks=function(m,b,N){return{type:b==="*"?"multiplication":"division",right:N}},Us=function(m,b){return b.reduce((N,U)=>({left:N,...U}),m)},ug=function(m,b,N){return{type:b==="+"?"addition":"subtraction",right:N}},pA="$((",R=me("$((",!1),q="))",Ce=me("))",!1),Ke=function(m){return m},Re="$(",ze=me("$(",!1),dt=function(m){return m},Ft="${",Fn=me("${",!1),Db=":-",$M=me(":-",!1),e1=function(m,b){return{name:m,defaultValue:b}},kb=":-}",t1=me(":-}",!1),r1=function(m){return{name:m,defaultValue:[]}},Rb=":+",i1=me(":+",!1),n1=function(m,b){return{name:m,alternativeValue:b}},Fb=":+}",s1=me(":+}",!1),o1=function(m){return{name:m,alternativeValue:[]}},Nb=function(m){return{name:m}},a1="$",A1=me("$",!1),l1=function(m){return e.isGlobPattern(m)},c1=function(m){return m},Lb=/^[a-zA-Z0-9_]/,Tb=Je([["a","z"],["A","Z"],["0","9"],"_"],!1,!1),Ob=function(){return T()},Mb=/^[$@*?#a-zA-Z0-9_\-]/,Kb=Je(["$","@","*","?","#",["a","z"],["A","Z"],["0","9"],"_","-"],!1,!1),u1=/^[(){}<>$|&; \t"']/,gg=Je(["(",")","{","}","<",">","$","|","&",";"," "," ",'"',"'"],!1,!1),Ub=/^[<>&; \t"']/,Hb=Je(["<",">","&",";"," "," ",'"',"'"],!1,!1),kE=/^[ \t]/,RE=Je([" "," "],!1,!1),Q=0,Me=0,dA=[{line:1,column:1}],d=0,E=[],I=0,k;if("startRule"in e){if(!(e.startRule in i))throw new Error(`Can't start parsing from rule "`+e.startRule+'".');n=i[e.startRule]}function T(){return r.substring(Me,Q)}function _(){return Et(Me,Q)}function te(m,b){throw b=b!==void 0?b:Et(Me,Q),ki([lt(m)],r.substring(Me,Q),b)}function Be(m,b){throw b=b!==void 0?b:Et(Me,Q),Nn(m,b)}function me(m,b){return{type:"literal",text:m,ignoreCase:b}}function Je(m,b,N){return{type:"class",parts:m,inverted:b,ignoreCase:N}}function nt(){return{type:"any"}}function wt(){return{type:"end"}}function lt(m){return{type:"other",description:m}}function it(m){var b=dA[m],N;if(b)return b;for(N=m-1;!dA[N];)N--;for(b=dA[N],b={line:b.line,column:b.column};Nd&&(d=Q,E=[]),E.push(m))}function Nn(m,b){return new Ml(m,null,null,b)}function ki(m,b,N){return new Ml(Ml.buildMessage(m,b),m,b,N)}function CA(){var m,b;return m=Q,b=Mr(),b===t&&(b=null),b!==t&&(Me=m,b=s(b)),m=b,m}function Mr(){var m,b,N,U,ce;if(m=Q,b=Kr(),b!==t){for(N=[],U=He();U!==t;)N.push(U),U=He();N!==t?(U=ga(),U!==t?(ce=ts(),ce===t&&(ce=null),ce!==t?(Me=m,b=o(b,U,ce),m=b):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t)}else Q=m,m=t;if(m===t)if(m=Q,b=Kr(),b!==t){for(N=[],U=He();U!==t;)N.push(U),U=He();N!==t?(U=ga(),U===t&&(U=null),U!==t?(Me=m,b=a(b,U),m=b):(Q=m,m=t)):(Q=m,m=t)}else Q=m,m=t;return m}function ts(){var m,b,N,U,ce;for(m=Q,b=[],N=He();N!==t;)b.push(N),N=He();if(b!==t)if(N=Mr(),N!==t){for(U=[],ce=He();ce!==t;)U.push(ce),ce=He();U!==t?(Me=m,b=l(N),m=b):(Q=m,m=t)}else Q=m,m=t;else Q=m,m=t;return m}function ga(){var m;return r.charCodeAt(Q)===59?(m=c,Q++):(m=t,I===0&&Qe(u)),m===t&&(r.charCodeAt(Q)===38?(m=g,Q++):(m=t,I===0&&Qe(f))),m}function Kr(){var m,b,N;return m=Q,b=g1(),b!==t?(N=yue(),N===t&&(N=null),N!==t?(Me=m,b=h(b,N),m=b):(Q=m,m=t)):(Q=m,m=t),m}function yue(){var m,b,N,U,ce,Se,ht;for(m=Q,b=[],N=He();N!==t;)b.push(N),N=He();if(b!==t)if(N=wue(),N!==t){for(U=[],ce=He();ce!==t;)U.push(ce),ce=He();if(U!==t)if(ce=Kr(),ce!==t){for(Se=[],ht=He();ht!==t;)Se.push(ht),ht=He();Se!==t?(Me=m,b=p(N,ce),m=b):(Q=m,m=t)}else Q=m,m=t;else Q=m,m=t}else Q=m,m=t;else Q=m,m=t;return m}function wue(){var m;return r.substr(Q,2)===C?(m=C,Q+=2):(m=t,I===0&&Qe(y)),m===t&&(r.substr(Q,2)===B?(m=B,Q+=2):(m=t,I===0&&Qe(v))),m}function g1(){var m,b,N;return m=Q,b=bue(),b!==t?(N=Bue(),N===t&&(N=null),N!==t?(Me=m,b=D(b,N),m=b):(Q=m,m=t)):(Q=m,m=t),m}function Bue(){var m,b,N,U,ce,Se,ht;for(m=Q,b=[],N=He();N!==t;)b.push(N),N=He();if(b!==t)if(N=Que(),N!==t){for(U=[],ce=He();ce!==t;)U.push(ce),ce=He();if(U!==t)if(ce=g1(),ce!==t){for(Se=[],ht=He();ht!==t;)Se.push(ht),ht=He();Se!==t?(Me=m,b=L(N,ce),m=b):(Q=m,m=t)}else Q=m,m=t;else Q=m,m=t}else Q=m,m=t;else Q=m,m=t;return m}function Que(){var m;return r.substr(Q,2)===H?(m=H,Q+=2):(m=t,I===0&&Qe(j)),m===t&&(r.charCodeAt(Q)===124?(m=$,Q++):(m=t,I===0&&Qe(V))),m}function FE(){var m,b,N,U,ce,Se;if(m=Q,b=Q1(),b!==t)if(r.charCodeAt(Q)===61?(N=W,Q++):(N=t,I===0&&Qe(Z)),N!==t)if(U=p1(),U!==t){for(ce=[],Se=He();Se!==t;)ce.push(Se),Se=He();ce!==t?(Me=m,b=A(b,U),m=b):(Q=m,m=t)}else Q=m,m=t;else Q=m,m=t;else Q=m,m=t;if(m===t)if(m=Q,b=Q1(),b!==t)if(r.charCodeAt(Q)===61?(N=W,Q++):(N=t,I===0&&Qe(Z)),N!==t){for(U=[],ce=He();ce!==t;)U.push(ce),ce=He();U!==t?(Me=m,b=ae(b),m=b):(Q=m,m=t)}else Q=m,m=t;else Q=m,m=t;return m}function bue(){var m,b,N,U,ce,Se,ht,Bt,Jr,hi,rs;for(m=Q,b=[],N=He();N!==t;)b.push(N),N=He();if(b!==t)if(r.charCodeAt(Q)===40?(N=ge,Q++):(N=t,I===0&&Qe(re)),N!==t){for(U=[],ce=He();ce!==t;)U.push(ce),ce=He();if(U!==t)if(ce=Mr(),ce!==t){for(Se=[],ht=He();ht!==t;)Se.push(ht),ht=He();if(Se!==t)if(r.charCodeAt(Q)===41?(ht=O,Q++):(ht=t,I===0&&Qe(F)),ht!==t){for(Bt=[],Jr=He();Jr!==t;)Bt.push(Jr),Jr=He();if(Bt!==t){for(Jr=[],hi=Bp();hi!==t;)Jr.push(hi),hi=Bp();if(Jr!==t){for(hi=[],rs=He();rs!==t;)hi.push(rs),rs=He();hi!==t?(Me=m,b=ue(ce,Jr),m=b):(Q=m,m=t)}else Q=m,m=t}else Q=m,m=t}else Q=m,m=t;else Q=m,m=t}else Q=m,m=t;else Q=m,m=t}else Q=m,m=t;else Q=m,m=t;if(m===t){for(m=Q,b=[],N=He();N!==t;)b.push(N),N=He();if(b!==t)if(r.charCodeAt(Q)===123?(N=he,Q++):(N=t,I===0&&Qe(ke)),N!==t){for(U=[],ce=He();ce!==t;)U.push(ce),ce=He();if(U!==t)if(ce=Mr(),ce!==t){for(Se=[],ht=He();ht!==t;)Se.push(ht),ht=He();if(Se!==t)if(r.charCodeAt(Q)===125?(ht=Fe,Q++):(ht=t,I===0&&Qe(Ne)),ht!==t){for(Bt=[],Jr=He();Jr!==t;)Bt.push(Jr),Jr=He();if(Bt!==t){for(Jr=[],hi=Bp();hi!==t;)Jr.push(hi),hi=Bp();if(Jr!==t){for(hi=[],rs=He();rs!==t;)hi.push(rs),rs=He();hi!==t?(Me=m,b=oe(ce,Jr),m=b):(Q=m,m=t)}else Q=m,m=t}else Q=m,m=t}else Q=m,m=t;else Q=m,m=t}else Q=m,m=t;else Q=m,m=t}else Q=m,m=t;else Q=m,m=t;if(m===t){for(m=Q,b=[],N=He();N!==t;)b.push(N),N=He();if(b!==t){for(N=[],U=FE();U!==t;)N.push(U),U=FE();if(N!==t){for(U=[],ce=He();ce!==t;)U.push(ce),ce=He();if(U!==t){if(ce=[],Se=h1(),Se!==t)for(;Se!==t;)ce.push(Se),Se=h1();else ce=t;if(ce!==t){for(Se=[],ht=He();ht!==t;)Se.push(ht),ht=He();Se!==t?(Me=m,b=le(N,ce),m=b):(Q=m,m=t)}else Q=m,m=t}else Q=m,m=t}else Q=m,m=t}else Q=m,m=t;if(m===t){for(m=Q,b=[],N=He();N!==t;)b.push(N),N=He();if(b!==t){if(N=[],U=FE(),U!==t)for(;U!==t;)N.push(U),U=FE();else N=t;if(N!==t){for(U=[],ce=He();ce!==t;)U.push(ce),ce=He();U!==t?(Me=m,b=we(N),m=b):(Q=m,m=t)}else Q=m,m=t}else Q=m,m=t}}}return m}function f1(){var m,b,N,U,ce;for(m=Q,b=[],N=He();N!==t;)b.push(N),N=He();if(b!==t){if(N=[],U=NE(),U!==t)for(;U!==t;)N.push(U),U=NE();else N=t;if(N!==t){for(U=[],ce=He();ce!==t;)U.push(ce),ce=He();U!==t?(Me=m,b=fe(N),m=b):(Q=m,m=t)}else Q=m,m=t}else Q=m,m=t;return m}function h1(){var m,b,N;for(m=Q,b=[],N=He();N!==t;)b.push(N),N=He();if(b!==t?(N=Bp(),N!==t?(Me=m,b=Ae(N),m=b):(Q=m,m=t)):(Q=m,m=t),m===t){for(m=Q,b=[],N=He();N!==t;)b.push(N),N=He();b!==t?(N=NE(),N!==t?(Me=m,b=Ae(N),m=b):(Q=m,m=t)):(Q=m,m=t)}return m}function Bp(){var m,b,N,U,ce;for(m=Q,b=[],N=He();N!==t;)b.push(N),N=He();return b!==t?(qe.test(r.charAt(Q))?(N=r.charAt(Q),Q++):(N=t,I===0&&Qe(ne)),N===t&&(N=null),N!==t?(U=Sue(),U!==t?(ce=NE(),ce!==t?(Me=m,b=Y(N,U,ce),m=b):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t),m}function Sue(){var m;return r.substr(Q,2)===pe?(m=pe,Q+=2):(m=t,I===0&&Qe(ie)),m===t&&(r.substr(Q,2)===de?(m=de,Q+=2):(m=t,I===0&&Qe(tt)),m===t&&(r.charCodeAt(Q)===62?(m=Pt,Q++):(m=t,I===0&&Qe(It)),m===t&&(r.substr(Q,3)===Or?(m=Or,Q+=3):(m=t,I===0&&Qe(ii)),m===t&&(r.substr(Q,2)===gi?(m=gi,Q+=2):(m=t,I===0&&Qe(hr)),m===t&&(r.charCodeAt(Q)===60?(m=fi,Q++):(m=t,I===0&&Qe(ni))))))),m}function NE(){var m,b,N;for(m=Q,b=[],N=He();N!==t;)b.push(N),N=He();return b!==t?(N=p1(),N!==t?(Me=m,b=Ae(N),m=b):(Q=m,m=t)):(Q=m,m=t),m}function p1(){var m,b,N;if(m=Q,b=[],N=d1(),N!==t)for(;N!==t;)b.push(N),N=d1();else b=t;return b!==t&&(Me=m,b=Ls(b)),m=b,m}function d1(){var m,b;return m=Q,b=vue(),b!==t&&(Me=m,b=pr(b)),m=b,m===t&&(m=Q,b=xue(),b!==t&&(Me=m,b=pr(b)),m=b,m===t&&(m=Q,b=Pue(),b!==t&&(Me=m,b=pr(b)),m=b,m===t&&(m=Q,b=Due(),b!==t&&(Me=m,b=pr(b)),m=b))),m}function vue(){var m,b,N,U;return m=Q,r.substr(Q,2)===Ei?(b=Ei,Q+=2):(b=t,I===0&&Qe(_n)),b!==t?(N=Fue(),N!==t?(r.charCodeAt(Q)===39?(U=oa,Q++):(U=t,I===0&&Qe(aA)),U!==t?(Me=m,b=eg(N),m=b):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t),m}function xue(){var m,b,N,U;return m=Q,r.charCodeAt(Q)===39?(b=oa,Q++):(b=t,I===0&&Qe(aA)),b!==t?(N=kue(),N!==t?(r.charCodeAt(Q)===39?(U=oa,Q++):(U=t,I===0&&Qe(aA)),U!==t?(Me=m,b=eg(N),m=b):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t),m}function Pue(){var m,b,N,U;if(m=Q,r.substr(Q,2)===Zn?(b=Zn,Q+=2):(b=t,I===0&&Qe(AA)),b!==t&&(Me=m,b=aa()),m=b,m===t)if(m=Q,r.charCodeAt(Q)===34?(b=up,Q++):(b=t,I===0&&Qe(lA)),b!==t){for(N=[],U=C1();U!==t;)N.push(U),U=C1();N!==t?(r.charCodeAt(Q)===34?(U=up,Q++):(U=t,I===0&&Qe(lA)),U!==t?(Me=m,b=cA(N),m=b):(Q=m,m=t)):(Q=m,m=t)}else Q=m,m=t;return m}function Due(){var m,b,N;if(m=Q,b=[],N=m1(),N!==t)for(;N!==t;)b.push(N),N=m1();else b=t;return b!==t&&(Me=m,b=cA(b)),m=b,m}function C1(){var m,b;return m=Q,b=w1(),b!==t&&(Me=m,b=wr(b)),m=b,m===t&&(m=Q,b=B1(),b!==t&&(Me=m,b=wl(b)),m=b,m===t&&(m=Q,b=qb(),b!==t&&(Me=m,b=tg(b)),m=b,m===t&&(m=Q,b=Rue(),b!==t&&(Me=m,b=po(b)),m=b))),m}function m1(){var m,b;return m=Q,b=w1(),b!==t&&(Me=m,b=rg(b)),m=b,m===t&&(m=Q,b=B1(),b!==t&&(Me=m,b=gp(b)),m=b,m===t&&(m=Q,b=qb(),b!==t&&(Me=m,b=fp(b)),m=b,m===t&&(m=Q,b=Tue(),b!==t&&(Me=m,b=vr(b)),m=b,m===t&&(m=Q,b=Lue(),b!==t&&(Me=m,b=po(b)),m=b)))),m}function kue(){var m,b,N;for(m=Q,b=[],se.test(r.charAt(Q))?(N=r.charAt(Q),Q++):(N=t,I===0&&Qe(Co));N!==t;)b.push(N),se.test(r.charAt(Q))?(N=r.charAt(Q),Q++):(N=t,I===0&&Qe(Co));return b!==t&&(Me=m,b=Dn(b)),m=b,m}function Rue(){var m,b,N;if(m=Q,b=[],N=E1(),N===t&&(ig.test(r.charAt(Q))?(N=r.charAt(Q),Q++):(N=t,I===0&&Qe(Qt))),N!==t)for(;N!==t;)b.push(N),N=E1(),N===t&&(ig.test(r.charAt(Q))?(N=r.charAt(Q),Q++):(N=t,I===0&&Qe(Qt)));else b=t;return b!==t&&(Me=m,b=Dn(b)),m=b,m}function E1(){var m,b,N;return m=Q,r.substr(Q,2)===Bl?(b=Bl,Q+=2):(b=t,I===0&&Qe(kn)),b!==t&&(Me=m,b=$n()),m=b,m===t&&(m=Q,r.charCodeAt(Q)===92?(b=es,Q++):(b=t,I===0&&Qe(gt)),b!==t?(mo.test(r.charAt(Q))?(N=r.charAt(Q),Q++):(N=t,I===0&&Qe(At)),N!==t?(Me=m,b=an(N),m=b):(Q=m,m=t)):(Q=m,m=t)),m}function Fue(){var m,b,N;for(m=Q,b=[],N=I1(),N===t&&(se.test(r.charAt(Q))?(N=r.charAt(Q),Q++):(N=t,I===0&&Qe(Co)));N!==t;)b.push(N),N=I1(),N===t&&(se.test(r.charAt(Q))?(N=r.charAt(Q),Q++):(N=t,I===0&&Qe(Co)));return b!==t&&(Me=m,b=Dn(b)),m=b,m}function I1(){var m,b,N;return m=Q,r.substr(Q,2)===S?(b=S,Q+=2):(b=t,I===0&&Qe(Tt)),b!==t&&(Me=m,b=ng()),m=b,m===t&&(m=Q,r.substr(Q,2)===Ql?(b=Ql,Q+=2):(b=t,I===0&&Qe(hp)),b!==t&&(Me=m,b=pp()),m=b,m===t&&(m=Q,r.charCodeAt(Q)===92?(b=es,Q++):(b=t,I===0&&Qe(gt)),b!==t?(dp.test(r.charAt(Q))?(N=r.charAt(Q),Q++):(N=t,I===0&&Qe(Cp)),N!==t?(Me=m,b=mp(),m=b):(Q=m,m=t)):(Q=m,m=t),m===t&&(m=Q,r.substr(Q,2)===G?(b=G,Q+=2):(b=t,I===0&&Qe(yt)),b!==t&&(Me=m,b=uA()),m=b,m===t&&(m=Q,r.substr(Q,2)===ji?(b=ji,Q+=2):(b=t,I===0&&Qe(bl)),b!==t&&(Me=m,b=Xe()),m=b,m===t&&(m=Q,r.substr(Q,2)===Aa?(b=Aa,Q+=2):(b=t,I===0&&Qe(sg)),b!==t&&(Me=m,b=bE()),m=b,m===t&&(m=Q,r.substr(Q,2)===Ep?(b=Ep,Q+=2):(b=t,I===0&&Qe(SE)),b!==t&&(Me=m,b=ar()),m=b,m===t&&(m=Q,r.substr(Q,2)===Rn?(b=Rn,Q+=2):(b=t,I===0&&Qe(Sl)),b!==t&&(Me=m,b=Ip()),m=b,m===t&&(m=Q,r.charCodeAt(Q)===92?(b=es,Q++):(b=t,I===0&&Qe(gt)),b!==t?(Ts.test(r.charAt(Q))?(N=r.charAt(Q),Q++):(N=t,I===0&&Qe(la)),N!==t?(Me=m,b=an(N),m=b):(Q=m,m=t)):(Q=m,m=t),m===t&&(m=Nue()))))))))),m}function Nue(){var m,b,N,U,ce,Se,ht,Bt,Jr,hi,rs,Jb;return m=Q,r.charCodeAt(Q)===92?(b=es,Q++):(b=t,I===0&&Qe(gt)),b!==t?(N=Gb(),N!==t?(Me=m,b=An(N),m=b):(Q=m,m=t)):(Q=m,m=t),m===t&&(m=Q,r.substr(Q,2)===Te?(b=Te,Q+=2):(b=t,I===0&&Qe(og)),b!==t?(N=Q,U=Q,ce=Gb(),ce!==t?(Se=Ln(),Se!==t?(ce=[ce,Se],U=ce):(Q=U,U=t)):(Q=U,U=t),U===t&&(U=Gb()),U!==t?N=r.substring(N,Q):N=U,N!==t?(Me=m,b=An(N),m=b):(Q=m,m=t)):(Q=m,m=t),m===t&&(m=Q,r.substr(Q,2)===vl?(b=vl,Q+=2):(b=t,I===0&&Qe(Os)),b!==t?(N=Q,U=Q,ce=Ln(),ce!==t?(Se=Ln(),Se!==t?(ht=Ln(),ht!==t?(Bt=Ln(),Bt!==t?(ce=[ce,Se,ht,Bt],U=ce):(Q=U,U=t)):(Q=U,U=t)):(Q=U,U=t)):(Q=U,U=t),U!==t?N=r.substring(N,Q):N=U,N!==t?(Me=m,b=An(N),m=b):(Q=m,m=t)):(Q=m,m=t),m===t&&(m=Q,r.substr(Q,2)===xl?(b=xl,Q+=2):(b=t,I===0&&Qe(gA)),b!==t?(N=Q,U=Q,ce=Ln(),ce!==t?(Se=Ln(),Se!==t?(ht=Ln(),ht!==t?(Bt=Ln(),Bt!==t?(Jr=Ln(),Jr!==t?(hi=Ln(),hi!==t?(rs=Ln(),rs!==t?(Jb=Ln(),Jb!==t?(ce=[ce,Se,ht,Bt,Jr,hi,rs,Jb],U=ce):(Q=U,U=t)):(Q=U,U=t)):(Q=U,U=t)):(Q=U,U=t)):(Q=U,U=t)):(Q=U,U=t)):(Q=U,U=t)):(Q=U,U=t),U!==t?N=r.substring(N,Q):N=U,N!==t?(Me=m,b=ag(N),m=b):(Q=m,m=t)):(Q=m,m=t)))),m}function Gb(){var m;return Ag.test(r.charAt(Q))?(m=r.charAt(Q),Q++):(m=t,I===0&&Qe(ca)),m}function Ln(){var m;return ua.test(r.charAt(Q))?(m=r.charAt(Q),Q++):(m=t,I===0&&Qe(rt)),m}function Lue(){var m,b,N,U,ce;if(m=Q,b=[],N=Q,r.charCodeAt(Q)===92?(U=es,Q++):(U=t,I===0&&Qe(gt)),U!==t?(r.length>Q?(ce=r.charAt(Q),Q++):(ce=t,I===0&&Qe(Eo)),ce!==t?(Me=N,U=an(ce),N=U):(Q=N,N=t)):(Q=N,N=t),N===t&&(N=Q,U=Q,I++,ce=b1(),I--,ce===t?U=void 0:(Q=U,U=t),U!==t?(r.length>Q?(ce=r.charAt(Q),Q++):(ce=t,I===0&&Qe(Eo)),ce!==t?(Me=N,U=an(ce),N=U):(Q=N,N=t)):(Q=N,N=t)),N!==t)for(;N!==t;)b.push(N),N=Q,r.charCodeAt(Q)===92?(U=es,Q++):(U=t,I===0&&Qe(gt)),U!==t?(r.length>Q?(ce=r.charAt(Q),Q++):(ce=t,I===0&&Qe(Eo)),ce!==t?(Me=N,U=an(ce),N=U):(Q=N,N=t)):(Q=N,N=t),N===t&&(N=Q,U=Q,I++,ce=b1(),I--,ce===t?U=void 0:(Q=U,U=t),U!==t?(r.length>Q?(ce=r.charAt(Q),Q++):(ce=t,I===0&&Qe(Eo)),ce!==t?(Me=N,U=an(ce),N=U):(Q=N,N=t)):(Q=N,N=t));else b=t;return b!==t&&(Me=m,b=Dn(b)),m=b,m}function Yb(){var m,b,N,U,ce,Se;if(m=Q,r.charCodeAt(Q)===45?(b=fA,Q++):(b=t,I===0&&Qe(Pl)),b===t&&(r.charCodeAt(Q)===43?(b=Ms,Q++):(b=t,I===0&&Qe(Dl))),b===t&&(b=null),b!==t){if(N=[],qe.test(r.charAt(Q))?(U=r.charAt(Q),Q++):(U=t,I===0&&Qe(ne)),U!==t)for(;U!==t;)N.push(U),qe.test(r.charAt(Q))?(U=r.charAt(Q),Q++):(U=t,I===0&&Qe(ne));else N=t;if(N!==t)if(r.charCodeAt(Q)===46?(U=vE,Q++):(U=t,I===0&&Qe(yp)),U!==t){if(ce=[],qe.test(r.charAt(Q))?(Se=r.charAt(Q),Q++):(Se=t,I===0&&Qe(ne)),Se!==t)for(;Se!==t;)ce.push(Se),qe.test(r.charAt(Q))?(Se=r.charAt(Q),Q++):(Se=t,I===0&&Qe(ne));else ce=t;ce!==t?(Me=m,b=lg(b,N,ce),m=b):(Q=m,m=t)}else Q=m,m=t;else Q=m,m=t}else Q=m,m=t;if(m===t){if(m=Q,r.charCodeAt(Q)===45?(b=fA,Q++):(b=t,I===0&&Qe(Pl)),b===t&&(r.charCodeAt(Q)===43?(b=Ms,Q++):(b=t,I===0&&Qe(Dl))),b===t&&(b=null),b!==t){if(N=[],qe.test(r.charAt(Q))?(U=r.charAt(Q),Q++):(U=t,I===0&&Qe(ne)),U!==t)for(;U!==t;)N.push(U),qe.test(r.charAt(Q))?(U=r.charAt(Q),Q++):(U=t,I===0&&Qe(ne));else N=t;N!==t?(Me=m,b=wp(b,N),m=b):(Q=m,m=t)}else Q=m,m=t;if(m===t&&(m=Q,b=qb(),b!==t&&(Me=m,b=xE(b)),m=b,m===t&&(m=Q,b=Rl(),b!==t&&(Me=m,b=kl(b)),m=b,m===t)))if(m=Q,r.charCodeAt(Q)===40?(b=ge,Q++):(b=t,I===0&&Qe(re)),b!==t){for(N=[],U=He();U!==t;)N.push(U),U=He();if(N!==t)if(U=y1(),U!==t){for(ce=[],Se=He();Se!==t;)ce.push(Se),Se=He();ce!==t?(r.charCodeAt(Q)===41?(Se=O,Q++):(Se=t,I===0&&Qe(F)),Se!==t?(Me=m,b=PE(U),m=b):(Q=m,m=t)):(Q=m,m=t)}else Q=m,m=t;else Q=m,m=t}else Q=m,m=t}return m}function jb(){var m,b,N,U,ce,Se,ht,Bt;if(m=Q,b=Yb(),b!==t){for(N=[],U=Q,ce=[],Se=He();Se!==t;)ce.push(Se),Se=He();if(ce!==t)if(r.charCodeAt(Q)===42?(Se=cg,Q++):(Se=t,I===0&&Qe(hA)),Se===t&&(r.charCodeAt(Q)===47?(Se=Rr,Q++):(Se=t,I===0&&Qe(DE))),Se!==t){for(ht=[],Bt=He();Bt!==t;)ht.push(Bt),Bt=He();ht!==t?(Bt=Yb(),Bt!==t?(Me=U,ce=Ks(b,Se,Bt),U=ce):(Q=U,U=t)):(Q=U,U=t)}else Q=U,U=t;else Q=U,U=t;for(;U!==t;){for(N.push(U),U=Q,ce=[],Se=He();Se!==t;)ce.push(Se),Se=He();if(ce!==t)if(r.charCodeAt(Q)===42?(Se=cg,Q++):(Se=t,I===0&&Qe(hA)),Se===t&&(r.charCodeAt(Q)===47?(Se=Rr,Q++):(Se=t,I===0&&Qe(DE))),Se!==t){for(ht=[],Bt=He();Bt!==t;)ht.push(Bt),Bt=He();ht!==t?(Bt=Yb(),Bt!==t?(Me=U,ce=Ks(b,Se,Bt),U=ce):(Q=U,U=t)):(Q=U,U=t)}else Q=U,U=t;else Q=U,U=t}N!==t?(Me=m,b=Us(b,N),m=b):(Q=m,m=t)}else Q=m,m=t;return m}function y1(){var m,b,N,U,ce,Se,ht,Bt;if(m=Q,b=jb(),b!==t){for(N=[],U=Q,ce=[],Se=He();Se!==t;)ce.push(Se),Se=He();if(ce!==t)if(r.charCodeAt(Q)===43?(Se=Ms,Q++):(Se=t,I===0&&Qe(Dl)),Se===t&&(r.charCodeAt(Q)===45?(Se=fA,Q++):(Se=t,I===0&&Qe(Pl))),Se!==t){for(ht=[],Bt=He();Bt!==t;)ht.push(Bt),Bt=He();ht!==t?(Bt=jb(),Bt!==t?(Me=U,ce=ug(b,Se,Bt),U=ce):(Q=U,U=t)):(Q=U,U=t)}else Q=U,U=t;else Q=U,U=t;for(;U!==t;){for(N.push(U),U=Q,ce=[],Se=He();Se!==t;)ce.push(Se),Se=He();if(ce!==t)if(r.charCodeAt(Q)===43?(Se=Ms,Q++):(Se=t,I===0&&Qe(Dl)),Se===t&&(r.charCodeAt(Q)===45?(Se=fA,Q++):(Se=t,I===0&&Qe(Pl))),Se!==t){for(ht=[],Bt=He();Bt!==t;)ht.push(Bt),Bt=He();ht!==t?(Bt=jb(),Bt!==t?(Me=U,ce=ug(b,Se,Bt),U=ce):(Q=U,U=t)):(Q=U,U=t)}else Q=U,U=t;else Q=U,U=t}N!==t?(Me=m,b=Us(b,N),m=b):(Q=m,m=t)}else Q=m,m=t;return m}function w1(){var m,b,N,U,ce,Se;if(m=Q,r.substr(Q,3)===pA?(b=pA,Q+=3):(b=t,I===0&&Qe(R)),b!==t){for(N=[],U=He();U!==t;)N.push(U),U=He();if(N!==t)if(U=y1(),U!==t){for(ce=[],Se=He();Se!==t;)ce.push(Se),Se=He();ce!==t?(r.substr(Q,2)===q?(Se=q,Q+=2):(Se=t,I===0&&Qe(Ce)),Se!==t?(Me=m,b=Ke(U),m=b):(Q=m,m=t)):(Q=m,m=t)}else Q=m,m=t;else Q=m,m=t}else Q=m,m=t;return m}function B1(){var m,b,N,U;return m=Q,r.substr(Q,2)===Re?(b=Re,Q+=2):(b=t,I===0&&Qe(ze)),b!==t?(N=Mr(),N!==t?(r.charCodeAt(Q)===41?(U=O,Q++):(U=t,I===0&&Qe(F)),U!==t?(Me=m,b=dt(N),m=b):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t),m}function qb(){var m,b,N,U,ce,Se;return m=Q,r.substr(Q,2)===Ft?(b=Ft,Q+=2):(b=t,I===0&&Qe(Fn)),b!==t?(N=Rl(),N!==t?(r.substr(Q,2)===Db?(U=Db,Q+=2):(U=t,I===0&&Qe($M)),U!==t?(ce=f1(),ce!==t?(r.charCodeAt(Q)===125?(Se=Fe,Q++):(Se=t,I===0&&Qe(Ne)),Se!==t?(Me=m,b=e1(N,ce),m=b):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t),m===t&&(m=Q,r.substr(Q,2)===Ft?(b=Ft,Q+=2):(b=t,I===0&&Qe(Fn)),b!==t?(N=Rl(),N!==t?(r.substr(Q,3)===kb?(U=kb,Q+=3):(U=t,I===0&&Qe(t1)),U!==t?(Me=m,b=r1(N),m=b):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t),m===t&&(m=Q,r.substr(Q,2)===Ft?(b=Ft,Q+=2):(b=t,I===0&&Qe(Fn)),b!==t?(N=Rl(),N!==t?(r.substr(Q,2)===Rb?(U=Rb,Q+=2):(U=t,I===0&&Qe(i1)),U!==t?(ce=f1(),ce!==t?(r.charCodeAt(Q)===125?(Se=Fe,Q++):(Se=t,I===0&&Qe(Ne)),Se!==t?(Me=m,b=n1(N,ce),m=b):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t),m===t&&(m=Q,r.substr(Q,2)===Ft?(b=Ft,Q+=2):(b=t,I===0&&Qe(Fn)),b!==t?(N=Rl(),N!==t?(r.substr(Q,3)===Fb?(U=Fb,Q+=3):(U=t,I===0&&Qe(s1)),U!==t?(Me=m,b=o1(N),m=b):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t),m===t&&(m=Q,r.substr(Q,2)===Ft?(b=Ft,Q+=2):(b=t,I===0&&Qe(Fn)),b!==t?(N=Rl(),N!==t?(r.charCodeAt(Q)===125?(U=Fe,Q++):(U=t,I===0&&Qe(Ne)),U!==t?(Me=m,b=Nb(N),m=b):(Q=m,m=t)):(Q=m,m=t)):(Q=m,m=t),m===t&&(m=Q,r.charCodeAt(Q)===36?(b=a1,Q++):(b=t,I===0&&Qe(A1)),b!==t?(N=Rl(),N!==t?(Me=m,b=Nb(N),m=b):(Q=m,m=t)):(Q=m,m=t)))))),m}function Tue(){var m,b,N;return m=Q,b=Oue(),b!==t?(Me=Q,N=l1(b),N?N=void 0:N=t,N!==t?(Me=m,b=c1(b),m=b):(Q=m,m=t)):(Q=m,m=t),m}function Oue(){var m,b,N,U,ce;if(m=Q,b=[],N=Q,U=Q,I++,ce=S1(),I--,ce===t?U=void 0:(Q=U,U=t),U!==t?(r.length>Q?(ce=r.charAt(Q),Q++):(ce=t,I===0&&Qe(Eo)),ce!==t?(Me=N,U=an(ce),N=U):(Q=N,N=t)):(Q=N,N=t),N!==t)for(;N!==t;)b.push(N),N=Q,U=Q,I++,ce=S1(),I--,ce===t?U=void 0:(Q=U,U=t),U!==t?(r.length>Q?(ce=r.charAt(Q),Q++):(ce=t,I===0&&Qe(Eo)),ce!==t?(Me=N,U=an(ce),N=U):(Q=N,N=t)):(Q=N,N=t);else b=t;return b!==t&&(Me=m,b=Dn(b)),m=b,m}function Q1(){var m,b,N;if(m=Q,b=[],Lb.test(r.charAt(Q))?(N=r.charAt(Q),Q++):(N=t,I===0&&Qe(Tb)),N!==t)for(;N!==t;)b.push(N),Lb.test(r.charAt(Q))?(N=r.charAt(Q),Q++):(N=t,I===0&&Qe(Tb));else b=t;return b!==t&&(Me=m,b=Ob()),m=b,m}function Rl(){var m,b,N;if(m=Q,b=[],Mb.test(r.charAt(Q))?(N=r.charAt(Q),Q++):(N=t,I===0&&Qe(Kb)),N!==t)for(;N!==t;)b.push(N),Mb.test(r.charAt(Q))?(N=r.charAt(Q),Q++):(N=t,I===0&&Qe(Kb));else b=t;return b!==t&&(Me=m,b=Ob()),m=b,m}function b1(){var m;return u1.test(r.charAt(Q))?(m=r.charAt(Q),Q++):(m=t,I===0&&Qe(gg)),m}function S1(){var m;return Ub.test(r.charAt(Q))?(m=r.charAt(Q),Q++):(m=t,I===0&&Qe(Hb)),m}function He(){var m,b;if(m=[],kE.test(r.charAt(Q))?(b=r.charAt(Q),Q++):(b=t,I===0&&Qe(RE)),b!==t)for(;b!==t;)m.push(b),kE.test(r.charAt(Q))?(b=r.charAt(Q),Q++):(b=t,I===0&&Qe(RE));else m=t;return m}if(k=n(),k!==t&&Q===r.length)return k;throw k!==t&&Q{"use strict";function Mge(r,e){function t(){this.constructor=r}t.prototype=e.prototype,r.prototype=new t}function Ul(r,e,t,i){this.message=r,this.expected=e,this.found=t,this.location=i,this.name="SyntaxError",typeof Error.captureStackTrace=="function"&&Error.captureStackTrace(this,Ul)}Mge(Ul,Error);Ul.buildMessage=function(r,e){var t={literal:function(c){return'"'+n(c.text)+'"'},class:function(c){var u="",g;for(g=0;g0){for(g=1,f=1;gH&&(H=v,j=[]),j.push(ne))}function Ne(ne,Y){return new Ul(ne,null,null,Y)}function oe(ne,Y,pe){return new Ul(Ul.buildMessage(ne,Y),ne,Y,pe)}function le(){var ne,Y,pe,ie;return ne=v,Y=we(),Y!==t?(r.charCodeAt(v)===47?(pe=s,v++):(pe=t,$===0&&Fe(o)),pe!==t?(ie=we(),ie!==t?(D=ne,Y=a(Y,ie),ne=Y):(v=ne,ne=t)):(v=ne,ne=t)):(v=ne,ne=t),ne===t&&(ne=v,Y=we(),Y!==t&&(D=ne,Y=l(Y)),ne=Y),ne}function we(){var ne,Y,pe,ie;return ne=v,Y=fe(),Y!==t?(r.charCodeAt(v)===64?(pe=c,v++):(pe=t,$===0&&Fe(u)),pe!==t?(ie=qe(),ie!==t?(D=ne,Y=g(Y,ie),ne=Y):(v=ne,ne=t)):(v=ne,ne=t)):(v=ne,ne=t),ne===t&&(ne=v,Y=fe(),Y!==t&&(D=ne,Y=f(Y)),ne=Y),ne}function fe(){var ne,Y,pe,ie,de;return ne=v,r.charCodeAt(v)===64?(Y=c,v++):(Y=t,$===0&&Fe(u)),Y!==t?(pe=Ae(),pe!==t?(r.charCodeAt(v)===47?(ie=s,v++):(ie=t,$===0&&Fe(o)),ie!==t?(de=Ae(),de!==t?(D=ne,Y=h(),ne=Y):(v=ne,ne=t)):(v=ne,ne=t)):(v=ne,ne=t)):(v=ne,ne=t),ne===t&&(ne=v,Y=Ae(),Y!==t&&(D=ne,Y=h()),ne=Y),ne}function Ae(){var ne,Y,pe;if(ne=v,Y=[],p.test(r.charAt(v))?(pe=r.charAt(v),v++):(pe=t,$===0&&Fe(C)),pe!==t)for(;pe!==t;)Y.push(pe),p.test(r.charAt(v))?(pe=r.charAt(v),v++):(pe=t,$===0&&Fe(C));else Y=t;return Y!==t&&(D=ne,Y=h()),ne=Y,ne}function qe(){var ne,Y,pe;if(ne=v,Y=[],y.test(r.charAt(v))?(pe=r.charAt(v),v++):(pe=t,$===0&&Fe(B)),pe!==t)for(;pe!==t;)Y.push(pe),y.test(r.charAt(v))?(pe=r.charAt(v),v++):(pe=t,$===0&&Fe(B));else Y=t;return Y!==t&&(D=ne,Y=h()),ne=Y,ne}if(V=n(),V!==t&&v===r.length)return V;throw V!==t&&v{"use strict";function UK(r){return typeof r>"u"||r===null}function Uge(r){return typeof r=="object"&&r!==null}function Hge(r){return Array.isArray(r)?r:UK(r)?[]:[r]}function Gge(r,e){var t,i,n,s;if(e)for(s=Object.keys(e),t=0,i=s.length;t{"use strict";function Op(r,e){Error.call(this),this.name="YAMLException",this.reason=r,this.mark=e,this.message=(this.reason||"(unknown reason)")+(this.mark?" "+this.mark.toString():""),Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):this.stack=new Error().stack||""}Op.prototype=Object.create(Error.prototype);Op.prototype.constructor=Op;Op.prototype.toString=function(e){var t=this.name+": ";return t+=this.reason||"(unknown reason)",!e&&this.mark&&(t+=" "+this.mark.toString()),t};HK.exports=Op});var jK=w((pXe,YK)=>{"use strict";var GK=Gl();function SS(r,e,t,i,n){this.name=r,this.buffer=e,this.position=t,this.line=i,this.column=n}SS.prototype.getSnippet=function(e,t){var i,n,s,o,a;if(!this.buffer)return null;for(e=e||4,t=t||75,i="",n=this.position;n>0&&`\0\r +\x85\u2028\u2029`.indexOf(this.buffer.charAt(n-1))===-1;)if(n-=1,this.position-n>t/2-1){i=" ... ",n+=5;break}for(s="",o=this.position;ot/2-1){s=" ... ",o-=5;break}return a=this.buffer.slice(n,o),GK.repeat(" ",e)+i+a+s+` +`+GK.repeat(" ",e+this.position-n+i.length)+"^"};SS.prototype.toString=function(e){var t,i="";return this.name&&(i+='in "'+this.name+'" '),i+="at line "+(this.line+1)+", column "+(this.column+1),e||(t=this.getSnippet(),t&&(i+=`: +`+t)),i};YK.exports=SS});var si=w((dXe,JK)=>{"use strict";var qK=Qg(),qge=["kind","resolve","construct","instanceOf","predicate","represent","defaultStyle","styleAliases"],Jge=["scalar","sequence","mapping"];function Wge(r){var e={};return r!==null&&Object.keys(r).forEach(function(t){r[t].forEach(function(i){e[String(i)]=t})}),e}function zge(r,e){if(e=e||{},Object.keys(e).forEach(function(t){if(qge.indexOf(t)===-1)throw new qK('Unknown option "'+t+'" is met in definition of "'+r+'" YAML type.')}),this.tag=r,this.kind=e.kind||null,this.resolve=e.resolve||function(){return!0},this.construct=e.construct||function(t){return t},this.instanceOf=e.instanceOf||null,this.predicate=e.predicate||null,this.represent=e.represent||null,this.defaultStyle=e.defaultStyle||null,this.styleAliases=Wge(e.styleAliases||null),Jge.indexOf(this.kind)===-1)throw new qK('Unknown kind "'+this.kind+'" is specified for "'+r+'" YAML type.')}JK.exports=zge});var Yl=w((CXe,zK)=>{"use strict";var WK=Gl(),nI=Qg(),Vge=si();function vS(r,e,t){var i=[];return r.include.forEach(function(n){t=vS(n,e,t)}),r[e].forEach(function(n){t.forEach(function(s,o){s.tag===n.tag&&s.kind===n.kind&&i.push(o)}),t.push(n)}),t.filter(function(n,s){return i.indexOf(s)===-1})}function Xge(){var r={scalar:{},sequence:{},mapping:{},fallback:{}},e,t;function i(n){r[n.kind][n.tag]=r.fallback[n.tag]=n}for(e=0,t=arguments.length;e{"use strict";var _ge=si();VK.exports=new _ge("tag:yaml.org,2002:str",{kind:"scalar",construct:function(r){return r!==null?r:""}})});var ZK=w((EXe,_K)=>{"use strict";var Zge=si();_K.exports=new Zge("tag:yaml.org,2002:seq",{kind:"sequence",construct:function(r){return r!==null?r:[]}})});var eU=w((IXe,$K)=>{"use strict";var $ge=si();$K.exports=new $ge("tag:yaml.org,2002:map",{kind:"mapping",construct:function(r){return r!==null?r:{}}})});var sI=w((yXe,tU)=>{"use strict";var efe=Yl();tU.exports=new efe({explicit:[XK(),ZK(),eU()]})});var iU=w((wXe,rU)=>{"use strict";var tfe=si();function rfe(r){if(r===null)return!0;var e=r.length;return e===1&&r==="~"||e===4&&(r==="null"||r==="Null"||r==="NULL")}function ife(){return null}function nfe(r){return r===null}rU.exports=new tfe("tag:yaml.org,2002:null",{kind:"scalar",resolve:rfe,construct:ife,predicate:nfe,represent:{canonical:function(){return"~"},lowercase:function(){return"null"},uppercase:function(){return"NULL"},camelcase:function(){return"Null"}},defaultStyle:"lowercase"})});var sU=w((BXe,nU)=>{"use strict";var sfe=si();function ofe(r){if(r===null)return!1;var e=r.length;return e===4&&(r==="true"||r==="True"||r==="TRUE")||e===5&&(r==="false"||r==="False"||r==="FALSE")}function afe(r){return r==="true"||r==="True"||r==="TRUE"}function Afe(r){return Object.prototype.toString.call(r)==="[object Boolean]"}nU.exports=new sfe("tag:yaml.org,2002:bool",{kind:"scalar",resolve:ofe,construct:afe,predicate:Afe,represent:{lowercase:function(r){return r?"true":"false"},uppercase:function(r){return r?"TRUE":"FALSE"},camelcase:function(r){return r?"True":"False"}},defaultStyle:"lowercase"})});var aU=w((QXe,oU)=>{"use strict";var lfe=Gl(),cfe=si();function ufe(r){return 48<=r&&r<=57||65<=r&&r<=70||97<=r&&r<=102}function gfe(r){return 48<=r&&r<=55}function ffe(r){return 48<=r&&r<=57}function hfe(r){if(r===null)return!1;var e=r.length,t=0,i=!1,n;if(!e)return!1;if(n=r[t],(n==="-"||n==="+")&&(n=r[++t]),n==="0"){if(t+1===e)return!0;if(n=r[++t],n==="b"){for(t++;t=0?"0b"+r.toString(2):"-0b"+r.toString(2).slice(1)},octal:function(r){return r>=0?"0"+r.toString(8):"-0"+r.toString(8).slice(1)},decimal:function(r){return r.toString(10)},hexadecimal:function(r){return r>=0?"0x"+r.toString(16).toUpperCase():"-0x"+r.toString(16).toUpperCase().slice(1)}},defaultStyle:"decimal",styleAliases:{binary:[2,"bin"],octal:[8,"oct"],decimal:[10,"dec"],hexadecimal:[16,"hex"]}})});var cU=w((bXe,lU)=>{"use strict";var AU=Gl(),Cfe=si(),mfe=new RegExp("^(?:[-+]?(?:0|[1-9][0-9_]*)(?:\\.[0-9_]*)?(?:[eE][-+]?[0-9]+)?|\\.[0-9_]+(?:[eE][-+]?[0-9]+)?|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*|[-+]?\\.(?:inf|Inf|INF)|\\.(?:nan|NaN|NAN))$");function Efe(r){return!(r===null||!mfe.test(r)||r[r.length-1]==="_")}function Ife(r){var e,t,i,n;return e=r.replace(/_/g,"").toLowerCase(),t=e[0]==="-"?-1:1,n=[],"+-".indexOf(e[0])>=0&&(e=e.slice(1)),e===".inf"?t===1?Number.POSITIVE_INFINITY:Number.NEGATIVE_INFINITY:e===".nan"?NaN:e.indexOf(":")>=0?(e.split(":").forEach(function(s){n.unshift(parseFloat(s,10))}),e=0,i=1,n.forEach(function(s){e+=s*i,i*=60}),t*e):t*parseFloat(e,10)}var yfe=/^[-+]?[0-9]+e/;function wfe(r,e){var t;if(isNaN(r))switch(e){case"lowercase":return".nan";case"uppercase":return".NAN";case"camelcase":return".NaN"}else if(Number.POSITIVE_INFINITY===r)switch(e){case"lowercase":return".inf";case"uppercase":return".INF";case"camelcase":return".Inf"}else if(Number.NEGATIVE_INFINITY===r)switch(e){case"lowercase":return"-.inf";case"uppercase":return"-.INF";case"camelcase":return"-.Inf"}else if(AU.isNegativeZero(r))return"-0.0";return t=r.toString(10),yfe.test(t)?t.replace("e",".e"):t}function Bfe(r){return Object.prototype.toString.call(r)==="[object Number]"&&(r%1!==0||AU.isNegativeZero(r))}lU.exports=new Cfe("tag:yaml.org,2002:float",{kind:"scalar",resolve:Efe,construct:Ife,predicate:Bfe,represent:wfe,defaultStyle:"lowercase"})});var xS=w((SXe,uU)=>{"use strict";var Qfe=Yl();uU.exports=new Qfe({include:[sI()],implicit:[iU(),sU(),aU(),cU()]})});var PS=w((vXe,gU)=>{"use strict";var bfe=Yl();gU.exports=new bfe({include:[xS()]})});var dU=w((xXe,pU)=>{"use strict";var Sfe=si(),fU=new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])$"),hU=new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)(?:[Tt]|[ \\t]+)([0-9][0-9]?):([0-9][0-9]):([0-9][0-9])(?:\\.([0-9]*))?(?:[ \\t]*(Z|([-+])([0-9][0-9]?)(?::([0-9][0-9]))?))?$");function vfe(r){return r===null?!1:fU.exec(r)!==null||hU.exec(r)!==null}function xfe(r){var e,t,i,n,s,o,a,l=0,c=null,u,g,f;if(e=fU.exec(r),e===null&&(e=hU.exec(r)),e===null)throw new Error("Date resolve error");if(t=+e[1],i=+e[2]-1,n=+e[3],!e[4])return new Date(Date.UTC(t,i,n));if(s=+e[4],o=+e[5],a=+e[6],e[7]){for(l=e[7].slice(0,3);l.length<3;)l+="0";l=+l}return e[9]&&(u=+e[10],g=+(e[11]||0),c=(u*60+g)*6e4,e[9]==="-"&&(c=-c)),f=new Date(Date.UTC(t,i,n,s,o,a,l)),c&&f.setTime(f.getTime()-c),f}function Pfe(r){return r.toISOString()}pU.exports=new Sfe("tag:yaml.org,2002:timestamp",{kind:"scalar",resolve:vfe,construct:xfe,instanceOf:Date,represent:Pfe})});var mU=w((PXe,CU)=>{"use strict";var Dfe=si();function kfe(r){return r==="<<"||r===null}CU.exports=new Dfe("tag:yaml.org,2002:merge",{kind:"scalar",resolve:kfe})});var yU=w((DXe,IU)=>{"use strict";var jl;try{EU=J,jl=EU("buffer").Buffer}catch{}var EU,Rfe=si(),DS=`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/= +\r`;function Ffe(r){if(r===null)return!1;var e,t,i=0,n=r.length,s=DS;for(t=0;t64)){if(e<0)return!1;i+=6}return i%8===0}function Nfe(r){var e,t,i=r.replace(/[\r\n=]/g,""),n=i.length,s=DS,o=0,a=[];for(e=0;e>16&255),a.push(o>>8&255),a.push(o&255)),o=o<<6|s.indexOf(i.charAt(e));return t=n%4*6,t===0?(a.push(o>>16&255),a.push(o>>8&255),a.push(o&255)):t===18?(a.push(o>>10&255),a.push(o>>2&255)):t===12&&a.push(o>>4&255),jl?jl.from?jl.from(a):new jl(a):a}function Lfe(r){var e="",t=0,i,n,s=r.length,o=DS;for(i=0;i>18&63],e+=o[t>>12&63],e+=o[t>>6&63],e+=o[t&63]),t=(t<<8)+r[i];return n=s%3,n===0?(e+=o[t>>18&63],e+=o[t>>12&63],e+=o[t>>6&63],e+=o[t&63]):n===2?(e+=o[t>>10&63],e+=o[t>>4&63],e+=o[t<<2&63],e+=o[64]):n===1&&(e+=o[t>>2&63],e+=o[t<<4&63],e+=o[64],e+=o[64]),e}function Tfe(r){return jl&&jl.isBuffer(r)}IU.exports=new Rfe("tag:yaml.org,2002:binary",{kind:"scalar",resolve:Ffe,construct:Nfe,predicate:Tfe,represent:Lfe})});var BU=w((kXe,wU)=>{"use strict";var Ofe=si(),Mfe=Object.prototype.hasOwnProperty,Kfe=Object.prototype.toString;function Ufe(r){if(r===null)return!0;var e=[],t,i,n,s,o,a=r;for(t=0,i=a.length;t{"use strict";var Gfe=si(),Yfe=Object.prototype.toString;function jfe(r){if(r===null)return!0;var e,t,i,n,s,o=r;for(s=new Array(o.length),e=0,t=o.length;e{"use strict";var Jfe=si(),Wfe=Object.prototype.hasOwnProperty;function zfe(r){if(r===null)return!0;var e,t=r;for(e in t)if(Wfe.call(t,e)&&t[e]!==null)return!1;return!0}function Vfe(r){return r!==null?r:{}}SU.exports=new Jfe("tag:yaml.org,2002:set",{kind:"mapping",resolve:zfe,construct:Vfe})});var Sg=w((NXe,xU)=>{"use strict";var Xfe=Yl();xU.exports=new Xfe({include:[PS()],implicit:[dU(),mU()],explicit:[yU(),BU(),bU(),vU()]})});var DU=w((LXe,PU)=>{"use strict";var _fe=si();function Zfe(){return!0}function $fe(){}function ehe(){return""}function the(r){return typeof r>"u"}PU.exports=new _fe("tag:yaml.org,2002:js/undefined",{kind:"scalar",resolve:Zfe,construct:$fe,predicate:the,represent:ehe})});var RU=w((TXe,kU)=>{"use strict";var rhe=si();function ihe(r){if(r===null||r.length===0)return!1;var e=r,t=/\/([gim]*)$/.exec(r),i="";return!(e[0]==="/"&&(t&&(i=t[1]),i.length>3||e[e.length-i.length-1]!=="/"))}function nhe(r){var e=r,t=/\/([gim]*)$/.exec(r),i="";return e[0]==="/"&&(t&&(i=t[1]),e=e.slice(1,e.length-i.length-1)),new RegExp(e,i)}function she(r){var e="/"+r.source+"/";return r.global&&(e+="g"),r.multiline&&(e+="m"),r.ignoreCase&&(e+="i"),e}function ohe(r){return Object.prototype.toString.call(r)==="[object RegExp]"}kU.exports=new rhe("tag:yaml.org,2002:js/regexp",{kind:"scalar",resolve:ihe,construct:nhe,predicate:ohe,represent:she})});var LU=w((OXe,NU)=>{"use strict";var oI;try{FU=J,oI=FU("esprima")}catch{typeof window<"u"&&(oI=window.esprima)}var FU,ahe=si();function Ahe(r){if(r===null)return!1;try{var e="("+r+")",t=oI.parse(e,{range:!0});return!(t.type!=="Program"||t.body.length!==1||t.body[0].type!=="ExpressionStatement"||t.body[0].expression.type!=="ArrowFunctionExpression"&&t.body[0].expression.type!=="FunctionExpression")}catch{return!1}}function lhe(r){var e="("+r+")",t=oI.parse(e,{range:!0}),i=[],n;if(t.type!=="Program"||t.body.length!==1||t.body[0].type!=="ExpressionStatement"||t.body[0].expression.type!=="ArrowFunctionExpression"&&t.body[0].expression.type!=="FunctionExpression")throw new Error("Failed to resolve function");return t.body[0].expression.params.forEach(function(s){i.push(s.name)}),n=t.body[0].expression.body.range,t.body[0].expression.body.type==="BlockStatement"?new Function(i,e.slice(n[0]+1,n[1]-1)):new Function(i,"return "+e.slice(n[0],n[1]))}function che(r){return r.toString()}function uhe(r){return Object.prototype.toString.call(r)==="[object Function]"}NU.exports=new ahe("tag:yaml.org,2002:js/function",{kind:"scalar",resolve:Ahe,construct:lhe,predicate:uhe,represent:che})});var Mp=w((MXe,OU)=>{"use strict";var TU=Yl();OU.exports=TU.DEFAULT=new TU({include:[Sg()],explicit:[DU(),RU(),LU()]})});var r2=w((KXe,Kp)=>{"use strict";var da=Gl(),jU=Qg(),ghe=jK(),qU=Sg(),fhe=Mp(),wA=Object.prototype.hasOwnProperty,aI=1,JU=2,WU=3,AI=4,kS=1,hhe=2,MU=3,phe=/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x84\x86-\x9F\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/,dhe=/[\x85\u2028\u2029]/,Che=/[,\[\]\{\}]/,zU=/^(?:!|!!|![a-z\-]+!)$/i,VU=/^(?:!|[^,\[\]\{\}])(?:%[0-9a-f]{2}|[0-9a-z\-#;\/\?:@&=\+\$,_\.!~\*'\(\)\[\]])*$/i;function KU(r){return Object.prototype.toString.call(r)}function Bo(r){return r===10||r===13}function Jl(r){return r===9||r===32}function un(r){return r===9||r===32||r===10||r===13}function vg(r){return r===44||r===91||r===93||r===123||r===125}function mhe(r){var e;return 48<=r&&r<=57?r-48:(e=r|32,97<=e&&e<=102?e-97+10:-1)}function Ehe(r){return r===120?2:r===117?4:r===85?8:0}function Ihe(r){return 48<=r&&r<=57?r-48:-1}function UU(r){return r===48?"\0":r===97?"\x07":r===98?"\b":r===116||r===9?" ":r===110?` +`:r===118?"\v":r===102?"\f":r===114?"\r":r===101?"\x1B":r===32?" ":r===34?'"':r===47?"/":r===92?"\\":r===78?"\x85":r===95?"\xA0":r===76?"\u2028":r===80?"\u2029":""}function yhe(r){return r<=65535?String.fromCharCode(r):String.fromCharCode((r-65536>>10)+55296,(r-65536&1023)+56320)}var XU=new Array(256),_U=new Array(256);for(ql=0;ql<256;ql++)XU[ql]=UU(ql)?1:0,_U[ql]=UU(ql);var ql;function whe(r,e){this.input=r,this.filename=e.filename||null,this.schema=e.schema||fhe,this.onWarning=e.onWarning||null,this.legacy=e.legacy||!1,this.json=e.json||!1,this.listener=e.listener||null,this.implicitTypes=this.schema.compiledImplicit,this.typeMap=this.schema.compiledTypeMap,this.length=r.length,this.position=0,this.line=0,this.lineStart=0,this.lineIndent=0,this.documents=[]}function ZU(r,e){return new jU(e,new ghe(r.filename,r.input,r.position,r.line,r.position-r.lineStart))}function ft(r,e){throw ZU(r,e)}function lI(r,e){r.onWarning&&r.onWarning.call(null,ZU(r,e))}var HU={YAML:function(e,t,i){var n,s,o;e.version!==null&&ft(e,"duplication of %YAML directive"),i.length!==1&&ft(e,"YAML directive accepts exactly one argument"),n=/^([0-9]+)\.([0-9]+)$/.exec(i[0]),n===null&&ft(e,"ill-formed argument of the YAML directive"),s=parseInt(n[1],10),o=parseInt(n[2],10),s!==1&&ft(e,"unacceptable YAML version of the document"),e.version=i[0],e.checkLineBreaks=o<2,o!==1&&o!==2&&lI(e,"unsupported YAML version of the document")},TAG:function(e,t,i){var n,s;i.length!==2&&ft(e,"TAG directive accepts exactly two arguments"),n=i[0],s=i[1],zU.test(n)||ft(e,"ill-formed tag handle (first argument) of the TAG directive"),wA.call(e.tagMap,n)&&ft(e,'there is a previously declared suffix for "'+n+'" tag handle'),VU.test(s)||ft(e,"ill-formed tag prefix (second argument) of the TAG directive"),e.tagMap[n]=s}};function yA(r,e,t,i){var n,s,o,a;if(e1&&(r.result+=da.repeat(` +`,e-1))}function Bhe(r,e,t){var i,n,s,o,a,l,c,u,g=r.kind,f=r.result,h;if(h=r.input.charCodeAt(r.position),un(h)||vg(h)||h===35||h===38||h===42||h===33||h===124||h===62||h===39||h===34||h===37||h===64||h===96||(h===63||h===45)&&(n=r.input.charCodeAt(r.position+1),un(n)||t&&vg(n)))return!1;for(r.kind="scalar",r.result="",s=o=r.position,a=!1;h!==0;){if(h===58){if(n=r.input.charCodeAt(r.position+1),un(n)||t&&vg(n))break}else if(h===35){if(i=r.input.charCodeAt(r.position-1),un(i))break}else{if(r.position===r.lineStart&&cI(r)||t&&vg(h))break;if(Bo(h))if(l=r.line,c=r.lineStart,u=r.lineIndent,zr(r,!1,-1),r.lineIndent>=e){a=!0,h=r.input.charCodeAt(r.position);continue}else{r.position=o,r.line=l,r.lineStart=c,r.lineIndent=u;break}}a&&(yA(r,s,o,!1),FS(r,r.line-l),s=o=r.position,a=!1),Jl(h)||(o=r.position+1),h=r.input.charCodeAt(++r.position)}return yA(r,s,o,!1),r.result?!0:(r.kind=g,r.result=f,!1)}function Qhe(r,e){var t,i,n;if(t=r.input.charCodeAt(r.position),t!==39)return!1;for(r.kind="scalar",r.result="",r.position++,i=n=r.position;(t=r.input.charCodeAt(r.position))!==0;)if(t===39)if(yA(r,i,r.position,!0),t=r.input.charCodeAt(++r.position),t===39)i=r.position,r.position++,n=r.position;else return!0;else Bo(t)?(yA(r,i,n,!0),FS(r,zr(r,!1,e)),i=n=r.position):r.position===r.lineStart&&cI(r)?ft(r,"unexpected end of the document within a single quoted scalar"):(r.position++,n=r.position);ft(r,"unexpected end of the stream within a single quoted scalar")}function bhe(r,e){var t,i,n,s,o,a;if(a=r.input.charCodeAt(r.position),a!==34)return!1;for(r.kind="scalar",r.result="",r.position++,t=i=r.position;(a=r.input.charCodeAt(r.position))!==0;){if(a===34)return yA(r,t,r.position,!0),r.position++,!0;if(a===92){if(yA(r,t,r.position,!0),a=r.input.charCodeAt(++r.position),Bo(a))zr(r,!1,e);else if(a<256&&XU[a])r.result+=_U[a],r.position++;else if((o=Ehe(a))>0){for(n=o,s=0;n>0;n--)a=r.input.charCodeAt(++r.position),(o=mhe(a))>=0?s=(s<<4)+o:ft(r,"expected hexadecimal character");r.result+=yhe(s),r.position++}else ft(r,"unknown escape sequence");t=i=r.position}else Bo(a)?(yA(r,t,i,!0),FS(r,zr(r,!1,e)),t=i=r.position):r.position===r.lineStart&&cI(r)?ft(r,"unexpected end of the document within a double quoted scalar"):(r.position++,i=r.position)}ft(r,"unexpected end of the stream within a double quoted scalar")}function She(r,e){var t=!0,i,n=r.tag,s,o=r.anchor,a,l,c,u,g,f={},h,p,C,y;if(y=r.input.charCodeAt(r.position),y===91)l=93,g=!1,s=[];else if(y===123)l=125,g=!0,s={};else return!1;for(r.anchor!==null&&(r.anchorMap[r.anchor]=s),y=r.input.charCodeAt(++r.position);y!==0;){if(zr(r,!0,e),y=r.input.charCodeAt(r.position),y===l)return r.position++,r.tag=n,r.anchor=o,r.kind=g?"mapping":"sequence",r.result=s,!0;t||ft(r,"missed comma between flow collection entries"),p=h=C=null,c=u=!1,y===63&&(a=r.input.charCodeAt(r.position+1),un(a)&&(c=u=!0,r.position++,zr(r,!0,e))),i=r.line,Pg(r,e,aI,!1,!0),p=r.tag,h=r.result,zr(r,!0,e),y=r.input.charCodeAt(r.position),(u||r.line===i)&&y===58&&(c=!0,y=r.input.charCodeAt(++r.position),zr(r,!0,e),Pg(r,e,aI,!1,!0),C=r.result),g?xg(r,s,f,p,h,C):c?s.push(xg(r,null,f,p,h,C)):s.push(h),zr(r,!0,e),y=r.input.charCodeAt(r.position),y===44?(t=!0,y=r.input.charCodeAt(++r.position)):t=!1}ft(r,"unexpected end of the stream within a flow collection")}function vhe(r,e){var t,i,n=kS,s=!1,o=!1,a=e,l=0,c=!1,u,g;if(g=r.input.charCodeAt(r.position),g===124)i=!1;else if(g===62)i=!0;else return!1;for(r.kind="scalar",r.result="";g!==0;)if(g=r.input.charCodeAt(++r.position),g===43||g===45)kS===n?n=g===43?MU:hhe:ft(r,"repeat of a chomping mode identifier");else if((u=Ihe(g))>=0)u===0?ft(r,"bad explicit indentation width of a block scalar; it cannot be less than one"):o?ft(r,"repeat of an indentation width identifier"):(a=e+u-1,o=!0);else break;if(Jl(g)){do g=r.input.charCodeAt(++r.position);while(Jl(g));if(g===35)do g=r.input.charCodeAt(++r.position);while(!Bo(g)&&g!==0)}for(;g!==0;){for(RS(r),r.lineIndent=0,g=r.input.charCodeAt(r.position);(!o||r.lineIndenta&&(a=r.lineIndent),Bo(g)){l++;continue}if(r.lineIndente)&&l!==0)ft(r,"bad indentation of a sequence entry");else if(r.lineIndente)&&(Pg(r,e,AI,!0,n)&&(p?f=r.result:h=r.result),p||(xg(r,c,u,g,f,h,s,o),g=f=h=null),zr(r,!0,-1),y=r.input.charCodeAt(r.position)),r.lineIndent>e&&y!==0)ft(r,"bad indentation of a mapping entry");else if(r.lineIndente?l=1:r.lineIndent===e?l=0:r.lineIndente?l=1:r.lineIndent===e?l=0:r.lineIndent tag; it should be "scalar", not "'+r.kind+'"'),g=0,f=r.implicitTypes.length;g tag; it should be "'+h.kind+'", not "'+r.kind+'"'),h.resolve(r.result)?(r.result=h.construct(r.result),r.anchor!==null&&(r.anchorMap[r.anchor]=r.result)):ft(r,"cannot resolve a node with !<"+r.tag+"> explicit tag")):ft(r,"unknown tag !<"+r.tag+">");return r.listener!==null&&r.listener("close",r),r.tag!==null||r.anchor!==null||u}function Rhe(r){var e=r.position,t,i,n,s=!1,o;for(r.version=null,r.checkLineBreaks=r.legacy,r.tagMap={},r.anchorMap={};(o=r.input.charCodeAt(r.position))!==0&&(zr(r,!0,-1),o=r.input.charCodeAt(r.position),!(r.lineIndent>0||o!==37));){for(s=!0,o=r.input.charCodeAt(++r.position),t=r.position;o!==0&&!un(o);)o=r.input.charCodeAt(++r.position);for(i=r.input.slice(t,r.position),n=[],i.length<1&&ft(r,"directive name must not be less than one character in length");o!==0;){for(;Jl(o);)o=r.input.charCodeAt(++r.position);if(o===35){do o=r.input.charCodeAt(++r.position);while(o!==0&&!Bo(o));break}if(Bo(o))break;for(t=r.position;o!==0&&!un(o);)o=r.input.charCodeAt(++r.position);n.push(r.input.slice(t,r.position))}o!==0&&RS(r),wA.call(HU,i)?HU[i](r,i,n):lI(r,'unknown document directive "'+i+'"')}if(zr(r,!0,-1),r.lineIndent===0&&r.input.charCodeAt(r.position)===45&&r.input.charCodeAt(r.position+1)===45&&r.input.charCodeAt(r.position+2)===45?(r.position+=3,zr(r,!0,-1)):s&&ft(r,"directives end mark is expected"),Pg(r,r.lineIndent-1,AI,!1,!0),zr(r,!0,-1),r.checkLineBreaks&&dhe.test(r.input.slice(e,r.position))&&lI(r,"non-ASCII line breaks are interpreted as content"),r.documents.push(r.result),r.position===r.lineStart&&cI(r)){r.input.charCodeAt(r.position)===46&&(r.position+=3,zr(r,!0,-1));return}if(r.position"u"&&(t=e,e=null);var i=$U(r,t);if(typeof e!="function")return i;for(var n=0,s=i.length;n"u"&&(t=e,e=null),e2(r,e,da.extend({schema:qU},t))}function Nhe(r,e){return t2(r,da.extend({schema:qU},e))}Kp.exports.loadAll=e2;Kp.exports.load=t2;Kp.exports.safeLoadAll=Fhe;Kp.exports.safeLoad=Nhe});var b2=w((UXe,OS)=>{"use strict";var Hp=Gl(),Gp=Qg(),Lhe=Mp(),The=Sg(),c2=Object.prototype.toString,u2=Object.prototype.hasOwnProperty,Ohe=9,Up=10,Mhe=13,Khe=32,Uhe=33,Hhe=34,g2=35,Ghe=37,Yhe=38,jhe=39,qhe=42,f2=44,Jhe=45,h2=58,Whe=61,zhe=62,Vhe=63,Xhe=64,p2=91,d2=93,_he=96,C2=123,Zhe=124,m2=125,Fi={};Fi[0]="\\0";Fi[7]="\\a";Fi[8]="\\b";Fi[9]="\\t";Fi[10]="\\n";Fi[11]="\\v";Fi[12]="\\f";Fi[13]="\\r";Fi[27]="\\e";Fi[34]='\\"';Fi[92]="\\\\";Fi[133]="\\N";Fi[160]="\\_";Fi[8232]="\\L";Fi[8233]="\\P";var $he=["y","Y","yes","Yes","YES","on","On","ON","n","N","no","No","NO","off","Off","OFF"];function epe(r,e){var t,i,n,s,o,a,l;if(e===null)return{};for(t={},i=Object.keys(e),n=0,s=i.length;n0?r.charCodeAt(s-1):null,f=f&&s2(o,a)}else{for(s=0;si&&r[g+1]!==" ",g=s);else if(!Dg(o))return uI;a=s>0?r.charCodeAt(s-1):null,f=f&&s2(o,a)}c=c||u&&s-g-1>i&&r[g+1]!==" "}return!l&&!c?f&&!n(r)?I2:y2:t>9&&E2(r)?uI:c?B2:w2}function ope(r,e,t,i){r.dump=function(){if(e.length===0)return"''";if(!r.noCompatMode&&$he.indexOf(e)!==-1)return"'"+e+"'";var n=r.indent*Math.max(1,t),s=r.lineWidth===-1?-1:Math.max(Math.min(r.lineWidth,40),r.lineWidth-n),o=i||r.flowLevel>-1&&t>=r.flowLevel;function a(l){return rpe(r,l)}switch(spe(e,o,r.indent,s,a)){case I2:return e;case y2:return"'"+e.replace(/'/g,"''")+"'";case w2:return"|"+o2(e,r.indent)+a2(n2(e,n));case B2:return">"+o2(e,r.indent)+a2(n2(ape(e,s),n));case uI:return'"'+Ape(e,s)+'"';default:throw new Gp("impossible error: invalid scalar style")}}()}function o2(r,e){var t=E2(r)?String(e):"",i=r[r.length-1]===` +`,n=i&&(r[r.length-2]===` +`||r===` +`),s=n?"+":i?"":"-";return t+s+` +`}function a2(r){return r[r.length-1]===` +`?r.slice(0,-1):r}function ape(r,e){for(var t=/(\n+)([^\n]*)/g,i=function(){var c=r.indexOf(` +`);return c=c!==-1?c:r.length,t.lastIndex=c,A2(r.slice(0,c),e)}(),n=r[0]===` +`||r[0]===" ",s,o;o=t.exec(r);){var a=o[1],l=o[2];s=l[0]===" ",i+=a+(!n&&!s&&l!==""?` +`:"")+A2(l,e),n=s}return i}function A2(r,e){if(r===""||r[0]===" ")return r;for(var t=/ [^ ]/g,i,n=0,s,o=0,a=0,l="";i=t.exec(r);)a=i.index,a-n>e&&(s=o>n?o:a,l+=` +`+r.slice(n,s),n=s+1),o=a;return l+=` +`,r.length-n>e&&o>n?l+=r.slice(n,o)+` +`+r.slice(o+1):l+=r.slice(n),l.slice(1)}function Ape(r){for(var e="",t,i,n,s=0;s=55296&&t<=56319&&(i=r.charCodeAt(s+1),i>=56320&&i<=57343)){e+=i2((t-55296)*1024+i-56320+65536),s++;continue}n=Fi[t],e+=!n&&Dg(t)?r[s]:n||i2(t)}return e}function lpe(r,e,t){var i="",n=r.tag,s,o;for(s=0,o=t.length;s1024&&(u+="? "),u+=r.dump+(r.condenseFlow?'"':"")+":"+(r.condenseFlow?"":" "),Wl(r,e,c,!1,!1)&&(u+=r.dump,i+=u));r.tag=n,r.dump="{"+i+"}"}function gpe(r,e,t,i){var n="",s=r.tag,o=Object.keys(t),a,l,c,u,g,f;if(r.sortKeys===!0)o.sort();else if(typeof r.sortKeys=="function")o.sort(r.sortKeys);else if(r.sortKeys)throw new Gp("sortKeys must be a boolean or a function");for(a=0,l=o.length;a1024,g&&(r.dump&&Up===r.dump.charCodeAt(0)?f+="?":f+="? "),f+=r.dump,g&&(f+=NS(r,e)),Wl(r,e+1,u,!0,g)&&(r.dump&&Up===r.dump.charCodeAt(0)?f+=":":f+=": ",f+=r.dump,n+=f));r.tag=s,r.dump=n||"{}"}function l2(r,e,t){var i,n,s,o,a,l;for(n=t?r.explicitTypes:r.implicitTypes,s=0,o=n.length;s tag resolver accepts not "'+l+'" style');r.dump=i}return!0}return!1}function Wl(r,e,t,i,n,s){r.tag=null,r.dump=t,l2(r,t,!1)||l2(r,t,!0);var o=c2.call(r.dump);i&&(i=r.flowLevel<0||r.flowLevel>e);var a=o==="[object Object]"||o==="[object Array]",l,c;if(a&&(l=r.duplicates.indexOf(t),c=l!==-1),(r.tag!==null&&r.tag!=="?"||c||r.indent!==2&&e>0)&&(n=!1),c&&r.usedDuplicates[l])r.dump="*ref_"+l;else{if(a&&c&&!r.usedDuplicates[l]&&(r.usedDuplicates[l]=!0),o==="[object Object]")i&&Object.keys(r.dump).length!==0?(gpe(r,e,r.dump,n),c&&(r.dump="&ref_"+l+r.dump)):(upe(r,e,r.dump),c&&(r.dump="&ref_"+l+" "+r.dump));else if(o==="[object Array]"){var u=r.noArrayIndent&&e>0?e-1:e;i&&r.dump.length!==0?(cpe(r,u,r.dump,n),c&&(r.dump="&ref_"+l+r.dump)):(lpe(r,u,r.dump),c&&(r.dump="&ref_"+l+" "+r.dump))}else if(o==="[object String]")r.tag!=="?"&&ope(r,r.dump,e,s);else{if(r.skipInvalid)return!1;throw new Gp("unacceptable kind of an object to dump "+o)}r.tag!==null&&r.tag!=="?"&&(r.dump="!<"+r.tag+"> "+r.dump)}return!0}function fpe(r,e){var t=[],i=[],n,s;for(LS(r,t,i),n=0,s=i.length;n{"use strict";var gI=r2(),S2=b2();function fI(r){return function(){throw new Error("Function "+r+" is deprecated and cannot be used.")}}Fr.exports.Type=si();Fr.exports.Schema=Yl();Fr.exports.FAILSAFE_SCHEMA=sI();Fr.exports.JSON_SCHEMA=xS();Fr.exports.CORE_SCHEMA=PS();Fr.exports.DEFAULT_SAFE_SCHEMA=Sg();Fr.exports.DEFAULT_FULL_SCHEMA=Mp();Fr.exports.load=gI.load;Fr.exports.loadAll=gI.loadAll;Fr.exports.safeLoad=gI.safeLoad;Fr.exports.safeLoadAll=gI.safeLoadAll;Fr.exports.dump=S2.dump;Fr.exports.safeDump=S2.safeDump;Fr.exports.YAMLException=Qg();Fr.exports.MINIMAL_SCHEMA=sI();Fr.exports.SAFE_SCHEMA=Sg();Fr.exports.DEFAULT_SCHEMA=Mp();Fr.exports.scan=fI("scan");Fr.exports.parse=fI("parse");Fr.exports.compose=fI("compose");Fr.exports.addConstructor=fI("addConstructor")});var P2=w((GXe,x2)=>{"use strict";var ppe=v2();x2.exports=ppe});var k2=w((YXe,D2)=>{"use strict";function dpe(r,e){function t(){this.constructor=r}t.prototype=e.prototype,r.prototype=new t}function zl(r,e,t,i){this.message=r,this.expected=e,this.found=t,this.location=i,this.name="SyntaxError",typeof Error.captureStackTrace=="function"&&Error.captureStackTrace(this,zl)}dpe(zl,Error);zl.buildMessage=function(r,e){var t={literal:function(c){return'"'+n(c.text)+'"'},class:function(c){var u="",g;for(g=0;g0){for(g=1,f=1;g({[Ke]:Ce})))},H=function(R){return R},j=function(R){return R},$=Ts("correct indentation"),V=" ",W=ar(" ",!1),Z=function(R){return R.length===pA*ug},A=function(R){return R.length===(pA+1)*ug},ae=function(){return pA++,!0},ge=function(){return pA--,!0},re=function(){return sg()},O=Ts("pseudostring"),F=/^[^\r\n\t ?:,\][{}#&*!|>'"%@`\-]/,ue=Rn(["\r",` +`," "," ","?",":",",","]","[","{","}","#","&","*","!","|",">","'",'"',"%","@","`","-"],!0,!1),he=/^[^\r\n\t ,\][{}:#"']/,ke=Rn(["\r",` +`," "," ",",","]","[","{","}",":","#",'"',"'"],!0,!1),Fe=function(){return sg().replace(/^ *| *$/g,"")},Ne="--",oe=ar("--",!1),le=/^[a-zA-Z\/0-9]/,we=Rn([["a","z"],["A","Z"],"/",["0","9"]],!1,!1),fe=/^[^\r\n\t :,]/,Ae=Rn(["\r",` +`," "," ",":",","],!0,!1),qe="null",ne=ar("null",!1),Y=function(){return null},pe="true",ie=ar("true",!1),de=function(){return!0},tt="false",Pt=ar("false",!1),It=function(){return!1},Or=Ts("string"),ii='"',gi=ar('"',!1),hr=function(){return""},fi=function(R){return R},ni=function(R){return R.join("")},Ls=/^[^"\\\0-\x1F\x7F]/,pr=Rn(['"',"\\",["\0",""],"\x7F"],!0,!1),Ei='\\"',_n=ar('\\"',!1),oa=function(){return'"'},aA="\\\\",eg=ar("\\\\",!1),Zn=function(){return"\\"},AA="\\/",aa=ar("\\/",!1),up=function(){return"/"},lA="\\b",cA=ar("\\b",!1),wr=function(){return"\b"},wl="\\f",tg=ar("\\f",!1),po=function(){return"\f"},rg="\\n",gp=ar("\\n",!1),fp=function(){return` +`},vr="\\r",se=ar("\\r",!1),Co=function(){return"\r"},Dn="\\t",ig=ar("\\t",!1),Qt=function(){return" "},Bl="\\u",kn=ar("\\u",!1),$n=function(R,q,Ce,Ke){return String.fromCharCode(parseInt(`0x${R}${q}${Ce}${Ke}`))},es=/^[0-9a-fA-F]/,gt=Rn([["0","9"],["a","f"],["A","F"]],!1,!1),mo=Ts("blank space"),At=/^[ \t]/,an=Rn([" "," "],!1,!1),S=Ts("white space"),Tt=/^[ \t\n\r]/,ng=Rn([" "," ",` +`,"\r"],!1,!1),Ql=`\r +`,hp=ar(`\r +`,!1),pp=` +`,dp=ar(` +`,!1),Cp="\r",mp=ar("\r",!1),G=0,yt=0,uA=[{line:1,column:1}],ji=0,bl=[],Xe=0,Aa;if("startRule"in e){if(!(e.startRule in i))throw new Error(`Can't start parsing from rule "`+e.startRule+'".');n=i[e.startRule]}function sg(){return r.substring(yt,G)}function bE(){return An(yt,G)}function Ep(R,q){throw q=q!==void 0?q:An(yt,G),vl([Ts(R)],r.substring(yt,G),q)}function SE(R,q){throw q=q!==void 0?q:An(yt,G),og(R,q)}function ar(R,q){return{type:"literal",text:R,ignoreCase:q}}function Rn(R,q,Ce){return{type:"class",parts:R,inverted:q,ignoreCase:Ce}}function Sl(){return{type:"any"}}function Ip(){return{type:"end"}}function Ts(R){return{type:"other",description:R}}function la(R){var q=uA[R],Ce;if(q)return q;for(Ce=R-1;!uA[Ce];)Ce--;for(q=uA[Ce],q={line:q.line,column:q.column};Ceji&&(ji=G,bl=[]),bl.push(R))}function og(R,q){return new zl(R,null,null,q)}function vl(R,q,Ce){return new zl(zl.buildMessage(R,q),R,q,Ce)}function Os(){var R;return R=ag(),R}function xl(){var R,q,Ce;for(R=G,q=[],Ce=gA();Ce!==t;)q.push(Ce),Ce=gA();return q!==t&&(yt=R,q=s(q)),R=q,R}function gA(){var R,q,Ce,Ke,Re;return R=G,q=ua(),q!==t?(r.charCodeAt(G)===45?(Ce=o,G++):(Ce=t,Xe===0&&Te(a)),Ce!==t?(Ke=Rr(),Ke!==t?(Re=ca(),Re!==t?(yt=R,q=l(Re),R=q):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)):(G=R,R=t),R}function ag(){var R,q,Ce;for(R=G,q=[],Ce=Ag();Ce!==t;)q.push(Ce),Ce=Ag();return q!==t&&(yt=R,q=c(q)),R=q,R}function Ag(){var R,q,Ce,Ke,Re,ze,dt,Ft,Fn;if(R=G,q=Rr(),q===t&&(q=null),q!==t){if(Ce=G,r.charCodeAt(G)===35?(Ke=u,G++):(Ke=t,Xe===0&&Te(g)),Ke!==t){if(Re=[],ze=G,dt=G,Xe++,Ft=Us(),Xe--,Ft===t?dt=void 0:(G=dt,dt=t),dt!==t?(r.length>G?(Ft=r.charAt(G),G++):(Ft=t,Xe===0&&Te(f)),Ft!==t?(dt=[dt,Ft],ze=dt):(G=ze,ze=t)):(G=ze,ze=t),ze!==t)for(;ze!==t;)Re.push(ze),ze=G,dt=G,Xe++,Ft=Us(),Xe--,Ft===t?dt=void 0:(G=dt,dt=t),dt!==t?(r.length>G?(Ft=r.charAt(G),G++):(Ft=t,Xe===0&&Te(f)),Ft!==t?(dt=[dt,Ft],ze=dt):(G=ze,ze=t)):(G=ze,ze=t);else Re=t;Re!==t?(Ke=[Ke,Re],Ce=Ke):(G=Ce,Ce=t)}else G=Ce,Ce=t;if(Ce===t&&(Ce=null),Ce!==t){if(Ke=[],Re=Ks(),Re!==t)for(;Re!==t;)Ke.push(Re),Re=Ks();else Ke=t;Ke!==t?(yt=R,q=h(),R=q):(G=R,R=t)}else G=R,R=t}else G=R,R=t;if(R===t&&(R=G,q=ua(),q!==t?(Ce=Pl(),Ce!==t?(Ke=Rr(),Ke===t&&(Ke=null),Ke!==t?(r.charCodeAt(G)===58?(Re=p,G++):(Re=t,Xe===0&&Te(C)),Re!==t?(ze=Rr(),ze===t&&(ze=null),ze!==t?(dt=ca(),dt!==t?(yt=R,q=y(Ce,dt),R=q):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)):(G=R,R=t),R===t&&(R=G,q=ua(),q!==t?(Ce=Ms(),Ce!==t?(Ke=Rr(),Ke===t&&(Ke=null),Ke!==t?(r.charCodeAt(G)===58?(Re=p,G++):(Re=t,Xe===0&&Te(C)),Re!==t?(ze=Rr(),ze===t&&(ze=null),ze!==t?(dt=ca(),dt!==t?(yt=R,q=y(Ce,dt),R=q):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)):(G=R,R=t),R===t))){if(R=G,q=ua(),q!==t)if(Ce=Ms(),Ce!==t)if(Ke=Rr(),Ke!==t)if(Re=vE(),Re!==t){if(ze=[],dt=Ks(),dt!==t)for(;dt!==t;)ze.push(dt),dt=Ks();else ze=t;ze!==t?(yt=R,q=y(Ce,Re),R=q):(G=R,R=t)}else G=R,R=t;else G=R,R=t;else G=R,R=t;else G=R,R=t;if(R===t)if(R=G,q=ua(),q!==t)if(Ce=Ms(),Ce!==t){if(Ke=[],Re=G,ze=Rr(),ze===t&&(ze=null),ze!==t?(r.charCodeAt(G)===44?(dt=B,G++):(dt=t,Xe===0&&Te(v)),dt!==t?(Ft=Rr(),Ft===t&&(Ft=null),Ft!==t?(Fn=Ms(),Fn!==t?(yt=Re,ze=D(Ce,Fn),Re=ze):(G=Re,Re=t)):(G=Re,Re=t)):(G=Re,Re=t)):(G=Re,Re=t),Re!==t)for(;Re!==t;)Ke.push(Re),Re=G,ze=Rr(),ze===t&&(ze=null),ze!==t?(r.charCodeAt(G)===44?(dt=B,G++):(dt=t,Xe===0&&Te(v)),dt!==t?(Ft=Rr(),Ft===t&&(Ft=null),Ft!==t?(Fn=Ms(),Fn!==t?(yt=Re,ze=D(Ce,Fn),Re=ze):(G=Re,Re=t)):(G=Re,Re=t)):(G=Re,Re=t)):(G=Re,Re=t);else Ke=t;Ke!==t?(Re=Rr(),Re===t&&(Re=null),Re!==t?(r.charCodeAt(G)===58?(ze=p,G++):(ze=t,Xe===0&&Te(C)),ze!==t?(dt=Rr(),dt===t&&(dt=null),dt!==t?(Ft=ca(),Ft!==t?(yt=R,q=L(Ce,Ke,Ft),R=q):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)}else G=R,R=t;else G=R,R=t}return R}function ca(){var R,q,Ce,Ke,Re,ze,dt;if(R=G,q=G,Xe++,Ce=G,Ke=Us(),Ke!==t?(Re=rt(),Re!==t?(r.charCodeAt(G)===45?(ze=o,G++):(ze=t,Xe===0&&Te(a)),ze!==t?(dt=Rr(),dt!==t?(Ke=[Ke,Re,ze,dt],Ce=Ke):(G=Ce,Ce=t)):(G=Ce,Ce=t)):(G=Ce,Ce=t)):(G=Ce,Ce=t),Xe--,Ce!==t?(G=q,q=void 0):q=t,q!==t?(Ce=Ks(),Ce!==t?(Ke=Eo(),Ke!==t?(Re=xl(),Re!==t?(ze=fA(),ze!==t?(yt=R,q=H(Re),R=q):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)):(G=R,R=t),R===t&&(R=G,q=Us(),q!==t?(Ce=Eo(),Ce!==t?(Ke=ag(),Ke!==t?(Re=fA(),Re!==t?(yt=R,q=H(Ke),R=q):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)):(G=R,R=t),R===t))if(R=G,q=Dl(),q!==t){if(Ce=[],Ke=Ks(),Ke!==t)for(;Ke!==t;)Ce.push(Ke),Ke=Ks();else Ce=t;Ce!==t?(yt=R,q=j(q),R=q):(G=R,R=t)}else G=R,R=t;return R}function ua(){var R,q,Ce;for(Xe++,R=G,q=[],r.charCodeAt(G)===32?(Ce=V,G++):(Ce=t,Xe===0&&Te(W));Ce!==t;)q.push(Ce),r.charCodeAt(G)===32?(Ce=V,G++):(Ce=t,Xe===0&&Te(W));return q!==t?(yt=G,Ce=Z(q),Ce?Ce=void 0:Ce=t,Ce!==t?(q=[q,Ce],R=q):(G=R,R=t)):(G=R,R=t),Xe--,R===t&&(q=t,Xe===0&&Te($)),R}function rt(){var R,q,Ce;for(R=G,q=[],r.charCodeAt(G)===32?(Ce=V,G++):(Ce=t,Xe===0&&Te(W));Ce!==t;)q.push(Ce),r.charCodeAt(G)===32?(Ce=V,G++):(Ce=t,Xe===0&&Te(W));return q!==t?(yt=G,Ce=A(q),Ce?Ce=void 0:Ce=t,Ce!==t?(q=[q,Ce],R=q):(G=R,R=t)):(G=R,R=t),R}function Eo(){var R;return yt=G,R=ae(),R?R=void 0:R=t,R}function fA(){var R;return yt=G,R=ge(),R?R=void 0:R=t,R}function Pl(){var R;return R=kl(),R===t&&(R=yp()),R}function Ms(){var R,q,Ce;if(R=kl(),R===t){if(R=G,q=[],Ce=lg(),Ce!==t)for(;Ce!==t;)q.push(Ce),Ce=lg();else q=t;q!==t&&(yt=R,q=re()),R=q}return R}function Dl(){var R;return R=wp(),R===t&&(R=xE(),R===t&&(R=kl(),R===t&&(R=yp()))),R}function vE(){var R;return R=wp(),R===t&&(R=kl(),R===t&&(R=lg())),R}function yp(){var R,q,Ce,Ke,Re,ze;if(Xe++,R=G,F.test(r.charAt(G))?(q=r.charAt(G),G++):(q=t,Xe===0&&Te(ue)),q!==t){for(Ce=[],Ke=G,Re=Rr(),Re===t&&(Re=null),Re!==t?(he.test(r.charAt(G))?(ze=r.charAt(G),G++):(ze=t,Xe===0&&Te(ke)),ze!==t?(Re=[Re,ze],Ke=Re):(G=Ke,Ke=t)):(G=Ke,Ke=t);Ke!==t;)Ce.push(Ke),Ke=G,Re=Rr(),Re===t&&(Re=null),Re!==t?(he.test(r.charAt(G))?(ze=r.charAt(G),G++):(ze=t,Xe===0&&Te(ke)),ze!==t?(Re=[Re,ze],Ke=Re):(G=Ke,Ke=t)):(G=Ke,Ke=t);Ce!==t?(yt=R,q=Fe(),R=q):(G=R,R=t)}else G=R,R=t;return Xe--,R===t&&(q=t,Xe===0&&Te(O)),R}function lg(){var R,q,Ce,Ke,Re;if(R=G,r.substr(G,2)===Ne?(q=Ne,G+=2):(q=t,Xe===0&&Te(oe)),q===t&&(q=null),q!==t)if(le.test(r.charAt(G))?(Ce=r.charAt(G),G++):(Ce=t,Xe===0&&Te(we)),Ce!==t){for(Ke=[],fe.test(r.charAt(G))?(Re=r.charAt(G),G++):(Re=t,Xe===0&&Te(Ae));Re!==t;)Ke.push(Re),fe.test(r.charAt(G))?(Re=r.charAt(G),G++):(Re=t,Xe===0&&Te(Ae));Ke!==t?(yt=R,q=Fe(),R=q):(G=R,R=t)}else G=R,R=t;else G=R,R=t;return R}function wp(){var R,q;return R=G,r.substr(G,4)===qe?(q=qe,G+=4):(q=t,Xe===0&&Te(ne)),q!==t&&(yt=R,q=Y()),R=q,R}function xE(){var R,q;return R=G,r.substr(G,4)===pe?(q=pe,G+=4):(q=t,Xe===0&&Te(ie)),q!==t&&(yt=R,q=de()),R=q,R===t&&(R=G,r.substr(G,5)===tt?(q=tt,G+=5):(q=t,Xe===0&&Te(Pt)),q!==t&&(yt=R,q=It()),R=q),R}function kl(){var R,q,Ce,Ke;return Xe++,R=G,r.charCodeAt(G)===34?(q=ii,G++):(q=t,Xe===0&&Te(gi)),q!==t?(r.charCodeAt(G)===34?(Ce=ii,G++):(Ce=t,Xe===0&&Te(gi)),Ce!==t?(yt=R,q=hr(),R=q):(G=R,R=t)):(G=R,R=t),R===t&&(R=G,r.charCodeAt(G)===34?(q=ii,G++):(q=t,Xe===0&&Te(gi)),q!==t?(Ce=PE(),Ce!==t?(r.charCodeAt(G)===34?(Ke=ii,G++):(Ke=t,Xe===0&&Te(gi)),Ke!==t?(yt=R,q=fi(Ce),R=q):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)),Xe--,R===t&&(q=t,Xe===0&&Te(Or)),R}function PE(){var R,q,Ce;if(R=G,q=[],Ce=cg(),Ce!==t)for(;Ce!==t;)q.push(Ce),Ce=cg();else q=t;return q!==t&&(yt=R,q=ni(q)),R=q,R}function cg(){var R,q,Ce,Ke,Re,ze;return Ls.test(r.charAt(G))?(R=r.charAt(G),G++):(R=t,Xe===0&&Te(pr)),R===t&&(R=G,r.substr(G,2)===Ei?(q=Ei,G+=2):(q=t,Xe===0&&Te(_n)),q!==t&&(yt=R,q=oa()),R=q,R===t&&(R=G,r.substr(G,2)===aA?(q=aA,G+=2):(q=t,Xe===0&&Te(eg)),q!==t&&(yt=R,q=Zn()),R=q,R===t&&(R=G,r.substr(G,2)===AA?(q=AA,G+=2):(q=t,Xe===0&&Te(aa)),q!==t&&(yt=R,q=up()),R=q,R===t&&(R=G,r.substr(G,2)===lA?(q=lA,G+=2):(q=t,Xe===0&&Te(cA)),q!==t&&(yt=R,q=wr()),R=q,R===t&&(R=G,r.substr(G,2)===wl?(q=wl,G+=2):(q=t,Xe===0&&Te(tg)),q!==t&&(yt=R,q=po()),R=q,R===t&&(R=G,r.substr(G,2)===rg?(q=rg,G+=2):(q=t,Xe===0&&Te(gp)),q!==t&&(yt=R,q=fp()),R=q,R===t&&(R=G,r.substr(G,2)===vr?(q=vr,G+=2):(q=t,Xe===0&&Te(se)),q!==t&&(yt=R,q=Co()),R=q,R===t&&(R=G,r.substr(G,2)===Dn?(q=Dn,G+=2):(q=t,Xe===0&&Te(ig)),q!==t&&(yt=R,q=Qt()),R=q,R===t&&(R=G,r.substr(G,2)===Bl?(q=Bl,G+=2):(q=t,Xe===0&&Te(kn)),q!==t?(Ce=hA(),Ce!==t?(Ke=hA(),Ke!==t?(Re=hA(),Re!==t?(ze=hA(),ze!==t?(yt=R,q=$n(Ce,Ke,Re,ze),R=q):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)):(G=R,R=t)))))))))),R}function hA(){var R;return es.test(r.charAt(G))?(R=r.charAt(G),G++):(R=t,Xe===0&&Te(gt)),R}function Rr(){var R,q;if(Xe++,R=[],At.test(r.charAt(G))?(q=r.charAt(G),G++):(q=t,Xe===0&&Te(an)),q!==t)for(;q!==t;)R.push(q),At.test(r.charAt(G))?(q=r.charAt(G),G++):(q=t,Xe===0&&Te(an));else R=t;return Xe--,R===t&&(q=t,Xe===0&&Te(mo)),R}function DE(){var R,q;if(Xe++,R=[],Tt.test(r.charAt(G))?(q=r.charAt(G),G++):(q=t,Xe===0&&Te(ng)),q!==t)for(;q!==t;)R.push(q),Tt.test(r.charAt(G))?(q=r.charAt(G),G++):(q=t,Xe===0&&Te(ng));else R=t;return Xe--,R===t&&(q=t,Xe===0&&Te(S)),R}function Ks(){var R,q,Ce,Ke,Re,ze;if(R=G,q=Us(),q!==t){for(Ce=[],Ke=G,Re=Rr(),Re===t&&(Re=null),Re!==t?(ze=Us(),ze!==t?(Re=[Re,ze],Ke=Re):(G=Ke,Ke=t)):(G=Ke,Ke=t);Ke!==t;)Ce.push(Ke),Ke=G,Re=Rr(),Re===t&&(Re=null),Re!==t?(ze=Us(),ze!==t?(Re=[Re,ze],Ke=Re):(G=Ke,Ke=t)):(G=Ke,Ke=t);Ce!==t?(q=[q,Ce],R=q):(G=R,R=t)}else G=R,R=t;return R}function Us(){var R;return r.substr(G,2)===Ql?(R=Ql,G+=2):(R=t,Xe===0&&Te(hp)),R===t&&(r.charCodeAt(G)===10?(R=pp,G++):(R=t,Xe===0&&Te(dp)),R===t&&(r.charCodeAt(G)===13?(R=Cp,G++):(R=t,Xe===0&&Te(mp)))),R}let ug=2,pA=0;if(Aa=n(),Aa!==t&&G===r.length)return Aa;throw Aa!==t&&G{"use strict";var wpe=r=>{let e=!1,t=!1,i=!1;for(let n=0;n{if(!(typeof r=="string"||Array.isArray(r)))throw new TypeError("Expected the input to be `string | string[]`");e=Object.assign({pascalCase:!1},e);let t=n=>e.pascalCase?n.charAt(0).toUpperCase()+n.slice(1):n;return Array.isArray(r)?r=r.map(n=>n.trim()).filter(n=>n.length).join("-"):r=r.trim(),r.length===0?"":r.length===1?e.pascalCase?r.toUpperCase():r.toLowerCase():(r!==r.toLowerCase()&&(r=wpe(r)),r=r.replace(/^[_.\- ]+/,"").toLowerCase().replace(/[_.\- ]+(\w|$)/g,(n,s)=>s.toUpperCase()).replace(/\d+(\w|$)/g,n=>n.toUpperCase()),t(r))};KS.exports=T2;KS.exports.default=T2});var M2=w((VXe,Bpe)=>{Bpe.exports=[{name:"AppVeyor",constant:"APPVEYOR",env:"APPVEYOR",pr:"APPVEYOR_PULL_REQUEST_NUMBER"},{name:"Azure Pipelines",constant:"AZURE_PIPELINES",env:"SYSTEM_TEAMFOUNDATIONCOLLECTIONURI",pr:"SYSTEM_PULLREQUEST_PULLREQUESTID"},{name:"Appcircle",constant:"APPCIRCLE",env:"AC_APPCIRCLE"},{name:"Bamboo",constant:"BAMBOO",env:"bamboo_planKey"},{name:"Bitbucket Pipelines",constant:"BITBUCKET",env:"BITBUCKET_COMMIT",pr:"BITBUCKET_PR_ID"},{name:"Bitrise",constant:"BITRISE",env:"BITRISE_IO",pr:"BITRISE_PULL_REQUEST"},{name:"Buddy",constant:"BUDDY",env:"BUDDY_WORKSPACE_ID",pr:"BUDDY_EXECUTION_PULL_REQUEST_ID"},{name:"Buildkite",constant:"BUILDKITE",env:"BUILDKITE",pr:{env:"BUILDKITE_PULL_REQUEST",ne:"false"}},{name:"CircleCI",constant:"CIRCLE",env:"CIRCLECI",pr:"CIRCLE_PULL_REQUEST"},{name:"Cirrus CI",constant:"CIRRUS",env:"CIRRUS_CI",pr:"CIRRUS_PR"},{name:"AWS CodeBuild",constant:"CODEBUILD",env:"CODEBUILD_BUILD_ARN"},{name:"Codefresh",constant:"CODEFRESH",env:"CF_BUILD_ID",pr:{any:["CF_PULL_REQUEST_NUMBER","CF_PULL_REQUEST_ID"]}},{name:"Codeship",constant:"CODESHIP",env:{CI_NAME:"codeship"}},{name:"Drone",constant:"DRONE",env:"DRONE",pr:{DRONE_BUILD_EVENT:"pull_request"}},{name:"dsari",constant:"DSARI",env:"DSARI"},{name:"GitHub Actions",constant:"GITHUB_ACTIONS",env:"GITHUB_ACTIONS",pr:{GITHUB_EVENT_NAME:"pull_request"}},{name:"GitLab CI",constant:"GITLAB",env:"GITLAB_CI",pr:"CI_MERGE_REQUEST_ID"},{name:"GoCD",constant:"GOCD",env:"GO_PIPELINE_LABEL"},{name:"LayerCI",constant:"LAYERCI",env:"LAYERCI",pr:"LAYERCI_PULL_REQUEST"},{name:"Hudson",constant:"HUDSON",env:"HUDSON_URL"},{name:"Jenkins",constant:"JENKINS",env:["JENKINS_URL","BUILD_ID"],pr:{any:["ghprbPullId","CHANGE_ID"]}},{name:"Magnum CI",constant:"MAGNUM",env:"MAGNUM"},{name:"Netlify CI",constant:"NETLIFY",env:"NETLIFY",pr:{env:"PULL_REQUEST",ne:"false"}},{name:"Nevercode",constant:"NEVERCODE",env:"NEVERCODE",pr:{env:"NEVERCODE_PULL_REQUEST",ne:"false"}},{name:"Render",constant:"RENDER",env:"RENDER",pr:{IS_PULL_REQUEST:"true"}},{name:"Sail CI",constant:"SAIL",env:"SAILCI",pr:"SAIL_PULL_REQUEST_NUMBER"},{name:"Semaphore",constant:"SEMAPHORE",env:"SEMAPHORE",pr:"PULL_REQUEST_NUMBER"},{name:"Screwdriver",constant:"SCREWDRIVER",env:"SCREWDRIVER",pr:{env:"SD_PULL_REQUEST",ne:"false"}},{name:"Shippable",constant:"SHIPPABLE",env:"SHIPPABLE",pr:{IS_PULL_REQUEST:"true"}},{name:"Solano CI",constant:"SOLANO",env:"TDDIUM",pr:"TDDIUM_PR_ID"},{name:"Strider CD",constant:"STRIDER",env:"STRIDER"},{name:"TaskCluster",constant:"TASKCLUSTER",env:["TASK_ID","RUN_ID"]},{name:"TeamCity",constant:"TEAMCITY",env:"TEAMCITY_VERSION"},{name:"Travis CI",constant:"TRAVIS",env:"TRAVIS",pr:{env:"TRAVIS_PULL_REQUEST",ne:"false"}},{name:"Vercel",constant:"VERCEL",env:"NOW_BUILDER"},{name:"Visual Studio App Center",constant:"APPCENTER",env:"APPCENTER_BUILD_ID"}]});var Vl=w(On=>{"use strict";var U2=M2(),Qo=process.env;Object.defineProperty(On,"_vendors",{value:U2.map(function(r){return r.constant})});On.name=null;On.isPR=null;U2.forEach(function(r){let t=(Array.isArray(r.env)?r.env:[r.env]).every(function(i){return K2(i)});if(On[r.constant]=t,t)switch(On.name=r.name,typeof r.pr){case"string":On.isPR=!!Qo[r.pr];break;case"object":"env"in r.pr?On.isPR=r.pr.env in Qo&&Qo[r.pr.env]!==r.pr.ne:"any"in r.pr?On.isPR=r.pr.any.some(function(i){return!!Qo[i]}):On.isPR=K2(r.pr);break;default:On.isPR=null}});On.isCI=!!(Qo.CI||Qo.CONTINUOUS_INTEGRATION||Qo.BUILD_NUMBER||Qo.RUN_ID||On.name);function K2(r){return typeof r=="string"?!!Qo[r]:Object.keys(r).every(function(e){return Qo[e]===r[e]})}});var gn={};ut(gn,{KeyRelationship:()=>Xl,applyCascade:()=>zp,base64RegExp:()=>q2,colorStringAlphaRegExp:()=>j2,colorStringRegExp:()=>Y2,computeKey:()=>BA,getPrintable:()=>Vr,hasExactLength:()=>X2,hasForbiddenKeys:()=>tde,hasKeyRelationship:()=>JS,hasMaxLength:()=>Mpe,hasMinLength:()=>Ope,hasMutuallyExclusiveKeys:()=>rde,hasRequiredKeys:()=>ede,hasUniqueItems:()=>Kpe,isArray:()=>Ppe,isAtLeast:()=>Gpe,isAtMost:()=>Ype,isBase64:()=>Zpe,isBoolean:()=>Spe,isDate:()=>xpe,isDict:()=>kpe,isEnum:()=>Wi,isHexColor:()=>_pe,isISO8601:()=>Xpe,isInExclusiveRange:()=>qpe,isInInclusiveRange:()=>jpe,isInstanceOf:()=>Fpe,isInteger:()=>Jpe,isJSON:()=>$pe,isLiteral:()=>Qpe,isLowerCase:()=>Wpe,isNegative:()=>Upe,isNullable:()=>Tpe,isNumber:()=>vpe,isObject:()=>Rpe,isOneOf:()=>Npe,isOptional:()=>Lpe,isPositive:()=>Hpe,isString:()=>Wp,isTuple:()=>Dpe,isUUID4:()=>Vpe,isUnknown:()=>V2,isUpperCase:()=>zpe,iso8601RegExp:()=>qS,makeCoercionFn:()=>_l,makeSetter:()=>z2,makeTrait:()=>W2,makeValidator:()=>bt,matchesRegExp:()=>Vp,plural:()=>EI,pushError:()=>pt,simpleKeyRegExp:()=>G2,uuid4RegExp:()=>J2});function bt({test:r}){return W2(r)()}function Vr(r){return r===null?"null":r===void 0?"undefined":r===""?"an empty string":JSON.stringify(r)}function BA(r,e){var t,i,n;return typeof e=="number"?`${(t=r==null?void 0:r.p)!==null&&t!==void 0?t:"."}[${e}]`:G2.test(e)?`${(i=r==null?void 0:r.p)!==null&&i!==void 0?i:""}.${e}`:`${(n=r==null?void 0:r.p)!==null&&n!==void 0?n:"."}[${JSON.stringify(e)}]`}function _l(r,e){return t=>{let i=r[e];return r[e]=t,_l(r,e).bind(null,i)}}function z2(r,e){return t=>{r[e]=t}}function EI(r,e,t){return r===1?e:t}function pt({errors:r,p:e}={},t){return r==null||r.push(`${e!=null?e:"."}: ${t}`),!1}function Qpe(r){return bt({test:(e,t)=>e!==r?pt(t,`Expected a literal (got ${Vr(r)})`):!0})}function Wi(r){let e=Array.isArray(r)?r:Object.values(r),t=new Set(e);return bt({test:(i,n)=>t.has(i)?!0:pt(n,`Expected a valid enumeration value (got ${Vr(i)})`)})}var G2,Y2,j2,q2,J2,qS,W2,V2,Wp,bpe,Spe,vpe,xpe,Ppe,Dpe,kpe,Rpe,Fpe,Npe,zp,Lpe,Tpe,Ope,Mpe,X2,Kpe,Upe,Hpe,Gpe,Ype,jpe,qpe,Jpe,Vp,Wpe,zpe,Vpe,Xpe,_pe,Zpe,$pe,ede,tde,rde,Xl,ide,JS,ns=Yue(()=>{G2=/^[a-zA-Z_][a-zA-Z0-9_]*$/,Y2=/^#[0-9a-f]{6}$/i,j2=/^#[0-9a-f]{6}([0-9a-f]{2})?$/i,q2=/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/,J2=/^[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}$/i,qS=/^(?:[1-9]\d{3}(-?)(?:(?:0[1-9]|1[0-2])\1(?:0[1-9]|1\d|2[0-8])|(?:0[13-9]|1[0-2])\1(?:29|30)|(?:0[13578]|1[02])(?:\1)31|00[1-9]|0[1-9]\d|[12]\d{2}|3(?:[0-5]\d|6[0-5]))|(?:[1-9]\d(?:0[48]|[2468][048]|[13579][26])|(?:[2468][048]|[13579][26])00)(?:(-?)02(?:\2)29|-?366))T(?:[01]\d|2[0-3])(:?)[0-5]\d(?:\3[0-5]\d)?(?:Z|[+-][01]\d(?:\3[0-5]\d)?)$/,W2=r=>()=>r;V2=()=>bt({test:(r,e)=>!0});Wp=()=>bt({test:(r,e)=>typeof r!="string"?pt(e,`Expected a string (got ${Vr(r)})`):!0});bpe=new Map([["true",!0],["True",!0],["1",!0],[1,!0],["false",!1],["False",!1],["0",!1],[0,!1]]),Spe=()=>bt({test:(r,e)=>{var t;if(typeof r!="boolean"){if(typeof(e==null?void 0:e.coercions)<"u"){if(typeof(e==null?void 0:e.coercion)>"u")return pt(e,"Unbound coercion result");let i=bpe.get(r);if(typeof i<"u")return e.coercions.push([(t=e.p)!==null&&t!==void 0?t:".",e.coercion.bind(null,i)]),!0}return pt(e,`Expected a boolean (got ${Vr(r)})`)}return!0}}),vpe=()=>bt({test:(r,e)=>{var t;if(typeof r!="number"){if(typeof(e==null?void 0:e.coercions)<"u"){if(typeof(e==null?void 0:e.coercion)>"u")return pt(e,"Unbound coercion result");let i;if(typeof r=="string"){let n;try{n=JSON.parse(r)}catch{}if(typeof n=="number")if(JSON.stringify(n)===r)i=n;else return pt(e,`Received a number that can't be safely represented by the runtime (${r})`)}if(typeof i<"u")return e.coercions.push([(t=e.p)!==null&&t!==void 0?t:".",e.coercion.bind(null,i)]),!0}return pt(e,`Expected a number (got ${Vr(r)})`)}return!0}}),xpe=()=>bt({test:(r,e)=>{var t;if(!(r instanceof Date)){if(typeof(e==null?void 0:e.coercions)<"u"){if(typeof(e==null?void 0:e.coercion)>"u")return pt(e,"Unbound coercion result");let i;if(typeof r=="string"&&qS.test(r))i=new Date(r);else{let n;if(typeof r=="string"){let s;try{s=JSON.parse(r)}catch{}typeof s=="number"&&(n=s)}else typeof r=="number"&&(n=r);if(typeof n<"u")if(Number.isSafeInteger(n)||!Number.isSafeInteger(n*1e3))i=new Date(n*1e3);else return pt(e,`Received a timestamp that can't be safely represented by the runtime (${r})`)}if(typeof i<"u")return e.coercions.push([(t=e.p)!==null&&t!==void 0?t:".",e.coercion.bind(null,i)]),!0}return pt(e,`Expected a date (got ${Vr(r)})`)}return!0}}),Ppe=(r,{delimiter:e}={})=>bt({test:(t,i)=>{var n;if(typeof t=="string"&&typeof e<"u"&&typeof(i==null?void 0:i.coercions)<"u"){if(typeof(i==null?void 0:i.coercion)>"u")return pt(i,"Unbound coercion result");t=t.split(e),i.coercions.push([(n=i.p)!==null&&n!==void 0?n:".",i.coercion.bind(null,t)])}if(!Array.isArray(t))return pt(i,`Expected an array (got ${Vr(t)})`);let s=!0;for(let o=0,a=t.length;o{let t=X2(r.length);return bt({test:(i,n)=>{var s;if(typeof i=="string"&&typeof e<"u"&&typeof(n==null?void 0:n.coercions)<"u"){if(typeof(n==null?void 0:n.coercion)>"u")return pt(n,"Unbound coercion result");i=i.split(e),n.coercions.push([(s=n.p)!==null&&s!==void 0?s:".",n.coercion.bind(null,i)])}if(!Array.isArray(i))return pt(n,`Expected a tuple (got ${Vr(i)})`);let o=t(i,Object.assign({},n));for(let a=0,l=i.length;abt({test:(t,i)=>{if(typeof t!="object"||t===null)return pt(i,`Expected an object (got ${Vr(t)})`);let n=Object.keys(t),s=!0;for(let o=0,a=n.length;o{let t=Object.keys(r);return bt({test:(i,n)=>{if(typeof i!="object"||i===null)return pt(n,`Expected an object (got ${Vr(i)})`);let s=new Set([...t,...Object.keys(i)]),o={},a=!0;for(let l of s){if(l==="constructor"||l==="__proto__")a=pt(Object.assign(Object.assign({},n),{p:BA(n,l)}),"Unsafe property name");else{let c=Object.prototype.hasOwnProperty.call(r,l)?r[l]:void 0,u=Object.prototype.hasOwnProperty.call(i,l)?i[l]:void 0;typeof c<"u"?a=c(u,Object.assign(Object.assign({},n),{p:BA(n,l),coercion:_l(i,l)}))&&a:e===null?a=pt(Object.assign(Object.assign({},n),{p:BA(n,l)}),`Extraneous property (got ${Vr(u)})`):Object.defineProperty(o,l,{enumerable:!0,get:()=>u,set:z2(i,l)})}if(!a&&(n==null?void 0:n.errors)==null)break}return e!==null&&(a||(n==null?void 0:n.errors)!=null)&&(a=e(o,n)&&a),a}})},Fpe=r=>bt({test:(e,t)=>e instanceof r?!0:pt(t,`Expected an instance of ${r.name} (got ${Vr(e)})`)}),Npe=(r,{exclusive:e=!1}={})=>bt({test:(t,i)=>{var n,s,o;let a=[],l=typeof(i==null?void 0:i.errors)<"u"?[]:void 0;for(let c=0,u=r.length;c1?pt(i,`Expected to match exactly a single predicate (matched ${a.join(", ")})`):(o=i==null?void 0:i.errors)===null||o===void 0||o.push(...l),!1}}),zp=(r,e)=>bt({test:(t,i)=>{var n,s;let o={value:t},a=typeof(i==null?void 0:i.coercions)<"u"?_l(o,"value"):void 0,l=typeof(i==null?void 0:i.coercions)<"u"?[]:void 0;if(!r(t,Object.assign(Object.assign({},i),{coercion:a,coercions:l})))return!1;let c=[];if(typeof l<"u")for(let[,u]of l)c.push(u());try{if(typeof(i==null?void 0:i.coercions)<"u"){if(o.value!==t){if(typeof(i==null?void 0:i.coercion)>"u")return pt(i,"Unbound coercion result");i.coercions.push([(n=i.p)!==null&&n!==void 0?n:".",i.coercion.bind(null,o.value)])}(s=i==null?void 0:i.coercions)===null||s===void 0||s.push(...l)}return e.every(u=>u(o.value,i))}finally{for(let u of c)u()}}}),Lpe=r=>bt({test:(e,t)=>typeof e>"u"?!0:r(e,t)}),Tpe=r=>bt({test:(e,t)=>e===null?!0:r(e,t)}),Ope=r=>bt({test:(e,t)=>e.length>=r?!0:pt(t,`Expected to have a length of at least ${r} elements (got ${e.length})`)}),Mpe=r=>bt({test:(e,t)=>e.length<=r?!0:pt(t,`Expected to have a length of at most ${r} elements (got ${e.length})`)}),X2=r=>bt({test:(e,t)=>e.length!==r?pt(t,`Expected to have a length of exactly ${r} elements (got ${e.length})`):!0}),Kpe=({map:r}={})=>bt({test:(e,t)=>{let i=new Set,n=new Set;for(let s=0,o=e.length;sbt({test:(r,e)=>r<=0?!0:pt(e,`Expected to be negative (got ${r})`)}),Hpe=()=>bt({test:(r,e)=>r>=0?!0:pt(e,`Expected to be positive (got ${r})`)}),Gpe=r=>bt({test:(e,t)=>e>=r?!0:pt(t,`Expected to be at least ${r} (got ${e})`)}),Ype=r=>bt({test:(e,t)=>e<=r?!0:pt(t,`Expected to be at most ${r} (got ${e})`)}),jpe=(r,e)=>bt({test:(t,i)=>t>=r&&t<=e?!0:pt(i,`Expected to be in the [${r}; ${e}] range (got ${t})`)}),qpe=(r,e)=>bt({test:(t,i)=>t>=r&&tbt({test:(e,t)=>e!==Math.round(e)?pt(t,`Expected to be an integer (got ${e})`):Number.isSafeInteger(e)?!0:pt(t,`Expected to be a safe integer (got ${e})`)}),Vp=r=>bt({test:(e,t)=>r.test(e)?!0:pt(t,`Expected to match the pattern ${r.toString()} (got ${Vr(e)})`)}),Wpe=()=>bt({test:(r,e)=>r!==r.toLowerCase()?pt(e,`Expected to be all-lowercase (got ${r})`):!0}),zpe=()=>bt({test:(r,e)=>r!==r.toUpperCase()?pt(e,`Expected to be all-uppercase (got ${r})`):!0}),Vpe=()=>bt({test:(r,e)=>J2.test(r)?!0:pt(e,`Expected to be a valid UUID v4 (got ${Vr(r)})`)}),Xpe=()=>bt({test:(r,e)=>qS.test(r)?!1:pt(e,`Expected to be a valid ISO 8601 date string (got ${Vr(r)})`)}),_pe=({alpha:r=!1})=>bt({test:(e,t)=>(r?Y2.test(e):j2.test(e))?!0:pt(t,`Expected to be a valid hexadecimal color string (got ${Vr(e)})`)}),Zpe=()=>bt({test:(r,e)=>q2.test(r)?!0:pt(e,`Expected to be a valid base 64 string (got ${Vr(r)})`)}),$pe=(r=V2())=>bt({test:(e,t)=>{let i;try{i=JSON.parse(e)}catch{return pt(t,`Expected to be a valid JSON string (got ${Vr(e)})`)}return r(i,t)}}),ede=r=>{let e=new Set(r);return bt({test:(t,i)=>{let n=new Set(Object.keys(t)),s=[];for(let o of e)n.has(o)||s.push(o);return s.length>0?pt(i,`Missing required ${EI(s.length,"property","properties")} ${s.map(o=>`"${o}"`).join(", ")}`):!0}})},tde=r=>{let e=new Set(r);return bt({test:(t,i)=>{let n=new Set(Object.keys(t)),s=[];for(let o of e)n.has(o)&&s.push(o);return s.length>0?pt(i,`Forbidden ${EI(s.length,"property","properties")} ${s.map(o=>`"${o}"`).join(", ")}`):!0}})},rde=r=>{let e=new Set(r);return bt({test:(t,i)=>{let n=new Set(Object.keys(t)),s=[];for(let o of e)n.has(o)&&s.push(o);return s.length>1?pt(i,`Mutually exclusive properties ${s.map(o=>`"${o}"`).join(", ")}`):!0}})};(function(r){r.Forbids="Forbids",r.Requires="Requires"})(Xl||(Xl={}));ide={[Xl.Forbids]:{expect:!1,message:"forbids using"},[Xl.Requires]:{expect:!0,message:"requires using"}},JS=(r,e,t,{ignore:i=[]}={})=>{let n=new Set(i),s=new Set(t),o=ide[e];return bt({test:(a,l)=>{let c=new Set(Object.keys(a));if(!c.has(r)||n.has(a[r]))return!0;let u=[];for(let g of s)(c.has(g)&&!n.has(a[g]))!==o.expect&&u.push(g);return u.length>=1?pt(l,`Property "${r}" ${o.message} ${EI(u.length,"property","properties")} ${u.map(g=>`"${g}"`).join(", ")}`):!0}})}});var fH=w((V_e,gH)=>{"use strict";gH.exports=(r,...e)=>new Promise(t=>{t(r(...e))})});var Tg=w((X_e,ev)=>{"use strict";var Ide=fH(),hH=r=>{if(r<1)throw new TypeError("Expected `concurrency` to be a number from 1 and up");let e=[],t=0,i=()=>{t--,e.length>0&&e.shift()()},n=(a,l,...c)=>{t++;let u=Ide(a,...c);l(u),u.then(i,i)},s=(a,l,...c)=>{tnew Promise(c=>s(a,c,...l));return Object.defineProperties(o,{activeCount:{get:()=>t},pendingCount:{get:()=>e.length}}),o};ev.exports=hH;ev.exports.default=hH});var ed=w((Z_e,pH)=>{var yde="2.0.0",wde=Number.MAX_SAFE_INTEGER||9007199254740991,Bde=16;pH.exports={SEMVER_SPEC_VERSION:yde,MAX_LENGTH:256,MAX_SAFE_INTEGER:wde,MAX_SAFE_COMPONENT_LENGTH:Bde}});var td=w(($_e,dH)=>{var Qde=typeof process=="object"&&process.env&&process.env.NODE_DEBUG&&/\bsemver\b/i.test(process.env.NODE_DEBUG)?(...r)=>console.error("SEMVER",...r):()=>{};dH.exports=Qde});var Zl=w((bA,CH)=>{var{MAX_SAFE_COMPONENT_LENGTH:tv}=ed(),bde=td();bA=CH.exports={};var Sde=bA.re=[],$e=bA.src=[],et=bA.t={},vde=0,St=(r,e,t)=>{let i=vde++;bde(i,e),et[r]=i,$e[i]=e,Sde[i]=new RegExp(e,t?"g":void 0)};St("NUMERICIDENTIFIER","0|[1-9]\\d*");St("NUMERICIDENTIFIERLOOSE","[0-9]+");St("NONNUMERICIDENTIFIER","\\d*[a-zA-Z-][a-zA-Z0-9-]*");St("MAINVERSION",`(${$e[et.NUMERICIDENTIFIER]})\\.(${$e[et.NUMERICIDENTIFIER]})\\.(${$e[et.NUMERICIDENTIFIER]})`);St("MAINVERSIONLOOSE",`(${$e[et.NUMERICIDENTIFIERLOOSE]})\\.(${$e[et.NUMERICIDENTIFIERLOOSE]})\\.(${$e[et.NUMERICIDENTIFIERLOOSE]})`);St("PRERELEASEIDENTIFIER",`(?:${$e[et.NUMERICIDENTIFIER]}|${$e[et.NONNUMERICIDENTIFIER]})`);St("PRERELEASEIDENTIFIERLOOSE",`(?:${$e[et.NUMERICIDENTIFIERLOOSE]}|${$e[et.NONNUMERICIDENTIFIER]})`);St("PRERELEASE",`(?:-(${$e[et.PRERELEASEIDENTIFIER]}(?:\\.${$e[et.PRERELEASEIDENTIFIER]})*))`);St("PRERELEASELOOSE",`(?:-?(${$e[et.PRERELEASEIDENTIFIERLOOSE]}(?:\\.${$e[et.PRERELEASEIDENTIFIERLOOSE]})*))`);St("BUILDIDENTIFIER","[0-9A-Za-z-]+");St("BUILD",`(?:\\+(${$e[et.BUILDIDENTIFIER]}(?:\\.${$e[et.BUILDIDENTIFIER]})*))`);St("FULLPLAIN",`v?${$e[et.MAINVERSION]}${$e[et.PRERELEASE]}?${$e[et.BUILD]}?`);St("FULL",`^${$e[et.FULLPLAIN]}$`);St("LOOSEPLAIN",`[v=\\s]*${$e[et.MAINVERSIONLOOSE]}${$e[et.PRERELEASELOOSE]}?${$e[et.BUILD]}?`);St("LOOSE",`^${$e[et.LOOSEPLAIN]}$`);St("GTLT","((?:<|>)?=?)");St("XRANGEIDENTIFIERLOOSE",`${$e[et.NUMERICIDENTIFIERLOOSE]}|x|X|\\*`);St("XRANGEIDENTIFIER",`${$e[et.NUMERICIDENTIFIER]}|x|X|\\*`);St("XRANGEPLAIN",`[v=\\s]*(${$e[et.XRANGEIDENTIFIER]})(?:\\.(${$e[et.XRANGEIDENTIFIER]})(?:\\.(${$e[et.XRANGEIDENTIFIER]})(?:${$e[et.PRERELEASE]})?${$e[et.BUILD]}?)?)?`);St("XRANGEPLAINLOOSE",`[v=\\s]*(${$e[et.XRANGEIDENTIFIERLOOSE]})(?:\\.(${$e[et.XRANGEIDENTIFIERLOOSE]})(?:\\.(${$e[et.XRANGEIDENTIFIERLOOSE]})(?:${$e[et.PRERELEASELOOSE]})?${$e[et.BUILD]}?)?)?`);St("XRANGE",`^${$e[et.GTLT]}\\s*${$e[et.XRANGEPLAIN]}$`);St("XRANGELOOSE",`^${$e[et.GTLT]}\\s*${$e[et.XRANGEPLAINLOOSE]}$`);St("COERCE",`(^|[^\\d])(\\d{1,${tv}})(?:\\.(\\d{1,${tv}}))?(?:\\.(\\d{1,${tv}}))?(?:$|[^\\d])`);St("COERCERTL",$e[et.COERCE],!0);St("LONETILDE","(?:~>?)");St("TILDETRIM",`(\\s*)${$e[et.LONETILDE]}\\s+`,!0);bA.tildeTrimReplace="$1~";St("TILDE",`^${$e[et.LONETILDE]}${$e[et.XRANGEPLAIN]}$`);St("TILDELOOSE",`^${$e[et.LONETILDE]}${$e[et.XRANGEPLAINLOOSE]}$`);St("LONECARET","(?:\\^)");St("CARETTRIM",`(\\s*)${$e[et.LONECARET]}\\s+`,!0);bA.caretTrimReplace="$1^";St("CARET",`^${$e[et.LONECARET]}${$e[et.XRANGEPLAIN]}$`);St("CARETLOOSE",`^${$e[et.LONECARET]}${$e[et.XRANGEPLAINLOOSE]}$`);St("COMPARATORLOOSE",`^${$e[et.GTLT]}\\s*(${$e[et.LOOSEPLAIN]})$|^$`);St("COMPARATOR",`^${$e[et.GTLT]}\\s*(${$e[et.FULLPLAIN]})$|^$`);St("COMPARATORTRIM",`(\\s*)${$e[et.GTLT]}\\s*(${$e[et.LOOSEPLAIN]}|${$e[et.XRANGEPLAIN]})`,!0);bA.comparatorTrimReplace="$1$2$3";St("HYPHENRANGE",`^\\s*(${$e[et.XRANGEPLAIN]})\\s+-\\s+(${$e[et.XRANGEPLAIN]})\\s*$`);St("HYPHENRANGELOOSE",`^\\s*(${$e[et.XRANGEPLAINLOOSE]})\\s+-\\s+(${$e[et.XRANGEPLAINLOOSE]})\\s*$`);St("STAR","(<|>)?=?\\s*\\*");St("GTE0","^\\s*>=\\s*0.0.0\\s*$");St("GTE0PRE","^\\s*>=\\s*0.0.0-0\\s*$")});var rd=w((eZe,mH)=>{var xde=["includePrerelease","loose","rtl"],Pde=r=>r?typeof r!="object"?{loose:!0}:xde.filter(e=>r[e]).reduce((e,t)=>(e[t]=!0,e),{}):{};mH.exports=Pde});var bI=w((tZe,yH)=>{var EH=/^[0-9]+$/,IH=(r,e)=>{let t=EH.test(r),i=EH.test(e);return t&&i&&(r=+r,e=+e),r===e?0:t&&!i?-1:i&&!t?1:rIH(e,r);yH.exports={compareIdentifiers:IH,rcompareIdentifiers:Dde}});var Li=w((rZe,bH)=>{var SI=td(),{MAX_LENGTH:wH,MAX_SAFE_INTEGER:vI}=ed(),{re:BH,t:QH}=Zl(),kde=rd(),{compareIdentifiers:id}=bI(),Un=class{constructor(e,t){if(t=kde(t),e instanceof Un){if(e.loose===!!t.loose&&e.includePrerelease===!!t.includePrerelease)return e;e=e.version}else if(typeof e!="string")throw new TypeError(`Invalid Version: ${e}`);if(e.length>wH)throw new TypeError(`version is longer than ${wH} characters`);SI("SemVer",e,t),this.options=t,this.loose=!!t.loose,this.includePrerelease=!!t.includePrerelease;let i=e.trim().match(t.loose?BH[QH.LOOSE]:BH[QH.FULL]);if(!i)throw new TypeError(`Invalid Version: ${e}`);if(this.raw=e,this.major=+i[1],this.minor=+i[2],this.patch=+i[3],this.major>vI||this.major<0)throw new TypeError("Invalid major version");if(this.minor>vI||this.minor<0)throw new TypeError("Invalid minor version");if(this.patch>vI||this.patch<0)throw new TypeError("Invalid patch version");i[4]?this.prerelease=i[4].split(".").map(n=>{if(/^[0-9]+$/.test(n)){let s=+n;if(s>=0&&s=0;)typeof this.prerelease[i]=="number"&&(this.prerelease[i]++,i=-2);i===-1&&this.prerelease.push(0)}t&&(this.prerelease[0]===t?isNaN(this.prerelease[1])&&(this.prerelease=[t,0]):this.prerelease=[t,0]);break;default:throw new Error(`invalid increment argument: ${e}`)}return this.format(),this.raw=this.version,this}};bH.exports=Un});var $l=w((iZe,PH)=>{var{MAX_LENGTH:Rde}=ed(),{re:SH,t:vH}=Zl(),xH=Li(),Fde=rd(),Nde=(r,e)=>{if(e=Fde(e),r instanceof xH)return r;if(typeof r!="string"||r.length>Rde||!(e.loose?SH[vH.LOOSE]:SH[vH.FULL]).test(r))return null;try{return new xH(r,e)}catch{return null}};PH.exports=Nde});var kH=w((nZe,DH)=>{var Lde=$l(),Tde=(r,e)=>{let t=Lde(r,e);return t?t.version:null};DH.exports=Tde});var FH=w((sZe,RH)=>{var Ode=$l(),Mde=(r,e)=>{let t=Ode(r.trim().replace(/^[=v]+/,""),e);return t?t.version:null};RH.exports=Mde});var LH=w((oZe,NH)=>{var Kde=Li(),Ude=(r,e,t,i)=>{typeof t=="string"&&(i=t,t=void 0);try{return new Kde(r,t).inc(e,i).version}catch{return null}};NH.exports=Ude});var ss=w((aZe,OH)=>{var TH=Li(),Hde=(r,e,t)=>new TH(r,t).compare(new TH(e,t));OH.exports=Hde});var xI=w((AZe,MH)=>{var Gde=ss(),Yde=(r,e,t)=>Gde(r,e,t)===0;MH.exports=Yde});var HH=w((lZe,UH)=>{var KH=$l(),jde=xI(),qde=(r,e)=>{if(jde(r,e))return null;{let t=KH(r),i=KH(e),n=t.prerelease.length||i.prerelease.length,s=n?"pre":"",o=n?"prerelease":"";for(let a in t)if((a==="major"||a==="minor"||a==="patch")&&t[a]!==i[a])return s+a;return o}};UH.exports=qde});var YH=w((cZe,GH)=>{var Jde=Li(),Wde=(r,e)=>new Jde(r,e).major;GH.exports=Wde});var qH=w((uZe,jH)=>{var zde=Li(),Vde=(r,e)=>new zde(r,e).minor;jH.exports=Vde});var WH=w((gZe,JH)=>{var Xde=Li(),_de=(r,e)=>new Xde(r,e).patch;JH.exports=_de});var VH=w((fZe,zH)=>{var Zde=$l(),$de=(r,e)=>{let t=Zde(r,e);return t&&t.prerelease.length?t.prerelease:null};zH.exports=$de});var _H=w((hZe,XH)=>{var eCe=ss(),tCe=(r,e,t)=>eCe(e,r,t);XH.exports=tCe});var $H=w((pZe,ZH)=>{var rCe=ss(),iCe=(r,e)=>rCe(r,e,!0);ZH.exports=iCe});var PI=w((dZe,tG)=>{var eG=Li(),nCe=(r,e,t)=>{let i=new eG(r,t),n=new eG(e,t);return i.compare(n)||i.compareBuild(n)};tG.exports=nCe});var iG=w((CZe,rG)=>{var sCe=PI(),oCe=(r,e)=>r.sort((t,i)=>sCe(t,i,e));rG.exports=oCe});var sG=w((mZe,nG)=>{var aCe=PI(),ACe=(r,e)=>r.sort((t,i)=>aCe(i,t,e));nG.exports=ACe});var nd=w((EZe,oG)=>{var lCe=ss(),cCe=(r,e,t)=>lCe(r,e,t)>0;oG.exports=cCe});var DI=w((IZe,aG)=>{var uCe=ss(),gCe=(r,e,t)=>uCe(r,e,t)<0;aG.exports=gCe});var rv=w((yZe,AG)=>{var fCe=ss(),hCe=(r,e,t)=>fCe(r,e,t)!==0;AG.exports=hCe});var kI=w((wZe,lG)=>{var pCe=ss(),dCe=(r,e,t)=>pCe(r,e,t)>=0;lG.exports=dCe});var RI=w((BZe,cG)=>{var CCe=ss(),mCe=(r,e,t)=>CCe(r,e,t)<=0;cG.exports=mCe});var iv=w((QZe,uG)=>{var ECe=xI(),ICe=rv(),yCe=nd(),wCe=kI(),BCe=DI(),QCe=RI(),bCe=(r,e,t,i)=>{switch(e){case"===":return typeof r=="object"&&(r=r.version),typeof t=="object"&&(t=t.version),r===t;case"!==":return typeof r=="object"&&(r=r.version),typeof t=="object"&&(t=t.version),r!==t;case"":case"=":case"==":return ECe(r,t,i);case"!=":return ICe(r,t,i);case">":return yCe(r,t,i);case">=":return wCe(r,t,i);case"<":return BCe(r,t,i);case"<=":return QCe(r,t,i);default:throw new TypeError(`Invalid operator: ${e}`)}};uG.exports=bCe});var fG=w((bZe,gG)=>{var SCe=Li(),vCe=$l(),{re:FI,t:NI}=Zl(),xCe=(r,e)=>{if(r instanceof SCe)return r;if(typeof r=="number"&&(r=String(r)),typeof r!="string")return null;e=e||{};let t=null;if(!e.rtl)t=r.match(FI[NI.COERCE]);else{let i;for(;(i=FI[NI.COERCERTL].exec(r))&&(!t||t.index+t[0].length!==r.length);)(!t||i.index+i[0].length!==t.index+t[0].length)&&(t=i),FI[NI.COERCERTL].lastIndex=i.index+i[1].length+i[2].length;FI[NI.COERCERTL].lastIndex=-1}return t===null?null:vCe(`${t[2]}.${t[3]||"0"}.${t[4]||"0"}`,e)};gG.exports=xCe});var pG=w((SZe,hG)=>{"use strict";hG.exports=function(r){r.prototype[Symbol.iterator]=function*(){for(let e=this.head;e;e=e.next)yield e.value}}});var sd=w((vZe,dG)=>{"use strict";dG.exports=Ht;Ht.Node=ec;Ht.create=Ht;function Ht(r){var e=this;if(e instanceof Ht||(e=new Ht),e.tail=null,e.head=null,e.length=0,r&&typeof r.forEach=="function")r.forEach(function(n){e.push(n)});else if(arguments.length>0)for(var t=0,i=arguments.length;t1)t=e;else if(this.head)i=this.head.next,t=this.head.value;else throw new TypeError("Reduce of empty list with no initial value");for(var n=0;i!==null;n++)t=r(t,i.value,n),i=i.next;return t};Ht.prototype.reduceReverse=function(r,e){var t,i=this.tail;if(arguments.length>1)t=e;else if(this.tail)i=this.tail.prev,t=this.tail.value;else throw new TypeError("Reduce of empty list with no initial value");for(var n=this.length-1;i!==null;n--)t=r(t,i.value,n),i=i.prev;return t};Ht.prototype.toArray=function(){for(var r=new Array(this.length),e=0,t=this.head;t!==null;e++)r[e]=t.value,t=t.next;return r};Ht.prototype.toArrayReverse=function(){for(var r=new Array(this.length),e=0,t=this.tail;t!==null;e++)r[e]=t.value,t=t.prev;return r};Ht.prototype.slice=function(r,e){e=e||this.length,e<0&&(e+=this.length),r=r||0,r<0&&(r+=this.length);var t=new Ht;if(ethis.length&&(e=this.length);for(var i=0,n=this.head;n!==null&&ithis.length&&(e=this.length);for(var i=this.length,n=this.tail;n!==null&&i>e;i--)n=n.prev;for(;n!==null&&i>r;i--,n=n.prev)t.push(n.value);return t};Ht.prototype.splice=function(r,e,...t){r>this.length&&(r=this.length-1),r<0&&(r=this.length+r);for(var i=0,n=this.head;n!==null&&i{"use strict";var RCe=sd(),tc=Symbol("max"),Ia=Symbol("length"),Og=Symbol("lengthCalculator"),ad=Symbol("allowStale"),rc=Symbol("maxAge"),Ea=Symbol("dispose"),CG=Symbol("noDisposeOnSet"),di=Symbol("lruList"),Ws=Symbol("cache"),EG=Symbol("updateAgeOnGet"),nv=()=>1,ov=class{constructor(e){if(typeof e=="number"&&(e={max:e}),e||(e={}),e.max&&(typeof e.max!="number"||e.max<0))throw new TypeError("max must be a non-negative number");let t=this[tc]=e.max||1/0,i=e.length||nv;if(this[Og]=typeof i!="function"?nv:i,this[ad]=e.stale||!1,e.maxAge&&typeof e.maxAge!="number")throw new TypeError("maxAge must be a number");this[rc]=e.maxAge||0,this[Ea]=e.dispose,this[CG]=e.noDisposeOnSet||!1,this[EG]=e.updateAgeOnGet||!1,this.reset()}set max(e){if(typeof e!="number"||e<0)throw new TypeError("max must be a non-negative number");this[tc]=e||1/0,od(this)}get max(){return this[tc]}set allowStale(e){this[ad]=!!e}get allowStale(){return this[ad]}set maxAge(e){if(typeof e!="number")throw new TypeError("maxAge must be a non-negative number");this[rc]=e,od(this)}get maxAge(){return this[rc]}set lengthCalculator(e){typeof e!="function"&&(e=nv),e!==this[Og]&&(this[Og]=e,this[Ia]=0,this[di].forEach(t=>{t.length=this[Og](t.value,t.key),this[Ia]+=t.length})),od(this)}get lengthCalculator(){return this[Og]}get length(){return this[Ia]}get itemCount(){return this[di].length}rforEach(e,t){t=t||this;for(let i=this[di].tail;i!==null;){let n=i.prev;mG(this,e,i,t),i=n}}forEach(e,t){t=t||this;for(let i=this[di].head;i!==null;){let n=i.next;mG(this,e,i,t),i=n}}keys(){return this[di].toArray().map(e=>e.key)}values(){return this[di].toArray().map(e=>e.value)}reset(){this[Ea]&&this[di]&&this[di].length&&this[di].forEach(e=>this[Ea](e.key,e.value)),this[Ws]=new Map,this[di]=new RCe,this[Ia]=0}dump(){return this[di].map(e=>LI(this,e)?!1:{k:e.key,v:e.value,e:e.now+(e.maxAge||0)}).toArray().filter(e=>e)}dumpLru(){return this[di]}set(e,t,i){if(i=i||this[rc],i&&typeof i!="number")throw new TypeError("maxAge must be a number");let n=i?Date.now():0,s=this[Og](t,e);if(this[Ws].has(e)){if(s>this[tc])return Mg(this,this[Ws].get(e)),!1;let l=this[Ws].get(e).value;return this[Ea]&&(this[CG]||this[Ea](e,l.value)),l.now=n,l.maxAge=i,l.value=t,this[Ia]+=s-l.length,l.length=s,this.get(e),od(this),!0}let o=new av(e,t,s,n,i);return o.length>this[tc]?(this[Ea]&&this[Ea](e,t),!1):(this[Ia]+=o.length,this[di].unshift(o),this[Ws].set(e,this[di].head),od(this),!0)}has(e){if(!this[Ws].has(e))return!1;let t=this[Ws].get(e).value;return!LI(this,t)}get(e){return sv(this,e,!0)}peek(e){return sv(this,e,!1)}pop(){let e=this[di].tail;return e?(Mg(this,e),e.value):null}del(e){Mg(this,this[Ws].get(e))}load(e){this.reset();let t=Date.now();for(let i=e.length-1;i>=0;i--){let n=e[i],s=n.e||0;if(s===0)this.set(n.k,n.v);else{let o=s-t;o>0&&this.set(n.k,n.v,o)}}}prune(){this[Ws].forEach((e,t)=>sv(this,t,!1))}},sv=(r,e,t)=>{let i=r[Ws].get(e);if(i){let n=i.value;if(LI(r,n)){if(Mg(r,i),!r[ad])return}else t&&(r[EG]&&(i.value.now=Date.now()),r[di].unshiftNode(i));return n.value}},LI=(r,e)=>{if(!e||!e.maxAge&&!r[rc])return!1;let t=Date.now()-e.now;return e.maxAge?t>e.maxAge:r[rc]&&t>r[rc]},od=r=>{if(r[Ia]>r[tc])for(let e=r[di].tail;r[Ia]>r[tc]&&e!==null;){let t=e.prev;Mg(r,e),e=t}},Mg=(r,e)=>{if(e){let t=e.value;r[Ea]&&r[Ea](t.key,t.value),r[Ia]-=t.length,r[Ws].delete(t.key),r[di].removeNode(e)}},av=class{constructor(e,t,i,n,s){this.key=e,this.value=t,this.length=i,this.now=n,this.maxAge=s||0}},mG=(r,e,t,i)=>{let n=t.value;LI(r,n)&&(Mg(r,t),r[ad]||(n=void 0)),n&&e.call(i,n.value,n.key,r)};IG.exports=ov});var os=w((PZe,bG)=>{var ic=class{constructor(e,t){if(t=NCe(t),e instanceof ic)return e.loose===!!t.loose&&e.includePrerelease===!!t.includePrerelease?e:new ic(e.raw,t);if(e instanceof Av)return this.raw=e.value,this.set=[[e]],this.format(),this;if(this.options=t,this.loose=!!t.loose,this.includePrerelease=!!t.includePrerelease,this.raw=e,this.set=e.split(/\s*\|\|\s*/).map(i=>this.parseRange(i.trim())).filter(i=>i.length),!this.set.length)throw new TypeError(`Invalid SemVer Range: ${e}`);if(this.set.length>1){let i=this.set[0];if(this.set=this.set.filter(n=>!BG(n[0])),this.set.length===0)this.set=[i];else if(this.set.length>1){for(let n of this.set)if(n.length===1&&KCe(n[0])){this.set=[n];break}}}this.format()}format(){return this.range=this.set.map(e=>e.join(" ").trim()).join("||").trim(),this.range}toString(){return this.range}parseRange(e){e=e.trim();let i=`parseRange:${Object.keys(this.options).join(",")}:${e}`,n=wG.get(i);if(n)return n;let s=this.options.loose,o=s?Ti[Bi.HYPHENRANGELOOSE]:Ti[Bi.HYPHENRANGE];e=e.replace(o,VCe(this.options.includePrerelease)),Gr("hyphen replace",e),e=e.replace(Ti[Bi.COMPARATORTRIM],TCe),Gr("comparator trim",e,Ti[Bi.COMPARATORTRIM]),e=e.replace(Ti[Bi.TILDETRIM],OCe),e=e.replace(Ti[Bi.CARETTRIM],MCe),e=e.split(/\s+/).join(" ");let a=s?Ti[Bi.COMPARATORLOOSE]:Ti[Bi.COMPARATOR],l=e.split(" ").map(f=>UCe(f,this.options)).join(" ").split(/\s+/).map(f=>zCe(f,this.options)).filter(this.options.loose?f=>!!f.match(a):()=>!0).map(f=>new Av(f,this.options)),c=l.length,u=new Map;for(let f of l){if(BG(f))return[f];u.set(f.value,f)}u.size>1&&u.has("")&&u.delete("");let g=[...u.values()];return wG.set(i,g),g}intersects(e,t){if(!(e instanceof ic))throw new TypeError("a Range is required");return this.set.some(i=>QG(i,t)&&e.set.some(n=>QG(n,t)&&i.every(s=>n.every(o=>s.intersects(o,t)))))}test(e){if(!e)return!1;if(typeof e=="string")try{e=new LCe(e,this.options)}catch{return!1}for(let t=0;tr.value==="<0.0.0-0",KCe=r=>r.value==="",QG=(r,e)=>{let t=!0,i=r.slice(),n=i.pop();for(;t&&i.length;)t=i.every(s=>n.intersects(s,e)),n=i.pop();return t},UCe=(r,e)=>(Gr("comp",r,e),r=YCe(r,e),Gr("caret",r),r=HCe(r,e),Gr("tildes",r),r=qCe(r,e),Gr("xrange",r),r=WCe(r,e),Gr("stars",r),r),Vi=r=>!r||r.toLowerCase()==="x"||r==="*",HCe=(r,e)=>r.trim().split(/\s+/).map(t=>GCe(t,e)).join(" "),GCe=(r,e)=>{let t=e.loose?Ti[Bi.TILDELOOSE]:Ti[Bi.TILDE];return r.replace(t,(i,n,s,o,a)=>{Gr("tilde",r,i,n,s,o,a);let l;return Vi(n)?l="":Vi(s)?l=`>=${n}.0.0 <${+n+1}.0.0-0`:Vi(o)?l=`>=${n}.${s}.0 <${n}.${+s+1}.0-0`:a?(Gr("replaceTilde pr",a),l=`>=${n}.${s}.${o}-${a} <${n}.${+s+1}.0-0`):l=`>=${n}.${s}.${o} <${n}.${+s+1}.0-0`,Gr("tilde return",l),l})},YCe=(r,e)=>r.trim().split(/\s+/).map(t=>jCe(t,e)).join(" "),jCe=(r,e)=>{Gr("caret",r,e);let t=e.loose?Ti[Bi.CARETLOOSE]:Ti[Bi.CARET],i=e.includePrerelease?"-0":"";return r.replace(t,(n,s,o,a,l)=>{Gr("caret",r,n,s,o,a,l);let c;return Vi(s)?c="":Vi(o)?c=`>=${s}.0.0${i} <${+s+1}.0.0-0`:Vi(a)?s==="0"?c=`>=${s}.${o}.0${i} <${s}.${+o+1}.0-0`:c=`>=${s}.${o}.0${i} <${+s+1}.0.0-0`:l?(Gr("replaceCaret pr",l),s==="0"?o==="0"?c=`>=${s}.${o}.${a}-${l} <${s}.${o}.${+a+1}-0`:c=`>=${s}.${o}.${a}-${l} <${s}.${+o+1}.0-0`:c=`>=${s}.${o}.${a}-${l} <${+s+1}.0.0-0`):(Gr("no pr"),s==="0"?o==="0"?c=`>=${s}.${o}.${a}${i} <${s}.${o}.${+a+1}-0`:c=`>=${s}.${o}.${a}${i} <${s}.${+o+1}.0-0`:c=`>=${s}.${o}.${a} <${+s+1}.0.0-0`),Gr("caret return",c),c})},qCe=(r,e)=>(Gr("replaceXRanges",r,e),r.split(/\s+/).map(t=>JCe(t,e)).join(" ")),JCe=(r,e)=>{r=r.trim();let t=e.loose?Ti[Bi.XRANGELOOSE]:Ti[Bi.XRANGE];return r.replace(t,(i,n,s,o,a,l)=>{Gr("xRange",r,i,n,s,o,a,l);let c=Vi(s),u=c||Vi(o),g=u||Vi(a),f=g;return n==="="&&f&&(n=""),l=e.includePrerelease?"-0":"",c?n===">"||n==="<"?i="<0.0.0-0":i="*":n&&f?(u&&(o=0),a=0,n===">"?(n=">=",u?(s=+s+1,o=0,a=0):(o=+o+1,a=0)):n==="<="&&(n="<",u?s=+s+1:o=+o+1),n==="<"&&(l="-0"),i=`${n+s}.${o}.${a}${l}`):u?i=`>=${s}.0.0${l} <${+s+1}.0.0-0`:g&&(i=`>=${s}.${o}.0${l} <${s}.${+o+1}.0-0`),Gr("xRange return",i),i})},WCe=(r,e)=>(Gr("replaceStars",r,e),r.trim().replace(Ti[Bi.STAR],"")),zCe=(r,e)=>(Gr("replaceGTE0",r,e),r.trim().replace(Ti[e.includePrerelease?Bi.GTE0PRE:Bi.GTE0],"")),VCe=r=>(e,t,i,n,s,o,a,l,c,u,g,f,h)=>(Vi(i)?t="":Vi(n)?t=`>=${i}.0.0${r?"-0":""}`:Vi(s)?t=`>=${i}.${n}.0${r?"-0":""}`:o?t=`>=${t}`:t=`>=${t}${r?"-0":""}`,Vi(c)?l="":Vi(u)?l=`<${+c+1}.0.0-0`:Vi(g)?l=`<${c}.${+u+1}.0-0`:f?l=`<=${c}.${u}.${g}-${f}`:r?l=`<${c}.${u}.${+g+1}-0`:l=`<=${l}`,`${t} ${l}`.trim()),XCe=(r,e,t)=>{for(let i=0;i0){let n=r[i].semver;if(n.major===e.major&&n.minor===e.minor&&n.patch===e.patch)return!0}return!1}return!0}});var Ad=w((DZe,DG)=>{var ld=Symbol("SemVer ANY"),Kg=class{static get ANY(){return ld}constructor(e,t){if(t=_Ce(t),e instanceof Kg){if(e.loose===!!t.loose)return e;e=e.value}cv("comparator",e,t),this.options=t,this.loose=!!t.loose,this.parse(e),this.semver===ld?this.value="":this.value=this.operator+this.semver.version,cv("comp",this)}parse(e){let t=this.options.loose?SG[vG.COMPARATORLOOSE]:SG[vG.COMPARATOR],i=e.match(t);if(!i)throw new TypeError(`Invalid comparator: ${e}`);this.operator=i[1]!==void 0?i[1]:"",this.operator==="="&&(this.operator=""),i[2]?this.semver=new xG(i[2],this.options.loose):this.semver=ld}toString(){return this.value}test(e){if(cv("Comparator.test",e,this.options.loose),this.semver===ld||e===ld)return!0;if(typeof e=="string")try{e=new xG(e,this.options)}catch{return!1}return lv(e,this.operator,this.semver,this.options)}intersects(e,t){if(!(e instanceof Kg))throw new TypeError("a Comparator is required");if((!t||typeof t!="object")&&(t={loose:!!t,includePrerelease:!1}),this.operator==="")return this.value===""?!0:new PG(e.value,t).test(this.value);if(e.operator==="")return e.value===""?!0:new PG(this.value,t).test(e.semver);let i=(this.operator===">="||this.operator===">")&&(e.operator===">="||e.operator===">"),n=(this.operator==="<="||this.operator==="<")&&(e.operator==="<="||e.operator==="<"),s=this.semver.version===e.semver.version,o=(this.operator===">="||this.operator==="<=")&&(e.operator===">="||e.operator==="<="),a=lv(this.semver,"<",e.semver,t)&&(this.operator===">="||this.operator===">")&&(e.operator==="<="||e.operator==="<"),l=lv(this.semver,">",e.semver,t)&&(this.operator==="<="||this.operator==="<")&&(e.operator===">="||e.operator===">");return i||n||s&&o||a||l}};DG.exports=Kg;var _Ce=rd(),{re:SG,t:vG}=Zl(),lv=iv(),cv=td(),xG=Li(),PG=os()});var cd=w((kZe,kG)=>{var ZCe=os(),$Ce=(r,e,t)=>{try{e=new ZCe(e,t)}catch{return!1}return e.test(r)};kG.exports=$Ce});var FG=w((RZe,RG)=>{var eme=os(),tme=(r,e)=>new eme(r,e).set.map(t=>t.map(i=>i.value).join(" ").trim().split(" "));RG.exports=tme});var LG=w((FZe,NG)=>{var rme=Li(),ime=os(),nme=(r,e,t)=>{let i=null,n=null,s=null;try{s=new ime(e,t)}catch{return null}return r.forEach(o=>{s.test(o)&&(!i||n.compare(o)===-1)&&(i=o,n=new rme(i,t))}),i};NG.exports=nme});var OG=w((NZe,TG)=>{var sme=Li(),ome=os(),ame=(r,e,t)=>{let i=null,n=null,s=null;try{s=new ome(e,t)}catch{return null}return r.forEach(o=>{s.test(o)&&(!i||n.compare(o)===1)&&(i=o,n=new sme(i,t))}),i};TG.exports=ame});var UG=w((LZe,KG)=>{var uv=Li(),Ame=os(),MG=nd(),lme=(r,e)=>{r=new Ame(r,e);let t=new uv("0.0.0");if(r.test(t)||(t=new uv("0.0.0-0"),r.test(t)))return t;t=null;for(let i=0;i{let a=new uv(o.semver.version);switch(o.operator){case">":a.prerelease.length===0?a.patch++:a.prerelease.push(0),a.raw=a.format();case"":case">=":(!s||MG(a,s))&&(s=a);break;case"<":case"<=":break;default:throw new Error(`Unexpected operation: ${o.operator}`)}}),s&&(!t||MG(t,s))&&(t=s)}return t&&r.test(t)?t:null};KG.exports=lme});var GG=w((TZe,HG)=>{var cme=os(),ume=(r,e)=>{try{return new cme(r,e).range||"*"}catch{return null}};HG.exports=ume});var TI=w((OZe,JG)=>{var gme=Li(),qG=Ad(),{ANY:fme}=qG,hme=os(),pme=cd(),YG=nd(),jG=DI(),dme=RI(),Cme=kI(),mme=(r,e,t,i)=>{r=new gme(r,i),e=new hme(e,i);let n,s,o,a,l;switch(t){case">":n=YG,s=dme,o=jG,a=">",l=">=";break;case"<":n=jG,s=Cme,o=YG,a="<",l="<=";break;default:throw new TypeError('Must provide a hilo val of "<" or ">"')}if(pme(r,e,i))return!1;for(let c=0;c{h.semver===fme&&(h=new qG(">=0.0.0")),g=g||h,f=f||h,n(h.semver,g.semver,i)?g=h:o(h.semver,f.semver,i)&&(f=h)}),g.operator===a||g.operator===l||(!f.operator||f.operator===a)&&s(r,f.semver))return!1;if(f.operator===l&&o(r,f.semver))return!1}return!0};JG.exports=mme});var zG=w((MZe,WG)=>{var Eme=TI(),Ime=(r,e,t)=>Eme(r,e,">",t);WG.exports=Ime});var XG=w((KZe,VG)=>{var yme=TI(),wme=(r,e,t)=>yme(r,e,"<",t);VG.exports=wme});var $G=w((UZe,ZG)=>{var _G=os(),Bme=(r,e,t)=>(r=new _G(r,t),e=new _G(e,t),r.intersects(e));ZG.exports=Bme});var tY=w((HZe,eY)=>{var Qme=cd(),bme=ss();eY.exports=(r,e,t)=>{let i=[],n=null,s=null,o=r.sort((u,g)=>bme(u,g,t));for(let u of o)Qme(u,e,t)?(s=u,n||(n=u)):(s&&i.push([n,s]),s=null,n=null);n&&i.push([n,null]);let a=[];for(let[u,g]of i)u===g?a.push(u):!g&&u===o[0]?a.push("*"):g?u===o[0]?a.push(`<=${g}`):a.push(`${u} - ${g}`):a.push(`>=${u}`);let l=a.join(" || "),c=typeof e.raw=="string"?e.raw:String(e);return l.length{var rY=os(),OI=Ad(),{ANY:gv}=OI,ud=cd(),fv=ss(),Sme=(r,e,t={})=>{if(r===e)return!0;r=new rY(r,t),e=new rY(e,t);let i=!1;e:for(let n of r.set){for(let s of e.set){let o=vme(n,s,t);if(i=i||o!==null,o)continue e}if(i)return!1}return!0},vme=(r,e,t)=>{if(r===e)return!0;if(r.length===1&&r[0].semver===gv){if(e.length===1&&e[0].semver===gv)return!0;t.includePrerelease?r=[new OI(">=0.0.0-0")]:r=[new OI(">=0.0.0")]}if(e.length===1&&e[0].semver===gv){if(t.includePrerelease)return!0;e=[new OI(">=0.0.0")]}let i=new Set,n,s;for(let h of r)h.operator===">"||h.operator===">="?n=iY(n,h,t):h.operator==="<"||h.operator==="<="?s=nY(s,h,t):i.add(h.semver);if(i.size>1)return null;let o;if(n&&s){if(o=fv(n.semver,s.semver,t),o>0)return null;if(o===0&&(n.operator!==">="||s.operator!=="<="))return null}for(let h of i){if(n&&!ud(h,String(n),t)||s&&!ud(h,String(s),t))return null;for(let p of e)if(!ud(h,String(p),t))return!1;return!0}let a,l,c,u,g=s&&!t.includePrerelease&&s.semver.prerelease.length?s.semver:!1,f=n&&!t.includePrerelease&&n.semver.prerelease.length?n.semver:!1;g&&g.prerelease.length===1&&s.operator==="<"&&g.prerelease[0]===0&&(g=!1);for(let h of e){if(u=u||h.operator===">"||h.operator===">=",c=c||h.operator==="<"||h.operator==="<=",n){if(f&&h.semver.prerelease&&h.semver.prerelease.length&&h.semver.major===f.major&&h.semver.minor===f.minor&&h.semver.patch===f.patch&&(f=!1),h.operator===">"||h.operator===">="){if(a=iY(n,h,t),a===h&&a!==n)return!1}else if(n.operator===">="&&!ud(n.semver,String(h),t))return!1}if(s){if(g&&h.semver.prerelease&&h.semver.prerelease.length&&h.semver.major===g.major&&h.semver.minor===g.minor&&h.semver.patch===g.patch&&(g=!1),h.operator==="<"||h.operator==="<="){if(l=nY(s,h,t),l===h&&l!==s)return!1}else if(s.operator==="<="&&!ud(s.semver,String(h),t))return!1}if(!h.operator&&(s||n)&&o!==0)return!1}return!(n&&c&&!s&&o!==0||s&&u&&!n&&o!==0||f||g)},iY=(r,e,t)=>{if(!r)return e;let i=fv(r.semver,e.semver,t);return i>0?r:i<0||e.operator===">"&&r.operator===">="?e:r},nY=(r,e,t)=>{if(!r)return e;let i=fv(r.semver,e.semver,t);return i<0?r:i>0||e.operator==="<"&&r.operator==="<="?e:r};sY.exports=Sme});var Xr=w((YZe,aY)=>{var hv=Zl();aY.exports={re:hv.re,src:hv.src,tokens:hv.t,SEMVER_SPEC_VERSION:ed().SEMVER_SPEC_VERSION,SemVer:Li(),compareIdentifiers:bI().compareIdentifiers,rcompareIdentifiers:bI().rcompareIdentifiers,parse:$l(),valid:kH(),clean:FH(),inc:LH(),diff:HH(),major:YH(),minor:qH(),patch:WH(),prerelease:VH(),compare:ss(),rcompare:_H(),compareLoose:$H(),compareBuild:PI(),sort:iG(),rsort:sG(),gt:nd(),lt:DI(),eq:xI(),neq:rv(),gte:kI(),lte:RI(),cmp:iv(),coerce:fG(),Comparator:Ad(),Range:os(),satisfies:cd(),toComparators:FG(),maxSatisfying:LG(),minSatisfying:OG(),minVersion:UG(),validRange:GG(),outside:TI(),gtr:zG(),ltr:XG(),intersects:$G(),simplifyRange:tY(),subset:oY()}});var pv=w(MI=>{"use strict";Object.defineProperty(MI,"__esModule",{value:!0});MI.VERSION=void 0;MI.VERSION="9.1.0"});var Gt=w((exports,module)=>{"use strict";var __spreadArray=exports&&exports.__spreadArray||function(r,e,t){if(t||arguments.length===2)for(var i=0,n=e.length,s;i{(function(r,e){typeof define=="function"&&define.amd?define([],e):typeof KI=="object"&&KI.exports?KI.exports=e():r.regexpToAst=e()})(typeof self<"u"?self:AY,function(){function r(){}r.prototype.saveState=function(){return{idx:this.idx,input:this.input,groupIdx:this.groupIdx}},r.prototype.restoreState=function(p){this.idx=p.idx,this.input=p.input,this.groupIdx=p.groupIdx},r.prototype.pattern=function(p){this.idx=0,this.input=p,this.groupIdx=0,this.consumeChar("/");var C=this.disjunction();this.consumeChar("/");for(var y={type:"Flags",loc:{begin:this.idx,end:p.length},global:!1,ignoreCase:!1,multiLine:!1,unicode:!1,sticky:!1};this.isRegExpFlag();)switch(this.popChar()){case"g":o(y,"global");break;case"i":o(y,"ignoreCase");break;case"m":o(y,"multiLine");break;case"u":o(y,"unicode");break;case"y":o(y,"sticky");break}if(this.idx!==this.input.length)throw Error("Redundant input: "+this.input.substring(this.idx));return{type:"Pattern",flags:y,value:C,loc:this.loc(0)}},r.prototype.disjunction=function(){var p=[],C=this.idx;for(p.push(this.alternative());this.peekChar()==="|";)this.consumeChar("|"),p.push(this.alternative());return{type:"Disjunction",value:p,loc:this.loc(C)}},r.prototype.alternative=function(){for(var p=[],C=this.idx;this.isTerm();)p.push(this.term());return{type:"Alternative",value:p,loc:this.loc(C)}},r.prototype.term=function(){return this.isAssertion()?this.assertion():this.atom()},r.prototype.assertion=function(){var p=this.idx;switch(this.popChar()){case"^":return{type:"StartAnchor",loc:this.loc(p)};case"$":return{type:"EndAnchor",loc:this.loc(p)};case"\\":switch(this.popChar()){case"b":return{type:"WordBoundary",loc:this.loc(p)};case"B":return{type:"NonWordBoundary",loc:this.loc(p)}}throw Error("Invalid Assertion Escape");case"(":this.consumeChar("?");var C;switch(this.popChar()){case"=":C="Lookahead";break;case"!":C="NegativeLookahead";break}a(C);var y=this.disjunction();return this.consumeChar(")"),{type:C,value:y,loc:this.loc(p)}}l()},r.prototype.quantifier=function(p){var C,y=this.idx;switch(this.popChar()){case"*":C={atLeast:0,atMost:1/0};break;case"+":C={atLeast:1,atMost:1/0};break;case"?":C={atLeast:0,atMost:1};break;case"{":var B=this.integerIncludingZero();switch(this.popChar()){case"}":C={atLeast:B,atMost:B};break;case",":var v;this.isDigit()?(v=this.integerIncludingZero(),C={atLeast:B,atMost:v}):C={atLeast:B,atMost:1/0},this.consumeChar("}");break}if(p===!0&&C===void 0)return;a(C);break}if(!(p===!0&&C===void 0))return a(C),this.peekChar(0)==="?"?(this.consumeChar("?"),C.greedy=!1):C.greedy=!0,C.type="Quantifier",C.loc=this.loc(y),C},r.prototype.atom=function(){var p,C=this.idx;switch(this.peekChar()){case".":p=this.dotAll();break;case"\\":p=this.atomEscape();break;case"[":p=this.characterClass();break;case"(":p=this.group();break}return p===void 0&&this.isPatternCharacter()&&(p=this.patternCharacter()),a(p),p.loc=this.loc(C),this.isQuantifier()&&(p.quantifier=this.quantifier()),p},r.prototype.dotAll=function(){return this.consumeChar("."),{type:"Set",complement:!0,value:[n(` +`),n("\r"),n("\u2028"),n("\u2029")]}},r.prototype.atomEscape=function(){switch(this.consumeChar("\\"),this.peekChar()){case"1":case"2":case"3":case"4":case"5":case"6":case"7":case"8":case"9":return this.decimalEscapeAtom();case"d":case"D":case"s":case"S":case"w":case"W":return this.characterClassEscape();case"f":case"n":case"r":case"t":case"v":return this.controlEscapeAtom();case"c":return this.controlLetterEscapeAtom();case"0":return this.nulCharacterAtom();case"x":return this.hexEscapeSequenceAtom();case"u":return this.regExpUnicodeEscapeSequenceAtom();default:return this.identityEscapeAtom()}},r.prototype.decimalEscapeAtom=function(){var p=this.positiveInteger();return{type:"GroupBackReference",value:p}},r.prototype.characterClassEscape=function(){var p,C=!1;switch(this.popChar()){case"d":p=u;break;case"D":p=u,C=!0;break;case"s":p=f;break;case"S":p=f,C=!0;break;case"w":p=g;break;case"W":p=g,C=!0;break}return a(p),{type:"Set",value:p,complement:C}},r.prototype.controlEscapeAtom=function(){var p;switch(this.popChar()){case"f":p=n("\f");break;case"n":p=n(` +`);break;case"r":p=n("\r");break;case"t":p=n(" ");break;case"v":p=n("\v");break}return a(p),{type:"Character",value:p}},r.prototype.controlLetterEscapeAtom=function(){this.consumeChar("c");var p=this.popChar();if(/[a-zA-Z]/.test(p)===!1)throw Error("Invalid ");var C=p.toUpperCase().charCodeAt(0)-64;return{type:"Character",value:C}},r.prototype.nulCharacterAtom=function(){return this.consumeChar("0"),{type:"Character",value:n("\0")}},r.prototype.hexEscapeSequenceAtom=function(){return this.consumeChar("x"),this.parseHexDigits(2)},r.prototype.regExpUnicodeEscapeSequenceAtom=function(){return this.consumeChar("u"),this.parseHexDigits(4)},r.prototype.identityEscapeAtom=function(){var p=this.popChar();return{type:"Character",value:n(p)}},r.prototype.classPatternCharacterAtom=function(){switch(this.peekChar()){case` +`:case"\r":case"\u2028":case"\u2029":case"\\":case"]":throw Error("TBD");default:var p=this.popChar();return{type:"Character",value:n(p)}}},r.prototype.characterClass=function(){var p=[],C=!1;for(this.consumeChar("["),this.peekChar(0)==="^"&&(this.consumeChar("^"),C=!0);this.isClassAtom();){var y=this.classAtom(),B=y.type==="Character";if(B&&this.isRangeDash()){this.consumeChar("-");var v=this.classAtom(),D=v.type==="Character";if(D){if(v.value=this.input.length)throw Error("Unexpected end of input");this.idx++},r.prototype.loc=function(p){return{begin:p,end:this.idx}};var e=/[0-9a-fA-F]/,t=/[0-9]/,i=/[1-9]/;function n(p){return p.charCodeAt(0)}function s(p,C){p.length!==void 0?p.forEach(function(y){C.push(y)}):C.push(p)}function o(p,C){if(p[C]===!0)throw"duplicate flag "+C;p[C]=!0}function a(p){if(p===void 0)throw Error("Internal Error - Should never get here!")}function l(){throw Error("Internal Error - Should never get here!")}var c,u=[];for(c=n("0");c<=n("9");c++)u.push(c);var g=[n("_")].concat(u);for(c=n("a");c<=n("z");c++)g.push(c);for(c=n("A");c<=n("Z");c++)g.push(c);var f=[n(" "),n("\f"),n(` +`),n("\r"),n(" "),n("\v"),n(" "),n("\xA0"),n("\u1680"),n("\u2000"),n("\u2001"),n("\u2002"),n("\u2003"),n("\u2004"),n("\u2005"),n("\u2006"),n("\u2007"),n("\u2008"),n("\u2009"),n("\u200A"),n("\u2028"),n("\u2029"),n("\u202F"),n("\u205F"),n("\u3000"),n("\uFEFF")];function h(){}return h.prototype.visitChildren=function(p){for(var C in p){var y=p[C];p.hasOwnProperty(C)&&(y.type!==void 0?this.visit(y):Array.isArray(y)&&y.forEach(function(B){this.visit(B)},this))}},h.prototype.visit=function(p){switch(p.type){case"Pattern":this.visitPattern(p);break;case"Flags":this.visitFlags(p);break;case"Disjunction":this.visitDisjunction(p);break;case"Alternative":this.visitAlternative(p);break;case"StartAnchor":this.visitStartAnchor(p);break;case"EndAnchor":this.visitEndAnchor(p);break;case"WordBoundary":this.visitWordBoundary(p);break;case"NonWordBoundary":this.visitNonWordBoundary(p);break;case"Lookahead":this.visitLookahead(p);break;case"NegativeLookahead":this.visitNegativeLookahead(p);break;case"Character":this.visitCharacter(p);break;case"Set":this.visitSet(p);break;case"Group":this.visitGroup(p);break;case"GroupBackReference":this.visitGroupBackReference(p);break;case"Quantifier":this.visitQuantifier(p);break}this.visitChildren(p)},h.prototype.visitPattern=function(p){},h.prototype.visitFlags=function(p){},h.prototype.visitDisjunction=function(p){},h.prototype.visitAlternative=function(p){},h.prototype.visitStartAnchor=function(p){},h.prototype.visitEndAnchor=function(p){},h.prototype.visitWordBoundary=function(p){},h.prototype.visitNonWordBoundary=function(p){},h.prototype.visitLookahead=function(p){},h.prototype.visitNegativeLookahead=function(p){},h.prototype.visitCharacter=function(p){},h.prototype.visitSet=function(p){},h.prototype.visitGroup=function(p){},h.prototype.visitGroupBackReference=function(p){},h.prototype.visitQuantifier=function(p){},{RegExpParser:r,BaseRegExpVisitor:h,VERSION:"0.5.0"}})});var GI=w(Ug=>{"use strict";Object.defineProperty(Ug,"__esModule",{value:!0});Ug.clearRegExpParserCache=Ug.getRegExpAst=void 0;var xme=UI(),HI={},Pme=new xme.RegExpParser;function Dme(r){var e=r.toString();if(HI.hasOwnProperty(e))return HI[e];var t=Pme.pattern(e);return HI[e]=t,t}Ug.getRegExpAst=Dme;function kme(){HI={}}Ug.clearRegExpParserCache=kme});var fY=w(pn=>{"use strict";var Rme=pn&&pn.__extends||function(){var r=function(e,t){return r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(i,n){i.__proto__=n}||function(i,n){for(var s in n)Object.prototype.hasOwnProperty.call(n,s)&&(i[s]=n[s])},r(e,t)};return function(e,t){if(typeof t!="function"&&t!==null)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");r(e,t);function i(){this.constructor=e}e.prototype=t===null?Object.create(t):(i.prototype=t.prototype,new i)}}();Object.defineProperty(pn,"__esModule",{value:!0});pn.canMatchCharCode=pn.firstCharOptimizedIndices=pn.getOptimizedStartCodesIndices=pn.failedOptimizationPrefixMsg=void 0;var cY=UI(),as=Gt(),uY=GI(),ya=Cv(),gY="Complement Sets are not supported for first char optimization";pn.failedOptimizationPrefixMsg=`Unable to use "first char" lexer optimizations: +`;function Fme(r,e){e===void 0&&(e=!1);try{var t=(0,uY.getRegExpAst)(r),i=jI(t.value,{},t.flags.ignoreCase);return i}catch(s){if(s.message===gY)e&&(0,as.PRINT_WARNING)(""+pn.failedOptimizationPrefixMsg+(" Unable to optimize: < "+r.toString()+` > +`)+` Complement Sets cannot be automatically optimized. + This will disable the lexer's first char optimizations. + See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#COMPLEMENT for details.`);else{var n="";e&&(n=` + This will disable the lexer's first char optimizations. + See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#REGEXP_PARSING for details.`),(0,as.PRINT_ERROR)(pn.failedOptimizationPrefixMsg+` +`+(" Failed parsing: < "+r.toString()+` > +`)+(" Using the regexp-to-ast library version: "+cY.VERSION+` +`)+" Please open an issue at: https://github.com/bd82/regexp-to-ast/issues"+n)}}return[]}pn.getOptimizedStartCodesIndices=Fme;function jI(r,e,t){switch(r.type){case"Disjunction":for(var i=0;i=ya.minOptimizationVal)for(var f=u.from>=ya.minOptimizationVal?u.from:ya.minOptimizationVal,h=u.to,p=(0,ya.charCodeToOptimizedIndex)(f),C=(0,ya.charCodeToOptimizedIndex)(h),y=p;y<=C;y++)e[y]=y}}});break;case"Group":jI(o.value,e,t);break;default:throw Error("Non Exhaustive Match")}var a=o.quantifier!==void 0&&o.quantifier.atLeast===0;if(o.type==="Group"&&dv(o)===!1||o.type!=="Group"&&a===!1)break}break;default:throw Error("non exhaustive match!")}return(0,as.values)(e)}pn.firstCharOptimizedIndices=jI;function YI(r,e,t){var i=(0,ya.charCodeToOptimizedIndex)(r);e[i]=i,t===!0&&Nme(r,e)}function Nme(r,e){var t=String.fromCharCode(r),i=t.toUpperCase();if(i!==t){var n=(0,ya.charCodeToOptimizedIndex)(i.charCodeAt(0));e[n]=n}else{var s=t.toLowerCase();if(s!==t){var n=(0,ya.charCodeToOptimizedIndex)(s.charCodeAt(0));e[n]=n}}}function lY(r,e){return(0,as.find)(r.value,function(t){if(typeof t=="number")return(0,as.contains)(e,t);var i=t;return(0,as.find)(e,function(n){return i.from<=n&&n<=i.to})!==void 0})}function dv(r){return r.quantifier&&r.quantifier.atLeast===0?!0:r.value?(0,as.isArray)(r.value)?(0,as.every)(r.value,dv):dv(r.value):!1}var Lme=function(r){Rme(e,r);function e(t){var i=r.call(this)||this;return i.targetCharCodes=t,i.found=!1,i}return e.prototype.visitChildren=function(t){if(this.found!==!0){switch(t.type){case"Lookahead":this.visitLookahead(t);return;case"NegativeLookahead":this.visitNegativeLookahead(t);return}r.prototype.visitChildren.call(this,t)}},e.prototype.visitCharacter=function(t){(0,as.contains)(this.targetCharCodes,t.value)&&(this.found=!0)},e.prototype.visitSet=function(t){t.complement?lY(t,this.targetCharCodes)===void 0&&(this.found=!0):lY(t,this.targetCharCodes)!==void 0&&(this.found=!0)},e}(cY.BaseRegExpVisitor);function Tme(r,e){if(e instanceof RegExp){var t=(0,uY.getRegExpAst)(e),i=new Lme(r);return i.visit(t),i.found}else return(0,as.find)(e,function(n){return(0,as.contains)(r,n.charCodeAt(0))})!==void 0}pn.canMatchCharCode=Tme});var Cv=w(Ve=>{"use strict";var hY=Ve&&Ve.__extends||function(){var r=function(e,t){return r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(i,n){i.__proto__=n}||function(i,n){for(var s in n)Object.prototype.hasOwnProperty.call(n,s)&&(i[s]=n[s])},r(e,t)};return function(e,t){if(typeof t!="function"&&t!==null)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");r(e,t);function i(){this.constructor=e}e.prototype=t===null?Object.create(t):(i.prototype=t.prototype,new i)}}();Object.defineProperty(Ve,"__esModule",{value:!0});Ve.charCodeToOptimizedIndex=Ve.minOptimizationVal=Ve.buildLineBreakIssueMessage=Ve.LineTerminatorOptimizedTester=Ve.isShortPattern=Ve.isCustomPattern=Ve.cloneEmptyGroups=Ve.performWarningRuntimeChecks=Ve.performRuntimeChecks=Ve.addStickyFlag=Ve.addStartOfInput=Ve.findUnreachablePatterns=Ve.findModesThatDoNotExist=Ve.findInvalidGroupType=Ve.findDuplicatePatterns=Ve.findUnsupportedFlags=Ve.findStartOfInputAnchor=Ve.findEmptyMatchRegExps=Ve.findEndOfInputAnchor=Ve.findInvalidPatterns=Ve.findMissingPatterns=Ve.validatePatterns=Ve.analyzeTokenTypes=Ve.enableSticky=Ve.disableSticky=Ve.SUPPORT_STICKY=Ve.MODES=Ve.DEFAULT_MODE=void 0;var pY=UI(),ir=gd(),xe=Gt(),Hg=fY(),dY=GI(),So="PATTERN";Ve.DEFAULT_MODE="defaultMode";Ve.MODES="modes";Ve.SUPPORT_STICKY=typeof new RegExp("(?:)").sticky=="boolean";function Ome(){Ve.SUPPORT_STICKY=!1}Ve.disableSticky=Ome;function Mme(){Ve.SUPPORT_STICKY=!0}Ve.enableSticky=Mme;function Kme(r,e){e=(0,xe.defaults)(e,{useSticky:Ve.SUPPORT_STICKY,debug:!1,safeMode:!1,positionTracking:"full",lineTerminatorCharacters:["\r",` +`],tracer:function(v,D){return D()}});var t=e.tracer;t("initCharCodeToOptimizedIndexMap",function(){Vme()});var i;t("Reject Lexer.NA",function(){i=(0,xe.reject)(r,function(v){return v[So]===ir.Lexer.NA})});var n=!1,s;t("Transform Patterns",function(){n=!1,s=(0,xe.map)(i,function(v){var D=v[So];if((0,xe.isRegExp)(D)){var L=D.source;return L.length===1&&L!=="^"&&L!=="$"&&L!=="."&&!D.ignoreCase?L:L.length===2&&L[0]==="\\"&&!(0,xe.contains)(["d","D","s","S","t","r","n","t","0","c","b","B","f","v","w","W"],L[1])?L[1]:e.useSticky?Iv(D):Ev(D)}else{if((0,xe.isFunction)(D))return n=!0,{exec:D};if((0,xe.has)(D,"exec"))return n=!0,D;if(typeof D=="string"){if(D.length===1)return D;var H=D.replace(/[\\^$.*+?()[\]{}|]/g,"\\$&"),j=new RegExp(H);return e.useSticky?Iv(j):Ev(j)}else throw Error("non exhaustive match")}})});var o,a,l,c,u;t("misc mapping",function(){o=(0,xe.map)(i,function(v){return v.tokenTypeIdx}),a=(0,xe.map)(i,function(v){var D=v.GROUP;if(D!==ir.Lexer.SKIPPED){if((0,xe.isString)(D))return D;if((0,xe.isUndefined)(D))return!1;throw Error("non exhaustive match")}}),l=(0,xe.map)(i,function(v){var D=v.LONGER_ALT;if(D){var L=(0,xe.isArray)(D)?(0,xe.map)(D,function(H){return(0,xe.indexOf)(i,H)}):[(0,xe.indexOf)(i,D)];return L}}),c=(0,xe.map)(i,function(v){return v.PUSH_MODE}),u=(0,xe.map)(i,function(v){return(0,xe.has)(v,"POP_MODE")})});var g;t("Line Terminator Handling",function(){var v=DY(e.lineTerminatorCharacters);g=(0,xe.map)(i,function(D){return!1}),e.positionTracking!=="onlyOffset"&&(g=(0,xe.map)(i,function(D){if((0,xe.has)(D,"LINE_BREAKS"))return D.LINE_BREAKS;if(xY(D,v)===!1)return(0,Hg.canMatchCharCode)(v,D.PATTERN)}))});var f,h,p,C;t("Misc Mapping #2",function(){f=(0,xe.map)(i,wv),h=(0,xe.map)(s,vY),p=(0,xe.reduce)(i,function(v,D){var L=D.GROUP;return(0,xe.isString)(L)&&L!==ir.Lexer.SKIPPED&&(v[L]=[]),v},{}),C=(0,xe.map)(s,function(v,D){return{pattern:s[D],longerAlt:l[D],canLineTerminator:g[D],isCustom:f[D],short:h[D],group:a[D],push:c[D],pop:u[D],tokenTypeIdx:o[D],tokenType:i[D]}})});var y=!0,B=[];return e.safeMode||t("First Char Optimization",function(){B=(0,xe.reduce)(i,function(v,D,L){if(typeof D.PATTERN=="string"){var H=D.PATTERN.charCodeAt(0),j=yv(H);mv(v,j,C[L])}else if((0,xe.isArray)(D.START_CHARS_HINT)){var $;(0,xe.forEach)(D.START_CHARS_HINT,function(W){var Z=typeof W=="string"?W.charCodeAt(0):W,A=yv(Z);$!==A&&($=A,mv(v,A,C[L]))})}else if((0,xe.isRegExp)(D.PATTERN))if(D.PATTERN.unicode)y=!1,e.ensureOptimizations&&(0,xe.PRINT_ERROR)(""+Hg.failedOptimizationPrefixMsg+(" Unable to analyze < "+D.PATTERN.toString()+` > pattern. +`)+` The regexp unicode flag is not currently supported by the regexp-to-ast library. + This will disable the lexer's first char optimizations. + For details See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#UNICODE_OPTIMIZE`);else{var V=(0,Hg.getOptimizedStartCodesIndices)(D.PATTERN,e.ensureOptimizations);(0,xe.isEmpty)(V)&&(y=!1),(0,xe.forEach)(V,function(W){mv(v,W,C[L])})}else e.ensureOptimizations&&(0,xe.PRINT_ERROR)(""+Hg.failedOptimizationPrefixMsg+(" TokenType: <"+D.name+`> is using a custom token pattern without providing parameter. +`)+` This will disable the lexer's first char optimizations. + For details See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#CUSTOM_OPTIMIZE`),y=!1;return v},[])}),t("ArrayPacking",function(){B=(0,xe.packArray)(B)}),{emptyGroups:p,patternIdxToConfig:C,charCodeToPatternIdxToConfig:B,hasCustom:n,canBeOptimized:y}}Ve.analyzeTokenTypes=Kme;function Ume(r,e){var t=[],i=CY(r);t=t.concat(i.errors);var n=mY(i.valid),s=n.valid;return t=t.concat(n.errors),t=t.concat(Hme(s)),t=t.concat(QY(s)),t=t.concat(bY(s,e)),t=t.concat(SY(s)),t}Ve.validatePatterns=Ume;function Hme(r){var e=[],t=(0,xe.filter)(r,function(i){return(0,xe.isRegExp)(i[So])});return e=e.concat(EY(t)),e=e.concat(yY(t)),e=e.concat(wY(t)),e=e.concat(BY(t)),e=e.concat(IY(t)),e}function CY(r){var e=(0,xe.filter)(r,function(n){return!(0,xe.has)(n,So)}),t=(0,xe.map)(e,function(n){return{message:"Token Type: ->"+n.name+"<- missing static 'PATTERN' property",type:ir.LexerDefinitionErrorType.MISSING_PATTERN,tokenTypes:[n]}}),i=(0,xe.difference)(r,e);return{errors:t,valid:i}}Ve.findMissingPatterns=CY;function mY(r){var e=(0,xe.filter)(r,function(n){var s=n[So];return!(0,xe.isRegExp)(s)&&!(0,xe.isFunction)(s)&&!(0,xe.has)(s,"exec")&&!(0,xe.isString)(s)}),t=(0,xe.map)(e,function(n){return{message:"Token Type: ->"+n.name+"<- static 'PATTERN' can only be a RegExp, a Function matching the {CustomPatternMatcherFunc} type or an Object matching the {ICustomPattern} interface.",type:ir.LexerDefinitionErrorType.INVALID_PATTERN,tokenTypes:[n]}}),i=(0,xe.difference)(r,e);return{errors:t,valid:i}}Ve.findInvalidPatterns=mY;var Gme=/[^\\][\$]/;function EY(r){var e=function(n){hY(s,n);function s(){var o=n!==null&&n.apply(this,arguments)||this;return o.found=!1,o}return s.prototype.visitEndAnchor=function(o){this.found=!0},s}(pY.BaseRegExpVisitor),t=(0,xe.filter)(r,function(n){var s=n[So];try{var o=(0,dY.getRegExpAst)(s),a=new e;return a.visit(o),a.found}catch{return Gme.test(s.source)}}),i=(0,xe.map)(t,function(n){return{message:`Unexpected RegExp Anchor Error: + Token Type: ->`+n.name+`<- static 'PATTERN' cannot contain end of input anchor '$' + See chevrotain.io/docs/guide/resolving_lexer_errors.html#ANCHORS for details.`,type:ir.LexerDefinitionErrorType.EOI_ANCHOR_FOUND,tokenTypes:[n]}});return i}Ve.findEndOfInputAnchor=EY;function IY(r){var e=(0,xe.filter)(r,function(i){var n=i[So];return n.test("")}),t=(0,xe.map)(e,function(i){return{message:"Token Type: ->"+i.name+"<- static 'PATTERN' must not match an empty string",type:ir.LexerDefinitionErrorType.EMPTY_MATCH_PATTERN,tokenTypes:[i]}});return t}Ve.findEmptyMatchRegExps=IY;var Yme=/[^\\[][\^]|^\^/;function yY(r){var e=function(n){hY(s,n);function s(){var o=n!==null&&n.apply(this,arguments)||this;return o.found=!1,o}return s.prototype.visitStartAnchor=function(o){this.found=!0},s}(pY.BaseRegExpVisitor),t=(0,xe.filter)(r,function(n){var s=n[So];try{var o=(0,dY.getRegExpAst)(s),a=new e;return a.visit(o),a.found}catch{return Yme.test(s.source)}}),i=(0,xe.map)(t,function(n){return{message:`Unexpected RegExp Anchor Error: + Token Type: ->`+n.name+`<- static 'PATTERN' cannot contain start of input anchor '^' + See https://chevrotain.io/docs/guide/resolving_lexer_errors.html#ANCHORS for details.`,type:ir.LexerDefinitionErrorType.SOI_ANCHOR_FOUND,tokenTypes:[n]}});return i}Ve.findStartOfInputAnchor=yY;function wY(r){var e=(0,xe.filter)(r,function(i){var n=i[So];return n instanceof RegExp&&(n.multiline||n.global)}),t=(0,xe.map)(e,function(i){return{message:"Token Type: ->"+i.name+"<- static 'PATTERN' may NOT contain global('g') or multiline('m')",type:ir.LexerDefinitionErrorType.UNSUPPORTED_FLAGS_FOUND,tokenTypes:[i]}});return t}Ve.findUnsupportedFlags=wY;function BY(r){var e=[],t=(0,xe.map)(r,function(s){return(0,xe.reduce)(r,function(o,a){return s.PATTERN.source===a.PATTERN.source&&!(0,xe.contains)(e,a)&&a.PATTERN!==ir.Lexer.NA&&(e.push(a),o.push(a)),o},[])});t=(0,xe.compact)(t);var i=(0,xe.filter)(t,function(s){return s.length>1}),n=(0,xe.map)(i,function(s){var o=(0,xe.map)(s,function(l){return l.name}),a=(0,xe.first)(s).PATTERN;return{message:"The same RegExp pattern ->"+a+"<-"+("has been used in all of the following Token Types: "+o.join(", ")+" <-"),type:ir.LexerDefinitionErrorType.DUPLICATE_PATTERNS_FOUND,tokenTypes:s}});return n}Ve.findDuplicatePatterns=BY;function QY(r){var e=(0,xe.filter)(r,function(i){if(!(0,xe.has)(i,"GROUP"))return!1;var n=i.GROUP;return n!==ir.Lexer.SKIPPED&&n!==ir.Lexer.NA&&!(0,xe.isString)(n)}),t=(0,xe.map)(e,function(i){return{message:"Token Type: ->"+i.name+"<- static 'GROUP' can only be Lexer.SKIPPED/Lexer.NA/A String",type:ir.LexerDefinitionErrorType.INVALID_GROUP_TYPE_FOUND,tokenTypes:[i]}});return t}Ve.findInvalidGroupType=QY;function bY(r,e){var t=(0,xe.filter)(r,function(n){return n.PUSH_MODE!==void 0&&!(0,xe.contains)(e,n.PUSH_MODE)}),i=(0,xe.map)(t,function(n){var s="Token Type: ->"+n.name+"<- static 'PUSH_MODE' value cannot refer to a Lexer Mode ->"+n.PUSH_MODE+"<-which does not exist";return{message:s,type:ir.LexerDefinitionErrorType.PUSH_MODE_DOES_NOT_EXIST,tokenTypes:[n]}});return i}Ve.findModesThatDoNotExist=bY;function SY(r){var e=[],t=(0,xe.reduce)(r,function(i,n,s){var o=n.PATTERN;return o===ir.Lexer.NA||((0,xe.isString)(o)?i.push({str:o,idx:s,tokenType:n}):(0,xe.isRegExp)(o)&&qme(o)&&i.push({str:o.source,idx:s,tokenType:n})),i},[]);return(0,xe.forEach)(r,function(i,n){(0,xe.forEach)(t,function(s){var o=s.str,a=s.idx,l=s.tokenType;if(n"+i.name+"<-")+`in the lexer's definition. +See https://chevrotain.io/docs/guide/resolving_lexer_errors.html#UNREACHABLE`;e.push({message:c,type:ir.LexerDefinitionErrorType.UNREACHABLE_PATTERN,tokenTypes:[i,l]})}})}),e}Ve.findUnreachablePatterns=SY;function jme(r,e){if((0,xe.isRegExp)(e)){var t=e.exec(r);return t!==null&&t.index===0}else{if((0,xe.isFunction)(e))return e(r,0,[],{});if((0,xe.has)(e,"exec"))return e.exec(r,0,[],{});if(typeof e=="string")return e===r;throw Error("non exhaustive match")}}function qme(r){var e=[".","\\","[","]","|","^","$","(",")","?","*","+","{"];return(0,xe.find)(e,function(t){return r.source.indexOf(t)!==-1})===void 0}function Ev(r){var e=r.ignoreCase?"i":"";return new RegExp("^(?:"+r.source+")",e)}Ve.addStartOfInput=Ev;function Iv(r){var e=r.ignoreCase?"iy":"y";return new RegExp(""+r.source,e)}Ve.addStickyFlag=Iv;function Jme(r,e,t){var i=[];return(0,xe.has)(r,Ve.DEFAULT_MODE)||i.push({message:"A MultiMode Lexer cannot be initialized without a <"+Ve.DEFAULT_MODE+`> property in its definition +`,type:ir.LexerDefinitionErrorType.MULTI_MODE_LEXER_WITHOUT_DEFAULT_MODE}),(0,xe.has)(r,Ve.MODES)||i.push({message:"A MultiMode Lexer cannot be initialized without a <"+Ve.MODES+`> property in its definition +`,type:ir.LexerDefinitionErrorType.MULTI_MODE_LEXER_WITHOUT_MODES_PROPERTY}),(0,xe.has)(r,Ve.MODES)&&(0,xe.has)(r,Ve.DEFAULT_MODE)&&!(0,xe.has)(r.modes,r.defaultMode)&&i.push({message:"A MultiMode Lexer cannot be initialized with a "+Ve.DEFAULT_MODE+": <"+r.defaultMode+`>which does not exist +`,type:ir.LexerDefinitionErrorType.MULTI_MODE_LEXER_DEFAULT_MODE_VALUE_DOES_NOT_EXIST}),(0,xe.has)(r,Ve.MODES)&&(0,xe.forEach)(r.modes,function(n,s){(0,xe.forEach)(n,function(o,a){(0,xe.isUndefined)(o)&&i.push({message:"A Lexer cannot be initialized using an undefined Token Type. Mode:"+("<"+s+"> at index: <"+a+`> +`),type:ir.LexerDefinitionErrorType.LEXER_DEFINITION_CANNOT_CONTAIN_UNDEFINED})})}),i}Ve.performRuntimeChecks=Jme;function Wme(r,e,t){var i=[],n=!1,s=(0,xe.compact)((0,xe.flatten)((0,xe.mapValues)(r.modes,function(l){return l}))),o=(0,xe.reject)(s,function(l){return l[So]===ir.Lexer.NA}),a=DY(t);return e&&(0,xe.forEach)(o,function(l){var c=xY(l,a);if(c!==!1){var u=PY(l,c),g={message:u,type:c.issue,tokenType:l};i.push(g)}else(0,xe.has)(l,"LINE_BREAKS")?l.LINE_BREAKS===!0&&(n=!0):(0,Hg.canMatchCharCode)(a,l.PATTERN)&&(n=!0)}),e&&!n&&i.push({message:`Warning: No LINE_BREAKS Found. + This Lexer has been defined to track line and column information, + But none of the Token Types can be identified as matching a line terminator. + See https://chevrotain.io/docs/guide/resolving_lexer_errors.html#LINE_BREAKS + for details.`,type:ir.LexerDefinitionErrorType.NO_LINE_BREAKS_FLAGS}),i}Ve.performWarningRuntimeChecks=Wme;function zme(r){var e={},t=(0,xe.keys)(r);return(0,xe.forEach)(t,function(i){var n=r[i];if((0,xe.isArray)(n))e[i]=[];else throw Error("non exhaustive match")}),e}Ve.cloneEmptyGroups=zme;function wv(r){var e=r.PATTERN;if((0,xe.isRegExp)(e))return!1;if((0,xe.isFunction)(e))return!0;if((0,xe.has)(e,"exec"))return!0;if((0,xe.isString)(e))return!1;throw Error("non exhaustive match")}Ve.isCustomPattern=wv;function vY(r){return(0,xe.isString)(r)&&r.length===1?r.charCodeAt(0):!1}Ve.isShortPattern=vY;Ve.LineTerminatorOptimizedTester={test:function(r){for(var e=r.length,t=this.lastIndex;t Token Type +`)+(" Root cause: "+e.errMsg+`. +`)+" For details See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#IDENTIFY_TERMINATOR";if(e.issue===ir.LexerDefinitionErrorType.CUSTOM_LINE_BREAK)return`Warning: A Custom Token Pattern should specify the option. +`+(" The problem is in the <"+r.name+`> Token Type +`)+" For details See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#CUSTOM_LINE_BREAK";throw Error("non exhaustive match")}Ve.buildLineBreakIssueMessage=PY;function DY(r){var e=(0,xe.map)(r,function(t){return(0,xe.isString)(t)&&t.length>0?t.charCodeAt(0):t});return e}function mv(r,e,t){r[e]===void 0?r[e]=[t]:r[e].push(t)}Ve.minOptimizationVal=256;var qI=[];function yv(r){return r255?255+~~(r/255):r}}});var Gg=w(Nt=>{"use strict";Object.defineProperty(Nt,"__esModule",{value:!0});Nt.isTokenType=Nt.hasExtendingTokensTypesMapProperty=Nt.hasExtendingTokensTypesProperty=Nt.hasCategoriesProperty=Nt.hasShortKeyProperty=Nt.singleAssignCategoriesToksMap=Nt.assignCategoriesMapProp=Nt.assignCategoriesTokensProp=Nt.assignTokenDefaultProps=Nt.expandCategories=Nt.augmentTokenTypes=Nt.tokenIdxToClass=Nt.tokenShortNameIdx=Nt.tokenStructuredMatcherNoCategories=Nt.tokenStructuredMatcher=void 0;var _r=Gt();function Xme(r,e){var t=r.tokenTypeIdx;return t===e.tokenTypeIdx?!0:e.isParent===!0&&e.categoryMatchesMap[t]===!0}Nt.tokenStructuredMatcher=Xme;function _me(r,e){return r.tokenTypeIdx===e.tokenTypeIdx}Nt.tokenStructuredMatcherNoCategories=_me;Nt.tokenShortNameIdx=1;Nt.tokenIdxToClass={};function Zme(r){var e=kY(r);RY(e),NY(e),FY(e),(0,_r.forEach)(e,function(t){t.isParent=t.categoryMatches.length>0})}Nt.augmentTokenTypes=Zme;function kY(r){for(var e=(0,_r.cloneArr)(r),t=r,i=!0;i;){t=(0,_r.compact)((0,_r.flatten)((0,_r.map)(t,function(s){return s.CATEGORIES})));var n=(0,_r.difference)(t,e);e=e.concat(n),(0,_r.isEmpty)(n)?i=!1:t=n}return e}Nt.expandCategories=kY;function RY(r){(0,_r.forEach)(r,function(e){LY(e)||(Nt.tokenIdxToClass[Nt.tokenShortNameIdx]=e,e.tokenTypeIdx=Nt.tokenShortNameIdx++),Bv(e)&&!(0,_r.isArray)(e.CATEGORIES)&&(e.CATEGORIES=[e.CATEGORIES]),Bv(e)||(e.CATEGORIES=[]),TY(e)||(e.categoryMatches=[]),OY(e)||(e.categoryMatchesMap={})})}Nt.assignTokenDefaultProps=RY;function FY(r){(0,_r.forEach)(r,function(e){e.categoryMatches=[],(0,_r.forEach)(e.categoryMatchesMap,function(t,i){e.categoryMatches.push(Nt.tokenIdxToClass[i].tokenTypeIdx)})})}Nt.assignCategoriesTokensProp=FY;function NY(r){(0,_r.forEach)(r,function(e){Qv([],e)})}Nt.assignCategoriesMapProp=NY;function Qv(r,e){(0,_r.forEach)(r,function(t){e.categoryMatchesMap[t.tokenTypeIdx]=!0}),(0,_r.forEach)(e.CATEGORIES,function(t){var i=r.concat(e);(0,_r.contains)(i,t)||Qv(i,t)})}Nt.singleAssignCategoriesToksMap=Qv;function LY(r){return(0,_r.has)(r,"tokenTypeIdx")}Nt.hasShortKeyProperty=LY;function Bv(r){return(0,_r.has)(r,"CATEGORIES")}Nt.hasCategoriesProperty=Bv;function TY(r){return(0,_r.has)(r,"categoryMatches")}Nt.hasExtendingTokensTypesProperty=TY;function OY(r){return(0,_r.has)(r,"categoryMatchesMap")}Nt.hasExtendingTokensTypesMapProperty=OY;function $me(r){return(0,_r.has)(r,"tokenTypeIdx")}Nt.isTokenType=$me});var bv=w(JI=>{"use strict";Object.defineProperty(JI,"__esModule",{value:!0});JI.defaultLexerErrorProvider=void 0;JI.defaultLexerErrorProvider={buildUnableToPopLexerModeMessage:function(r){return"Unable to pop Lexer Mode after encountering Token ->"+r.image+"<- The Mode Stack is empty"},buildUnexpectedCharactersMessage:function(r,e,t,i,n){return"unexpected character: ->"+r.charAt(e)+"<- at offset: "+e+","+(" skipped "+t+" characters.")}}});var gd=w(nc=>{"use strict";Object.defineProperty(nc,"__esModule",{value:!0});nc.Lexer=nc.LexerDefinitionErrorType=void 0;var zs=Cv(),nr=Gt(),eEe=Gg(),tEe=bv(),rEe=GI(),iEe;(function(r){r[r.MISSING_PATTERN=0]="MISSING_PATTERN",r[r.INVALID_PATTERN=1]="INVALID_PATTERN",r[r.EOI_ANCHOR_FOUND=2]="EOI_ANCHOR_FOUND",r[r.UNSUPPORTED_FLAGS_FOUND=3]="UNSUPPORTED_FLAGS_FOUND",r[r.DUPLICATE_PATTERNS_FOUND=4]="DUPLICATE_PATTERNS_FOUND",r[r.INVALID_GROUP_TYPE_FOUND=5]="INVALID_GROUP_TYPE_FOUND",r[r.PUSH_MODE_DOES_NOT_EXIST=6]="PUSH_MODE_DOES_NOT_EXIST",r[r.MULTI_MODE_LEXER_WITHOUT_DEFAULT_MODE=7]="MULTI_MODE_LEXER_WITHOUT_DEFAULT_MODE",r[r.MULTI_MODE_LEXER_WITHOUT_MODES_PROPERTY=8]="MULTI_MODE_LEXER_WITHOUT_MODES_PROPERTY",r[r.MULTI_MODE_LEXER_DEFAULT_MODE_VALUE_DOES_NOT_EXIST=9]="MULTI_MODE_LEXER_DEFAULT_MODE_VALUE_DOES_NOT_EXIST",r[r.LEXER_DEFINITION_CANNOT_CONTAIN_UNDEFINED=10]="LEXER_DEFINITION_CANNOT_CONTAIN_UNDEFINED",r[r.SOI_ANCHOR_FOUND=11]="SOI_ANCHOR_FOUND",r[r.EMPTY_MATCH_PATTERN=12]="EMPTY_MATCH_PATTERN",r[r.NO_LINE_BREAKS_FLAGS=13]="NO_LINE_BREAKS_FLAGS",r[r.UNREACHABLE_PATTERN=14]="UNREACHABLE_PATTERN",r[r.IDENTIFY_TERMINATOR=15]="IDENTIFY_TERMINATOR",r[r.CUSTOM_LINE_BREAK=16]="CUSTOM_LINE_BREAK"})(iEe=nc.LexerDefinitionErrorType||(nc.LexerDefinitionErrorType={}));var fd={deferDefinitionErrorsHandling:!1,positionTracking:"full",lineTerminatorsPattern:/\n|\r\n?/g,lineTerminatorCharacters:[` +`,"\r"],ensureOptimizations:!1,safeMode:!1,errorMessageProvider:tEe.defaultLexerErrorProvider,traceInitPerf:!1,skipValidations:!1};Object.freeze(fd);var nEe=function(){function r(e,t){var i=this;if(t===void 0&&(t=fd),this.lexerDefinition=e,this.lexerDefinitionErrors=[],this.lexerDefinitionWarning=[],this.patternIdxToConfig={},this.charCodeToPatternIdxToConfig={},this.modes=[],this.emptyGroups={},this.config=void 0,this.trackStartLines=!0,this.trackEndLines=!0,this.hasCustom=!1,this.canModeBeOptimized={},typeof t=="boolean")throw Error(`The second argument to the Lexer constructor is now an ILexerConfig Object. +a boolean 2nd argument is no longer supported`);this.config=(0,nr.merge)(fd,t);var n=this.config.traceInitPerf;n===!0?(this.traceInitMaxIdent=1/0,this.traceInitPerf=!0):typeof n=="number"&&(this.traceInitMaxIdent=n,this.traceInitPerf=!0),this.traceInitIndent=-1,this.TRACE_INIT("Lexer Constructor",function(){var s,o=!0;i.TRACE_INIT("Lexer Config handling",function(){if(i.config.lineTerminatorsPattern===fd.lineTerminatorsPattern)i.config.lineTerminatorsPattern=zs.LineTerminatorOptimizedTester;else if(i.config.lineTerminatorCharacters===fd.lineTerminatorCharacters)throw Error(`Error: Missing property on the Lexer config. + For details See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#MISSING_LINE_TERM_CHARS`);if(t.safeMode&&t.ensureOptimizations)throw Error('"safeMode" and "ensureOptimizations" flags are mutually exclusive.');i.trackStartLines=/full|onlyStart/i.test(i.config.positionTracking),i.trackEndLines=/full/i.test(i.config.positionTracking),(0,nr.isArray)(e)?(s={modes:{}},s.modes[zs.DEFAULT_MODE]=(0,nr.cloneArr)(e),s[zs.DEFAULT_MODE]=zs.DEFAULT_MODE):(o=!1,s=(0,nr.cloneObj)(e))}),i.config.skipValidations===!1&&(i.TRACE_INIT("performRuntimeChecks",function(){i.lexerDefinitionErrors=i.lexerDefinitionErrors.concat((0,zs.performRuntimeChecks)(s,i.trackStartLines,i.config.lineTerminatorCharacters))}),i.TRACE_INIT("performWarningRuntimeChecks",function(){i.lexerDefinitionWarning=i.lexerDefinitionWarning.concat((0,zs.performWarningRuntimeChecks)(s,i.trackStartLines,i.config.lineTerminatorCharacters))})),s.modes=s.modes?s.modes:{},(0,nr.forEach)(s.modes,function(u,g){s.modes[g]=(0,nr.reject)(u,function(f){return(0,nr.isUndefined)(f)})});var a=(0,nr.keys)(s.modes);if((0,nr.forEach)(s.modes,function(u,g){i.TRACE_INIT("Mode: <"+g+"> processing",function(){if(i.modes.push(g),i.config.skipValidations===!1&&i.TRACE_INIT("validatePatterns",function(){i.lexerDefinitionErrors=i.lexerDefinitionErrors.concat((0,zs.validatePatterns)(u,a))}),(0,nr.isEmpty)(i.lexerDefinitionErrors)){(0,eEe.augmentTokenTypes)(u);var f;i.TRACE_INIT("analyzeTokenTypes",function(){f=(0,zs.analyzeTokenTypes)(u,{lineTerminatorCharacters:i.config.lineTerminatorCharacters,positionTracking:t.positionTracking,ensureOptimizations:t.ensureOptimizations,safeMode:t.safeMode,tracer:i.TRACE_INIT.bind(i)})}),i.patternIdxToConfig[g]=f.patternIdxToConfig,i.charCodeToPatternIdxToConfig[g]=f.charCodeToPatternIdxToConfig,i.emptyGroups=(0,nr.merge)(i.emptyGroups,f.emptyGroups),i.hasCustom=f.hasCustom||i.hasCustom,i.canModeBeOptimized[g]=f.canBeOptimized}})}),i.defaultMode=s.defaultMode,!(0,nr.isEmpty)(i.lexerDefinitionErrors)&&!i.config.deferDefinitionErrorsHandling){var l=(0,nr.map)(i.lexerDefinitionErrors,function(u){return u.message}),c=l.join(`----------------------- +`);throw new Error(`Errors detected in definition of Lexer: +`+c)}(0,nr.forEach)(i.lexerDefinitionWarning,function(u){(0,nr.PRINT_WARNING)(u.message)}),i.TRACE_INIT("Choosing sub-methods implementations",function(){if(zs.SUPPORT_STICKY?(i.chopInput=nr.IDENTITY,i.match=i.matchWithTest):(i.updateLastIndex=nr.NOOP,i.match=i.matchWithExec),o&&(i.handleModes=nr.NOOP),i.trackStartLines===!1&&(i.computeNewColumn=nr.IDENTITY),i.trackEndLines===!1&&(i.updateTokenEndLineColumnLocation=nr.NOOP),/full/i.test(i.config.positionTracking))i.createTokenInstance=i.createFullToken;else if(/onlyStart/i.test(i.config.positionTracking))i.createTokenInstance=i.createStartOnlyToken;else if(/onlyOffset/i.test(i.config.positionTracking))i.createTokenInstance=i.createOffsetOnlyToken;else throw Error('Invalid config option: "'+i.config.positionTracking+'"');i.hasCustom?(i.addToken=i.addTokenUsingPush,i.handlePayload=i.handlePayloadWithCustom):(i.addToken=i.addTokenUsingMemberAccess,i.handlePayload=i.handlePayloadNoCustom)}),i.TRACE_INIT("Failed Optimization Warnings",function(){var u=(0,nr.reduce)(i.canModeBeOptimized,function(g,f,h){return f===!1&&g.push(h),g},[]);if(t.ensureOptimizations&&!(0,nr.isEmpty)(u))throw Error("Lexer Modes: < "+u.join(", ")+` > cannot be optimized. + Disable the "ensureOptimizations" lexer config flag to silently ignore this and run the lexer in an un-optimized mode. + Or inspect the console log for details on how to resolve these issues.`)}),i.TRACE_INIT("clearRegExpParserCache",function(){(0,rEe.clearRegExpParserCache)()}),i.TRACE_INIT("toFastProperties",function(){(0,nr.toFastProperties)(i)})})}return r.prototype.tokenize=function(e,t){if(t===void 0&&(t=this.defaultMode),!(0,nr.isEmpty)(this.lexerDefinitionErrors)){var i=(0,nr.map)(this.lexerDefinitionErrors,function(o){return o.message}),n=i.join(`----------------------- +`);throw new Error(`Unable to Tokenize because Errors detected in definition of Lexer: +`+n)}var s=this.tokenizeInternal(e,t);return s},r.prototype.tokenizeInternal=function(e,t){var i=this,n,s,o,a,l,c,u,g,f,h,p,C,y,B,v,D,L=e,H=L.length,j=0,$=0,V=this.hasCustom?0:Math.floor(e.length/10),W=new Array(V),Z=[],A=this.trackStartLines?1:void 0,ae=this.trackStartLines?1:void 0,ge=(0,zs.cloneEmptyGroups)(this.emptyGroups),re=this.trackStartLines,O=this.config.lineTerminatorsPattern,F=0,ue=[],he=[],ke=[],Fe=[];Object.freeze(Fe);var Ne=void 0;function oe(){return ue}function le(pr){var Ei=(0,zs.charCodeToOptimizedIndex)(pr),_n=he[Ei];return _n===void 0?Fe:_n}var we=function(pr){if(ke.length===1&&pr.tokenType.PUSH_MODE===void 0){var Ei=i.config.errorMessageProvider.buildUnableToPopLexerModeMessage(pr);Z.push({offset:pr.startOffset,line:pr.startLine!==void 0?pr.startLine:void 0,column:pr.startColumn!==void 0?pr.startColumn:void 0,length:pr.image.length,message:Ei})}else{ke.pop();var _n=(0,nr.last)(ke);ue=i.patternIdxToConfig[_n],he=i.charCodeToPatternIdxToConfig[_n],F=ue.length;var oa=i.canModeBeOptimized[_n]&&i.config.safeMode===!1;he&&oa?Ne=le:Ne=oe}};function fe(pr){ke.push(pr),he=this.charCodeToPatternIdxToConfig[pr],ue=this.patternIdxToConfig[pr],F=ue.length,F=ue.length;var Ei=this.canModeBeOptimized[pr]&&this.config.safeMode===!1;he&&Ei?Ne=le:Ne=oe}fe.call(this,t);for(var Ae;jc.length){c=a,u=g,Ae=tt;break}}}break}}if(c!==null){if(f=c.length,h=Ae.group,h!==void 0&&(p=Ae.tokenTypeIdx,C=this.createTokenInstance(c,j,p,Ae.tokenType,A,ae,f),this.handlePayload(C,u),h===!1?$=this.addToken(W,$,C):ge[h].push(C)),e=this.chopInput(e,f),j=j+f,ae=this.computeNewColumn(ae,f),re===!0&&Ae.canLineTerminator===!0){var It=0,Or=void 0,ii=void 0;O.lastIndex=0;do Or=O.test(c),Or===!0&&(ii=O.lastIndex-1,It++);while(Or===!0);It!==0&&(A=A+It,ae=f-ii,this.updateTokenEndLineColumnLocation(C,h,ii,It,A,ae,f))}this.handleModes(Ae,we,fe,C)}else{for(var gi=j,hr=A,fi=ae,ni=!1;!ni&&j <"+e+">");var n=(0,nr.timer)(t),s=n.time,o=n.value,a=s>10?console.warn:console.log;return this.traceInitIndent time: "+s+"ms"),this.traceInitIndent--,o}else return t()},r.SKIPPED="This marks a skipped Token pattern, this means each token identified by it willbe consumed and then thrown into oblivion, this can be used to for example to completely ignore whitespace.",r.NA=/NOT_APPLICABLE/,r}();nc.Lexer=nEe});var SA=w(Qi=>{"use strict";Object.defineProperty(Qi,"__esModule",{value:!0});Qi.tokenMatcher=Qi.createTokenInstance=Qi.EOF=Qi.createToken=Qi.hasTokenLabel=Qi.tokenName=Qi.tokenLabel=void 0;var Vs=Gt(),sEe=gd(),Sv=Gg();function oEe(r){return JY(r)?r.LABEL:r.name}Qi.tokenLabel=oEe;function aEe(r){return r.name}Qi.tokenName=aEe;function JY(r){return(0,Vs.isString)(r.LABEL)&&r.LABEL!==""}Qi.hasTokenLabel=JY;var AEe="parent",MY="categories",KY="label",UY="group",HY="push_mode",GY="pop_mode",YY="longer_alt",jY="line_breaks",qY="start_chars_hint";function WY(r){return lEe(r)}Qi.createToken=WY;function lEe(r){var e=r.pattern,t={};if(t.name=r.name,(0,Vs.isUndefined)(e)||(t.PATTERN=e),(0,Vs.has)(r,AEe))throw`The parent property is no longer supported. +See: https://github.com/chevrotain/chevrotain/issues/564#issuecomment-349062346 for details.`;return(0,Vs.has)(r,MY)&&(t.CATEGORIES=r[MY]),(0,Sv.augmentTokenTypes)([t]),(0,Vs.has)(r,KY)&&(t.LABEL=r[KY]),(0,Vs.has)(r,UY)&&(t.GROUP=r[UY]),(0,Vs.has)(r,GY)&&(t.POP_MODE=r[GY]),(0,Vs.has)(r,HY)&&(t.PUSH_MODE=r[HY]),(0,Vs.has)(r,YY)&&(t.LONGER_ALT=r[YY]),(0,Vs.has)(r,jY)&&(t.LINE_BREAKS=r[jY]),(0,Vs.has)(r,qY)&&(t.START_CHARS_HINT=r[qY]),t}Qi.EOF=WY({name:"EOF",pattern:sEe.Lexer.NA});(0,Sv.augmentTokenTypes)([Qi.EOF]);function cEe(r,e,t,i,n,s,o,a){return{image:e,startOffset:t,endOffset:i,startLine:n,endLine:s,startColumn:o,endColumn:a,tokenTypeIdx:r.tokenTypeIdx,tokenType:r}}Qi.createTokenInstance=cEe;function uEe(r,e){return(0,Sv.tokenStructuredMatcher)(r,e)}Qi.tokenMatcher=uEe});var dn=w(Wt=>{"use strict";var wa=Wt&&Wt.__extends||function(){var r=function(e,t){return r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(i,n){i.__proto__=n}||function(i,n){for(var s in n)Object.prototype.hasOwnProperty.call(n,s)&&(i[s]=n[s])},r(e,t)};return function(e,t){if(typeof t!="function"&&t!==null)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");r(e,t);function i(){this.constructor=e}e.prototype=t===null?Object.create(t):(i.prototype=t.prototype,new i)}}();Object.defineProperty(Wt,"__esModule",{value:!0});Wt.serializeProduction=Wt.serializeGrammar=Wt.Terminal=Wt.Alternation=Wt.RepetitionWithSeparator=Wt.Repetition=Wt.RepetitionMandatoryWithSeparator=Wt.RepetitionMandatory=Wt.Option=Wt.Alternative=Wt.Rule=Wt.NonTerminal=Wt.AbstractProduction=void 0;var Ar=Gt(),gEe=SA(),vo=function(){function r(e){this._definition=e}return Object.defineProperty(r.prototype,"definition",{get:function(){return this._definition},set:function(e){this._definition=e},enumerable:!1,configurable:!0}),r.prototype.accept=function(e){e.visit(this),(0,Ar.forEach)(this.definition,function(t){t.accept(e)})},r}();Wt.AbstractProduction=vo;var zY=function(r){wa(e,r);function e(t){var i=r.call(this,[])||this;return i.idx=1,(0,Ar.assign)(i,(0,Ar.pick)(t,function(n){return n!==void 0})),i}return Object.defineProperty(e.prototype,"definition",{get:function(){return this.referencedRule!==void 0?this.referencedRule.definition:[]},set:function(t){},enumerable:!1,configurable:!0}),e.prototype.accept=function(t){t.visit(this)},e}(vo);Wt.NonTerminal=zY;var VY=function(r){wa(e,r);function e(t){var i=r.call(this,t.definition)||this;return i.orgText="",(0,Ar.assign)(i,(0,Ar.pick)(t,function(n){return n!==void 0})),i}return e}(vo);Wt.Rule=VY;var XY=function(r){wa(e,r);function e(t){var i=r.call(this,t.definition)||this;return i.ignoreAmbiguities=!1,(0,Ar.assign)(i,(0,Ar.pick)(t,function(n){return n!==void 0})),i}return e}(vo);Wt.Alternative=XY;var _Y=function(r){wa(e,r);function e(t){var i=r.call(this,t.definition)||this;return i.idx=1,(0,Ar.assign)(i,(0,Ar.pick)(t,function(n){return n!==void 0})),i}return e}(vo);Wt.Option=_Y;var ZY=function(r){wa(e,r);function e(t){var i=r.call(this,t.definition)||this;return i.idx=1,(0,Ar.assign)(i,(0,Ar.pick)(t,function(n){return n!==void 0})),i}return e}(vo);Wt.RepetitionMandatory=ZY;var $Y=function(r){wa(e,r);function e(t){var i=r.call(this,t.definition)||this;return i.idx=1,(0,Ar.assign)(i,(0,Ar.pick)(t,function(n){return n!==void 0})),i}return e}(vo);Wt.RepetitionMandatoryWithSeparator=$Y;var ej=function(r){wa(e,r);function e(t){var i=r.call(this,t.definition)||this;return i.idx=1,(0,Ar.assign)(i,(0,Ar.pick)(t,function(n){return n!==void 0})),i}return e}(vo);Wt.Repetition=ej;var tj=function(r){wa(e,r);function e(t){var i=r.call(this,t.definition)||this;return i.idx=1,(0,Ar.assign)(i,(0,Ar.pick)(t,function(n){return n!==void 0})),i}return e}(vo);Wt.RepetitionWithSeparator=tj;var rj=function(r){wa(e,r);function e(t){var i=r.call(this,t.definition)||this;return i.idx=1,i.ignoreAmbiguities=!1,i.hasPredicates=!1,(0,Ar.assign)(i,(0,Ar.pick)(t,function(n){return n!==void 0})),i}return Object.defineProperty(e.prototype,"definition",{get:function(){return this._definition},set:function(t){this._definition=t},enumerable:!1,configurable:!0}),e}(vo);Wt.Alternation=rj;var WI=function(){function r(e){this.idx=1,(0,Ar.assign)(this,(0,Ar.pick)(e,function(t){return t!==void 0}))}return r.prototype.accept=function(e){e.visit(this)},r}();Wt.Terminal=WI;function fEe(r){return(0,Ar.map)(r,hd)}Wt.serializeGrammar=fEe;function hd(r){function e(s){return(0,Ar.map)(s,hd)}if(r instanceof zY){var t={type:"NonTerminal",name:r.nonTerminalName,idx:r.idx};return(0,Ar.isString)(r.label)&&(t.label=r.label),t}else{if(r instanceof XY)return{type:"Alternative",definition:e(r.definition)};if(r instanceof _Y)return{type:"Option",idx:r.idx,definition:e(r.definition)};if(r instanceof ZY)return{type:"RepetitionMandatory",idx:r.idx,definition:e(r.definition)};if(r instanceof $Y)return{type:"RepetitionMandatoryWithSeparator",idx:r.idx,separator:hd(new WI({terminalType:r.separator})),definition:e(r.definition)};if(r instanceof tj)return{type:"RepetitionWithSeparator",idx:r.idx,separator:hd(new WI({terminalType:r.separator})),definition:e(r.definition)};if(r instanceof ej)return{type:"Repetition",idx:r.idx,definition:e(r.definition)};if(r instanceof rj)return{type:"Alternation",idx:r.idx,definition:e(r.definition)};if(r instanceof WI){var i={type:"Terminal",name:r.terminalType.name,label:(0,gEe.tokenLabel)(r.terminalType),idx:r.idx};(0,Ar.isString)(r.label)&&(i.terminalLabel=r.label);var n=r.terminalType.PATTERN;return r.terminalType.PATTERN&&(i.pattern=(0,Ar.isRegExp)(n)?n.source:n),i}else{if(r instanceof VY)return{type:"Rule",name:r.name,orgText:r.orgText,definition:e(r.definition)};throw Error("non exhaustive match")}}}Wt.serializeProduction=hd});var VI=w(zI=>{"use strict";Object.defineProperty(zI,"__esModule",{value:!0});zI.RestWalker=void 0;var vv=Gt(),Cn=dn(),hEe=function(){function r(){}return r.prototype.walk=function(e,t){var i=this;t===void 0&&(t=[]),(0,vv.forEach)(e.definition,function(n,s){var o=(0,vv.drop)(e.definition,s+1);if(n instanceof Cn.NonTerminal)i.walkProdRef(n,o,t);else if(n instanceof Cn.Terminal)i.walkTerminal(n,o,t);else if(n instanceof Cn.Alternative)i.walkFlat(n,o,t);else if(n instanceof Cn.Option)i.walkOption(n,o,t);else if(n instanceof Cn.RepetitionMandatory)i.walkAtLeastOne(n,o,t);else if(n instanceof Cn.RepetitionMandatoryWithSeparator)i.walkAtLeastOneSep(n,o,t);else if(n instanceof Cn.RepetitionWithSeparator)i.walkManySep(n,o,t);else if(n instanceof Cn.Repetition)i.walkMany(n,o,t);else if(n instanceof Cn.Alternation)i.walkOr(n,o,t);else throw Error("non exhaustive match")})},r.prototype.walkTerminal=function(e,t,i){},r.prototype.walkProdRef=function(e,t,i){},r.prototype.walkFlat=function(e,t,i){var n=t.concat(i);this.walk(e,n)},r.prototype.walkOption=function(e,t,i){var n=t.concat(i);this.walk(e,n)},r.prototype.walkAtLeastOne=function(e,t,i){var n=[new Cn.Option({definition:e.definition})].concat(t,i);this.walk(e,n)},r.prototype.walkAtLeastOneSep=function(e,t,i){var n=ij(e,t,i);this.walk(e,n)},r.prototype.walkMany=function(e,t,i){var n=[new Cn.Option({definition:e.definition})].concat(t,i);this.walk(e,n)},r.prototype.walkManySep=function(e,t,i){var n=ij(e,t,i);this.walk(e,n)},r.prototype.walkOr=function(e,t,i){var n=this,s=t.concat(i);(0,vv.forEach)(e.definition,function(o){var a=new Cn.Alternative({definition:[o]});n.walk(a,s)})},r}();zI.RestWalker=hEe;function ij(r,e,t){var i=[new Cn.Option({definition:[new Cn.Terminal({terminalType:r.separator})].concat(r.definition)})],n=i.concat(e,t);return n}});var Yg=w(XI=>{"use strict";Object.defineProperty(XI,"__esModule",{value:!0});XI.GAstVisitor=void 0;var xo=dn(),pEe=function(){function r(){}return r.prototype.visit=function(e){var t=e;switch(t.constructor){case xo.NonTerminal:return this.visitNonTerminal(t);case xo.Alternative:return this.visitAlternative(t);case xo.Option:return this.visitOption(t);case xo.RepetitionMandatory:return this.visitRepetitionMandatory(t);case xo.RepetitionMandatoryWithSeparator:return this.visitRepetitionMandatoryWithSeparator(t);case xo.RepetitionWithSeparator:return this.visitRepetitionWithSeparator(t);case xo.Repetition:return this.visitRepetition(t);case xo.Alternation:return this.visitAlternation(t);case xo.Terminal:return this.visitTerminal(t);case xo.Rule:return this.visitRule(t);default:throw Error("non exhaustive match")}},r.prototype.visitNonTerminal=function(e){},r.prototype.visitAlternative=function(e){},r.prototype.visitOption=function(e){},r.prototype.visitRepetition=function(e){},r.prototype.visitRepetitionMandatory=function(e){},r.prototype.visitRepetitionMandatoryWithSeparator=function(e){},r.prototype.visitRepetitionWithSeparator=function(e){},r.prototype.visitAlternation=function(e){},r.prototype.visitTerminal=function(e){},r.prototype.visitRule=function(e){},r}();XI.GAstVisitor=pEe});var dd=w(Oi=>{"use strict";var dEe=Oi&&Oi.__extends||function(){var r=function(e,t){return r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(i,n){i.__proto__=n}||function(i,n){for(var s in n)Object.prototype.hasOwnProperty.call(n,s)&&(i[s]=n[s])},r(e,t)};return function(e,t){if(typeof t!="function"&&t!==null)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");r(e,t);function i(){this.constructor=e}e.prototype=t===null?Object.create(t):(i.prototype=t.prototype,new i)}}();Object.defineProperty(Oi,"__esModule",{value:!0});Oi.collectMethods=Oi.DslMethodsCollectorVisitor=Oi.getProductionDslName=Oi.isBranchingProd=Oi.isOptionalProd=Oi.isSequenceProd=void 0;var pd=Gt(),Qr=dn(),CEe=Yg();function mEe(r){return r instanceof Qr.Alternative||r instanceof Qr.Option||r instanceof Qr.Repetition||r instanceof Qr.RepetitionMandatory||r instanceof Qr.RepetitionMandatoryWithSeparator||r instanceof Qr.RepetitionWithSeparator||r instanceof Qr.Terminal||r instanceof Qr.Rule}Oi.isSequenceProd=mEe;function xv(r,e){e===void 0&&(e=[]);var t=r instanceof Qr.Option||r instanceof Qr.Repetition||r instanceof Qr.RepetitionWithSeparator;return t?!0:r instanceof Qr.Alternation?(0,pd.some)(r.definition,function(i){return xv(i,e)}):r instanceof Qr.NonTerminal&&(0,pd.contains)(e,r)?!1:r instanceof Qr.AbstractProduction?(r instanceof Qr.NonTerminal&&e.push(r),(0,pd.every)(r.definition,function(i){return xv(i,e)})):!1}Oi.isOptionalProd=xv;function EEe(r){return r instanceof Qr.Alternation}Oi.isBranchingProd=EEe;function IEe(r){if(r instanceof Qr.NonTerminal)return"SUBRULE";if(r instanceof Qr.Option)return"OPTION";if(r instanceof Qr.Alternation)return"OR";if(r instanceof Qr.RepetitionMandatory)return"AT_LEAST_ONE";if(r instanceof Qr.RepetitionMandatoryWithSeparator)return"AT_LEAST_ONE_SEP";if(r instanceof Qr.RepetitionWithSeparator)return"MANY_SEP";if(r instanceof Qr.Repetition)return"MANY";if(r instanceof Qr.Terminal)return"CONSUME";throw Error("non exhaustive match")}Oi.getProductionDslName=IEe;var nj=function(r){dEe(e,r);function e(){var t=r!==null&&r.apply(this,arguments)||this;return t.separator="-",t.dslMethods={option:[],alternation:[],repetition:[],repetitionWithSeparator:[],repetitionMandatory:[],repetitionMandatoryWithSeparator:[]},t}return e.prototype.reset=function(){this.dslMethods={option:[],alternation:[],repetition:[],repetitionWithSeparator:[],repetitionMandatory:[],repetitionMandatoryWithSeparator:[]}},e.prototype.visitTerminal=function(t){var i=t.terminalType.name+this.separator+"Terminal";(0,pd.has)(this.dslMethods,i)||(this.dslMethods[i]=[]),this.dslMethods[i].push(t)},e.prototype.visitNonTerminal=function(t){var i=t.nonTerminalName+this.separator+"Terminal";(0,pd.has)(this.dslMethods,i)||(this.dslMethods[i]=[]),this.dslMethods[i].push(t)},e.prototype.visitOption=function(t){this.dslMethods.option.push(t)},e.prototype.visitRepetitionWithSeparator=function(t){this.dslMethods.repetitionWithSeparator.push(t)},e.prototype.visitRepetitionMandatory=function(t){this.dslMethods.repetitionMandatory.push(t)},e.prototype.visitRepetitionMandatoryWithSeparator=function(t){this.dslMethods.repetitionMandatoryWithSeparator.push(t)},e.prototype.visitRepetition=function(t){this.dslMethods.repetition.push(t)},e.prototype.visitAlternation=function(t){this.dslMethods.alternation.push(t)},e}(CEe.GAstVisitor);Oi.DslMethodsCollectorVisitor=nj;var _I=new nj;function yEe(r){_I.reset(),r.accept(_I);var e=_I.dslMethods;return _I.reset(),e}Oi.collectMethods=yEe});var Dv=w(Po=>{"use strict";Object.defineProperty(Po,"__esModule",{value:!0});Po.firstForTerminal=Po.firstForBranching=Po.firstForSequence=Po.first=void 0;var ZI=Gt(),sj=dn(),Pv=dd();function $I(r){if(r instanceof sj.NonTerminal)return $I(r.referencedRule);if(r instanceof sj.Terminal)return Aj(r);if((0,Pv.isSequenceProd)(r))return oj(r);if((0,Pv.isBranchingProd)(r))return aj(r);throw Error("non exhaustive match")}Po.first=$I;function oj(r){for(var e=[],t=r.definition,i=0,n=t.length>i,s,o=!0;n&&o;)s=t[i],o=(0,Pv.isOptionalProd)(s),e=e.concat($I(s)),i=i+1,n=t.length>i;return(0,ZI.uniq)(e)}Po.firstForSequence=oj;function aj(r){var e=(0,ZI.map)(r.definition,function(t){return $I(t)});return(0,ZI.uniq)((0,ZI.flatten)(e))}Po.firstForBranching=aj;function Aj(r){return[r.terminalType]}Po.firstForTerminal=Aj});var kv=w(ey=>{"use strict";Object.defineProperty(ey,"__esModule",{value:!0});ey.IN=void 0;ey.IN="_~IN~_"});var fj=w(As=>{"use strict";var wEe=As&&As.__extends||function(){var r=function(e,t){return r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(i,n){i.__proto__=n}||function(i,n){for(var s in n)Object.prototype.hasOwnProperty.call(n,s)&&(i[s]=n[s])},r(e,t)};return function(e,t){if(typeof t!="function"&&t!==null)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");r(e,t);function i(){this.constructor=e}e.prototype=t===null?Object.create(t):(i.prototype=t.prototype,new i)}}();Object.defineProperty(As,"__esModule",{value:!0});As.buildInProdFollowPrefix=As.buildBetweenProdsFollowPrefix=As.computeAllProdsFollows=As.ResyncFollowsWalker=void 0;var BEe=VI(),QEe=Dv(),lj=Gt(),cj=kv(),bEe=dn(),uj=function(r){wEe(e,r);function e(t){var i=r.call(this)||this;return i.topProd=t,i.follows={},i}return e.prototype.startWalking=function(){return this.walk(this.topProd),this.follows},e.prototype.walkTerminal=function(t,i,n){},e.prototype.walkProdRef=function(t,i,n){var s=gj(t.referencedRule,t.idx)+this.topProd.name,o=i.concat(n),a=new bEe.Alternative({definition:o}),l=(0,QEe.first)(a);this.follows[s]=l},e}(BEe.RestWalker);As.ResyncFollowsWalker=uj;function SEe(r){var e={};return(0,lj.forEach)(r,function(t){var i=new uj(t).startWalking();(0,lj.assign)(e,i)}),e}As.computeAllProdsFollows=SEe;function gj(r,e){return r.name+e+cj.IN}As.buildBetweenProdsFollowPrefix=gj;function vEe(r){var e=r.terminalType.name;return e+r.idx+cj.IN}As.buildInProdFollowPrefix=vEe});var Cd=w(Ba=>{"use strict";Object.defineProperty(Ba,"__esModule",{value:!0});Ba.defaultGrammarValidatorErrorProvider=Ba.defaultGrammarResolverErrorProvider=Ba.defaultParserErrorProvider=void 0;var jg=SA(),xEe=Gt(),Xs=Gt(),Rv=dn(),hj=dd();Ba.defaultParserErrorProvider={buildMismatchTokenMessage:function(r){var e=r.expected,t=r.actual,i=r.previous,n=r.ruleName,s=(0,jg.hasTokenLabel)(e),o=s?"--> "+(0,jg.tokenLabel)(e)+" <--":"token of type --> "+e.name+" <--",a="Expecting "+o+" but found --> '"+t.image+"' <--";return a},buildNotAllInputParsedMessage:function(r){var e=r.firstRedundant,t=r.ruleName;return"Redundant input, expecting EOF but found: "+e.image},buildNoViableAltMessage:function(r){var e=r.expectedPathsPerAlt,t=r.actual,i=r.previous,n=r.customUserDescription,s=r.ruleName,o="Expecting: ",a=(0,Xs.first)(t).image,l=` +but found: '`+a+"'";if(n)return o+n+l;var c=(0,Xs.reduce)(e,function(h,p){return h.concat(p)},[]),u=(0,Xs.map)(c,function(h){return"["+(0,Xs.map)(h,function(p){return(0,jg.tokenLabel)(p)}).join(", ")+"]"}),g=(0,Xs.map)(u,function(h,p){return" "+(p+1)+". "+h}),f=`one of these possible Token sequences: +`+g.join(` +`);return o+f+l},buildEarlyExitMessage:function(r){var e=r.expectedIterationPaths,t=r.actual,i=r.customUserDescription,n=r.ruleName,s="Expecting: ",o=(0,Xs.first)(t).image,a=` +but found: '`+o+"'";if(i)return s+i+a;var l=(0,Xs.map)(e,function(u){return"["+(0,Xs.map)(u,function(g){return(0,jg.tokenLabel)(g)}).join(",")+"]"}),c=`expecting at least one iteration which starts with one of these possible Token sequences:: + `+("<"+l.join(" ,")+">");return s+c+a}};Object.freeze(Ba.defaultParserErrorProvider);Ba.defaultGrammarResolverErrorProvider={buildRuleNotFoundError:function(r,e){var t="Invalid grammar, reference to a rule which is not defined: ->"+e.nonTerminalName+`<- +inside top level rule: ->`+r.name+"<-";return t}};Ba.defaultGrammarValidatorErrorProvider={buildDuplicateFoundError:function(r,e){function t(u){return u instanceof Rv.Terminal?u.terminalType.name:u instanceof Rv.NonTerminal?u.nonTerminalName:""}var i=r.name,n=(0,Xs.first)(e),s=n.idx,o=(0,hj.getProductionDslName)(n),a=t(n),l=s>0,c="->"+o+(l?s:"")+"<- "+(a?"with argument: ->"+a+"<-":"")+` + appears more than once (`+e.length+" times) in the top level rule: ->"+i+`<-. + For further details see: https://chevrotain.io/docs/FAQ.html#NUMERICAL_SUFFIXES + `;return c=c.replace(/[ \t]+/g," "),c=c.replace(/\s\s+/g,` +`),c},buildNamespaceConflictError:function(r){var e=`Namespace conflict found in grammar. +`+("The grammar has both a Terminal(Token) and a Non-Terminal(Rule) named: <"+r.name+`>. +`)+`To resolve this make sure each Terminal and Non-Terminal names are unique +This is easy to accomplish by using the convention that Terminal names start with an uppercase letter +and Non-Terminal names start with a lower case letter.`;return e},buildAlternationPrefixAmbiguityError:function(r){var e=(0,Xs.map)(r.prefixPath,function(n){return(0,jg.tokenLabel)(n)}).join(", "),t=r.alternation.idx===0?"":r.alternation.idx,i="Ambiguous alternatives: <"+r.ambiguityIndices.join(" ,")+`> due to common lookahead prefix +`+("in inside <"+r.topLevelRule.name+`> Rule, +`)+("<"+e+`> may appears as a prefix path in all these alternatives. +`)+`See: https://chevrotain.io/docs/guide/resolving_grammar_errors.html#COMMON_PREFIX +For Further details.`;return i},buildAlternationAmbiguityError:function(r){var e=(0,Xs.map)(r.prefixPath,function(n){return(0,jg.tokenLabel)(n)}).join(", "),t=r.alternation.idx===0?"":r.alternation.idx,i="Ambiguous Alternatives Detected: <"+r.ambiguityIndices.join(" ,")+"> in "+(" inside <"+r.topLevelRule.name+`> Rule, +`)+("<"+e+`> may appears as a prefix path in all these alternatives. +`);return i=i+`See: https://chevrotain.io/docs/guide/resolving_grammar_errors.html#AMBIGUOUS_ALTERNATIVES +For Further details.`,i},buildEmptyRepetitionError:function(r){var e=(0,hj.getProductionDslName)(r.repetition);r.repetition.idx!==0&&(e+=r.repetition.idx);var t="The repetition <"+e+"> within Rule <"+r.topLevelRule.name+`> can never consume any tokens. +This could lead to an infinite loop.`;return t},buildTokenNameError:function(r){return"deprecated"},buildEmptyAlternationError:function(r){var e="Ambiguous empty alternative: <"+(r.emptyChoiceIdx+1)+">"+(" in inside <"+r.topLevelRule.name+`> Rule. +`)+"Only the last alternative may be an empty alternative.";return e},buildTooManyAlternativesError:function(r){var e=`An Alternation cannot have more than 256 alternatives: +`+(" inside <"+r.topLevelRule.name+`> Rule. + has `+(r.alternation.definition.length+1)+" alternatives.");return e},buildLeftRecursionError:function(r){var e=r.topLevelRule.name,t=xEe.map(r.leftRecursionPath,function(s){return s.name}),i=e+" --> "+t.concat([e]).join(" --> "),n=`Left Recursion found in grammar. +`+("rule: <"+e+`> can be invoked from itself (directly or indirectly) +`)+(`without consuming any Tokens. The grammar path that causes this is: + `+i+` +`)+` To fix this refactor your grammar to remove the left recursion. +see: https://en.wikipedia.org/wiki/LL_parser#Left_Factoring.`;return n},buildInvalidRuleNameError:function(r){return"deprecated"},buildDuplicateRuleNameError:function(r){var e;r.topLevelRule instanceof Rv.Rule?e=r.topLevelRule.name:e=r.topLevelRule;var t="Duplicate definition, rule: ->"+e+"<- is already defined in the grammar: ->"+r.grammarName+"<-";return t}}});var Cj=w(vA=>{"use strict";var PEe=vA&&vA.__extends||function(){var r=function(e,t){return r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(i,n){i.__proto__=n}||function(i,n){for(var s in n)Object.prototype.hasOwnProperty.call(n,s)&&(i[s]=n[s])},r(e,t)};return function(e,t){if(typeof t!="function"&&t!==null)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");r(e,t);function i(){this.constructor=e}e.prototype=t===null?Object.create(t):(i.prototype=t.prototype,new i)}}();Object.defineProperty(vA,"__esModule",{value:!0});vA.GastRefResolverVisitor=vA.resolveGrammar=void 0;var DEe=Hn(),pj=Gt(),kEe=Yg();function REe(r,e){var t=new dj(r,e);return t.resolveRefs(),t.errors}vA.resolveGrammar=REe;var dj=function(r){PEe(e,r);function e(t,i){var n=r.call(this)||this;return n.nameToTopRule=t,n.errMsgProvider=i,n.errors=[],n}return e.prototype.resolveRefs=function(){var t=this;(0,pj.forEach)((0,pj.values)(this.nameToTopRule),function(i){t.currTopLevel=i,i.accept(t)})},e.prototype.visitNonTerminal=function(t){var i=this.nameToTopRule[t.nonTerminalName];if(i)t.referencedRule=i;else{var n=this.errMsgProvider.buildRuleNotFoundError(this.currTopLevel,t);this.errors.push({message:n,type:DEe.ParserDefinitionErrorType.UNRESOLVED_SUBRULE_REF,ruleName:this.currTopLevel.name,unresolvedRefName:t.nonTerminalName})}},e}(kEe.GAstVisitor);vA.GastRefResolverVisitor=dj});var Ed=w(Nr=>{"use strict";var sc=Nr&&Nr.__extends||function(){var r=function(e,t){return r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(i,n){i.__proto__=n}||function(i,n){for(var s in n)Object.prototype.hasOwnProperty.call(n,s)&&(i[s]=n[s])},r(e,t)};return function(e,t){if(typeof t!="function"&&t!==null)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");r(e,t);function i(){this.constructor=e}e.prototype=t===null?Object.create(t):(i.prototype=t.prototype,new i)}}();Object.defineProperty(Nr,"__esModule",{value:!0});Nr.nextPossibleTokensAfter=Nr.possiblePathsFrom=Nr.NextTerminalAfterAtLeastOneSepWalker=Nr.NextTerminalAfterAtLeastOneWalker=Nr.NextTerminalAfterManySepWalker=Nr.NextTerminalAfterManyWalker=Nr.AbstractNextTerminalAfterProductionWalker=Nr.NextAfterTokenWalker=Nr.AbstractNextPossibleTokensWalker=void 0;var mj=VI(),Kt=Gt(),FEe=Dv(),kt=dn(),Ej=function(r){sc(e,r);function e(t,i){var n=r.call(this)||this;return n.topProd=t,n.path=i,n.possibleTokTypes=[],n.nextProductionName="",n.nextProductionOccurrence=0,n.found=!1,n.isAtEndOfPath=!1,n}return e.prototype.startWalking=function(){if(this.found=!1,this.path.ruleStack[0]!==this.topProd.name)throw Error("The path does not start with the walker's top Rule!");return this.ruleStack=(0,Kt.cloneArr)(this.path.ruleStack).reverse(),this.occurrenceStack=(0,Kt.cloneArr)(this.path.occurrenceStack).reverse(),this.ruleStack.pop(),this.occurrenceStack.pop(),this.updateExpectedNext(),this.walk(this.topProd),this.possibleTokTypes},e.prototype.walk=function(t,i){i===void 0&&(i=[]),this.found||r.prototype.walk.call(this,t,i)},e.prototype.walkProdRef=function(t,i,n){if(t.referencedRule.name===this.nextProductionName&&t.idx===this.nextProductionOccurrence){var s=i.concat(n);this.updateExpectedNext(),this.walk(t.referencedRule,s)}},e.prototype.updateExpectedNext=function(){(0,Kt.isEmpty)(this.ruleStack)?(this.nextProductionName="",this.nextProductionOccurrence=0,this.isAtEndOfPath=!0):(this.nextProductionName=this.ruleStack.pop(),this.nextProductionOccurrence=this.occurrenceStack.pop())},e}(mj.RestWalker);Nr.AbstractNextPossibleTokensWalker=Ej;var NEe=function(r){sc(e,r);function e(t,i){var n=r.call(this,t,i)||this;return n.path=i,n.nextTerminalName="",n.nextTerminalOccurrence=0,n.nextTerminalName=n.path.lastTok.name,n.nextTerminalOccurrence=n.path.lastTokOccurrence,n}return e.prototype.walkTerminal=function(t,i,n){if(this.isAtEndOfPath&&t.terminalType.name===this.nextTerminalName&&t.idx===this.nextTerminalOccurrence&&!this.found){var s=i.concat(n),o=new kt.Alternative({definition:s});this.possibleTokTypes=(0,FEe.first)(o),this.found=!0}},e}(Ej);Nr.NextAfterTokenWalker=NEe;var md=function(r){sc(e,r);function e(t,i){var n=r.call(this)||this;return n.topRule=t,n.occurrence=i,n.result={token:void 0,occurrence:void 0,isEndOfRule:void 0},n}return e.prototype.startWalking=function(){return this.walk(this.topRule),this.result},e}(mj.RestWalker);Nr.AbstractNextTerminalAfterProductionWalker=md;var LEe=function(r){sc(e,r);function e(){return r!==null&&r.apply(this,arguments)||this}return e.prototype.walkMany=function(t,i,n){if(t.idx===this.occurrence){var s=(0,Kt.first)(i.concat(n));this.result.isEndOfRule=s===void 0,s instanceof kt.Terminal&&(this.result.token=s.terminalType,this.result.occurrence=s.idx)}else r.prototype.walkMany.call(this,t,i,n)},e}(md);Nr.NextTerminalAfterManyWalker=LEe;var TEe=function(r){sc(e,r);function e(){return r!==null&&r.apply(this,arguments)||this}return e.prototype.walkManySep=function(t,i,n){if(t.idx===this.occurrence){var s=(0,Kt.first)(i.concat(n));this.result.isEndOfRule=s===void 0,s instanceof kt.Terminal&&(this.result.token=s.terminalType,this.result.occurrence=s.idx)}else r.prototype.walkManySep.call(this,t,i,n)},e}(md);Nr.NextTerminalAfterManySepWalker=TEe;var OEe=function(r){sc(e,r);function e(){return r!==null&&r.apply(this,arguments)||this}return e.prototype.walkAtLeastOne=function(t,i,n){if(t.idx===this.occurrence){var s=(0,Kt.first)(i.concat(n));this.result.isEndOfRule=s===void 0,s instanceof kt.Terminal&&(this.result.token=s.terminalType,this.result.occurrence=s.idx)}else r.prototype.walkAtLeastOne.call(this,t,i,n)},e}(md);Nr.NextTerminalAfterAtLeastOneWalker=OEe;var MEe=function(r){sc(e,r);function e(){return r!==null&&r.apply(this,arguments)||this}return e.prototype.walkAtLeastOneSep=function(t,i,n){if(t.idx===this.occurrence){var s=(0,Kt.first)(i.concat(n));this.result.isEndOfRule=s===void 0,s instanceof kt.Terminal&&(this.result.token=s.terminalType,this.result.occurrence=s.idx)}else r.prototype.walkAtLeastOneSep.call(this,t,i,n)},e}(md);Nr.NextTerminalAfterAtLeastOneSepWalker=MEe;function Ij(r,e,t){t===void 0&&(t=[]),t=(0,Kt.cloneArr)(t);var i=[],n=0;function s(c){return c.concat((0,Kt.drop)(r,n+1))}function o(c){var u=Ij(s(c),e,t);return i.concat(u)}for(;t.length=0;ge--){var re=B.definition[ge],O={idx:p,def:re.definition.concat((0,Kt.drop)(h)),ruleStack:C,occurrenceStack:y};g.push(O),g.push(o)}else if(B instanceof kt.Alternative)g.push({idx:p,def:B.definition.concat((0,Kt.drop)(h)),ruleStack:C,occurrenceStack:y});else if(B instanceof kt.Rule)g.push(UEe(B,p,C,y));else throw Error("non exhaustive match")}}return u}Nr.nextPossibleTokensAfter=KEe;function UEe(r,e,t,i){var n=(0,Kt.cloneArr)(t);n.push(r.name);var s=(0,Kt.cloneArr)(i);return s.push(1),{idx:e,def:r.definition,ruleStack:n,occurrenceStack:s}}});var Id=w(_t=>{"use strict";var Bj=_t&&_t.__extends||function(){var r=function(e,t){return r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(i,n){i.__proto__=n}||function(i,n){for(var s in n)Object.prototype.hasOwnProperty.call(n,s)&&(i[s]=n[s])},r(e,t)};return function(e,t){if(typeof t!="function"&&t!==null)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");r(e,t);function i(){this.constructor=e}e.prototype=t===null?Object.create(t):(i.prototype=t.prototype,new i)}}();Object.defineProperty(_t,"__esModule",{value:!0});_t.areTokenCategoriesNotUsed=_t.isStrictPrefixOfPath=_t.containsPath=_t.getLookaheadPathsForOptionalProd=_t.getLookaheadPathsForOr=_t.lookAheadSequenceFromAlternatives=_t.buildSingleAlternativeLookaheadFunction=_t.buildAlternativesLookAheadFunc=_t.buildLookaheadFuncForOptionalProd=_t.buildLookaheadFuncForOr=_t.getProdType=_t.PROD_TYPE=void 0;var sr=Gt(),yj=Ed(),HEe=VI(),ty=Gg(),xA=dn(),GEe=Yg(),oi;(function(r){r[r.OPTION=0]="OPTION",r[r.REPETITION=1]="REPETITION",r[r.REPETITION_MANDATORY=2]="REPETITION_MANDATORY",r[r.REPETITION_MANDATORY_WITH_SEPARATOR=3]="REPETITION_MANDATORY_WITH_SEPARATOR",r[r.REPETITION_WITH_SEPARATOR=4]="REPETITION_WITH_SEPARATOR",r[r.ALTERNATION=5]="ALTERNATION"})(oi=_t.PROD_TYPE||(_t.PROD_TYPE={}));function YEe(r){if(r instanceof xA.Option)return oi.OPTION;if(r instanceof xA.Repetition)return oi.REPETITION;if(r instanceof xA.RepetitionMandatory)return oi.REPETITION_MANDATORY;if(r instanceof xA.RepetitionMandatoryWithSeparator)return oi.REPETITION_MANDATORY_WITH_SEPARATOR;if(r instanceof xA.RepetitionWithSeparator)return oi.REPETITION_WITH_SEPARATOR;if(r instanceof xA.Alternation)return oi.ALTERNATION;throw Error("non exhaustive match")}_t.getProdType=YEe;function jEe(r,e,t,i,n,s){var o=bj(r,e,t),a=Lv(o)?ty.tokenStructuredMatcherNoCategories:ty.tokenStructuredMatcher;return s(o,i,a,n)}_t.buildLookaheadFuncForOr=jEe;function qEe(r,e,t,i,n,s){var o=Sj(r,e,n,t),a=Lv(o)?ty.tokenStructuredMatcherNoCategories:ty.tokenStructuredMatcher;return s(o[0],a,i)}_t.buildLookaheadFuncForOptionalProd=qEe;function JEe(r,e,t,i){var n=r.length,s=(0,sr.every)(r,function(l){return(0,sr.every)(l,function(c){return c.length===1})});if(e)return function(l){for(var c=(0,sr.map)(l,function(D){return D.GATE}),u=0;u{"use strict";var Tv=zt&&zt.__extends||function(){var r=function(e,t){return r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(i,n){i.__proto__=n}||function(i,n){for(var s in n)Object.prototype.hasOwnProperty.call(n,s)&&(i[s]=n[s])},r(e,t)};return function(e,t){if(typeof t!="function"&&t!==null)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");r(e,t);function i(){this.constructor=e}e.prototype=t===null?Object.create(t):(i.prototype=t.prototype,new i)}}();Object.defineProperty(zt,"__esModule",{value:!0});zt.checkPrefixAlternativesAmbiguities=zt.validateSomeNonEmptyLookaheadPath=zt.validateTooManyAlts=zt.RepetionCollector=zt.validateAmbiguousAlternationAlternatives=zt.validateEmptyOrAlternative=zt.getFirstNoneTerminal=zt.validateNoLeftRecursion=zt.validateRuleIsOverridden=zt.validateRuleDoesNotAlreadyExist=zt.OccurrenceValidationCollector=zt.identifyProductionForDuplicates=zt.validateGrammar=void 0;var er=Gt(),br=Gt(),Do=Hn(),Ov=dd(),qg=Id(),_Ee=Ed(),_s=dn(),Mv=Yg();function ZEe(r,e,t,i,n){var s=er.map(r,function(h){return $Ee(h,i)}),o=er.map(r,function(h){return Kv(h,h,i)}),a=[],l=[],c=[];(0,br.every)(o,br.isEmpty)&&(a=(0,br.map)(r,function(h){return Rj(h,i)}),l=(0,br.map)(r,function(h){return Fj(h,e,i)}),c=Tj(r,e,i));var u=rIe(r,t,i),g=(0,br.map)(r,function(h){return Lj(h,i)}),f=(0,br.map)(r,function(h){return kj(h,r,n,i)});return er.flatten(s.concat(c,o,a,l,u,g,f))}zt.validateGrammar=ZEe;function $Ee(r,e){var t=new Dj;r.accept(t);var i=t.allProductions,n=er.groupBy(i,xj),s=er.pick(n,function(a){return a.length>1}),o=er.map(er.values(s),function(a){var l=er.first(a),c=e.buildDuplicateFoundError(r,a),u=(0,Ov.getProductionDslName)(l),g={message:c,type:Do.ParserDefinitionErrorType.DUPLICATE_PRODUCTIONS,ruleName:r.name,dslName:u,occurrence:l.idx},f=Pj(l);return f&&(g.parameter=f),g});return o}function xj(r){return(0,Ov.getProductionDslName)(r)+"_#_"+r.idx+"_#_"+Pj(r)}zt.identifyProductionForDuplicates=xj;function Pj(r){return r instanceof _s.Terminal?r.terminalType.name:r instanceof _s.NonTerminal?r.nonTerminalName:""}var Dj=function(r){Tv(e,r);function e(){var t=r!==null&&r.apply(this,arguments)||this;return t.allProductions=[],t}return e.prototype.visitNonTerminal=function(t){this.allProductions.push(t)},e.prototype.visitOption=function(t){this.allProductions.push(t)},e.prototype.visitRepetitionWithSeparator=function(t){this.allProductions.push(t)},e.prototype.visitRepetitionMandatory=function(t){this.allProductions.push(t)},e.prototype.visitRepetitionMandatoryWithSeparator=function(t){this.allProductions.push(t)},e.prototype.visitRepetition=function(t){this.allProductions.push(t)},e.prototype.visitAlternation=function(t){this.allProductions.push(t)},e.prototype.visitTerminal=function(t){this.allProductions.push(t)},e}(Mv.GAstVisitor);zt.OccurrenceValidationCollector=Dj;function kj(r,e,t,i){var n=[],s=(0,br.reduce)(e,function(a,l){return l.name===r.name?a+1:a},0);if(s>1){var o=i.buildDuplicateRuleNameError({topLevelRule:r,grammarName:t});n.push({message:o,type:Do.ParserDefinitionErrorType.DUPLICATE_RULE_NAME,ruleName:r.name})}return n}zt.validateRuleDoesNotAlreadyExist=kj;function eIe(r,e,t){var i=[],n;return er.contains(e,r)||(n="Invalid rule override, rule: ->"+r+"<- cannot be overridden in the grammar: ->"+t+"<-as it is not defined in any of the super grammars ",i.push({message:n,type:Do.ParserDefinitionErrorType.INVALID_RULE_OVERRIDE,ruleName:r})),i}zt.validateRuleIsOverridden=eIe;function Kv(r,e,t,i){i===void 0&&(i=[]);var n=[],s=yd(e.definition);if(er.isEmpty(s))return[];var o=r.name,a=er.contains(s,r);a&&n.push({message:t.buildLeftRecursionError({topLevelRule:r,leftRecursionPath:i}),type:Do.ParserDefinitionErrorType.LEFT_RECURSION,ruleName:o});var l=er.difference(s,i.concat([r])),c=er.map(l,function(u){var g=er.cloneArr(i);return g.push(u),Kv(r,u,t,g)});return n.concat(er.flatten(c))}zt.validateNoLeftRecursion=Kv;function yd(r){var e=[];if(er.isEmpty(r))return e;var t=er.first(r);if(t instanceof _s.NonTerminal)e.push(t.referencedRule);else if(t instanceof _s.Alternative||t instanceof _s.Option||t instanceof _s.RepetitionMandatory||t instanceof _s.RepetitionMandatoryWithSeparator||t instanceof _s.RepetitionWithSeparator||t instanceof _s.Repetition)e=e.concat(yd(t.definition));else if(t instanceof _s.Alternation)e=er.flatten(er.map(t.definition,function(o){return yd(o.definition)}));else if(!(t instanceof _s.Terminal))throw Error("non exhaustive match");var i=(0,Ov.isOptionalProd)(t),n=r.length>1;if(i&&n){var s=er.drop(r);return e.concat(yd(s))}else return e}zt.getFirstNoneTerminal=yd;var Uv=function(r){Tv(e,r);function e(){var t=r!==null&&r.apply(this,arguments)||this;return t.alternations=[],t}return e.prototype.visitAlternation=function(t){this.alternations.push(t)},e}(Mv.GAstVisitor);function Rj(r,e){var t=new Uv;r.accept(t);var i=t.alternations,n=er.reduce(i,function(s,o){var a=er.dropRight(o.definition),l=er.map(a,function(c,u){var g=(0,_Ee.nextPossibleTokensAfter)([c],[],null,1);return er.isEmpty(g)?{message:e.buildEmptyAlternationError({topLevelRule:r,alternation:o,emptyChoiceIdx:u}),type:Do.ParserDefinitionErrorType.NONE_LAST_EMPTY_ALT,ruleName:r.name,occurrence:o.idx,alternative:u+1}:null});return s.concat(er.compact(l))},[]);return n}zt.validateEmptyOrAlternative=Rj;function Fj(r,e,t){var i=new Uv;r.accept(i);var n=i.alternations;n=(0,br.reject)(n,function(o){return o.ignoreAmbiguities===!0});var s=er.reduce(n,function(o,a){var l=a.idx,c=a.maxLookahead||e,u=(0,qg.getLookaheadPathsForOr)(l,r,c,a),g=tIe(u,a,r,t),f=Oj(u,a,r,t);return o.concat(g,f)},[]);return s}zt.validateAmbiguousAlternationAlternatives=Fj;var Nj=function(r){Tv(e,r);function e(){var t=r!==null&&r.apply(this,arguments)||this;return t.allProductions=[],t}return e.prototype.visitRepetitionWithSeparator=function(t){this.allProductions.push(t)},e.prototype.visitRepetitionMandatory=function(t){this.allProductions.push(t)},e.prototype.visitRepetitionMandatoryWithSeparator=function(t){this.allProductions.push(t)},e.prototype.visitRepetition=function(t){this.allProductions.push(t)},e}(Mv.GAstVisitor);zt.RepetionCollector=Nj;function Lj(r,e){var t=new Uv;r.accept(t);var i=t.alternations,n=er.reduce(i,function(s,o){return o.definition.length>255&&s.push({message:e.buildTooManyAlternativesError({topLevelRule:r,alternation:o}),type:Do.ParserDefinitionErrorType.TOO_MANY_ALTS,ruleName:r.name,occurrence:o.idx}),s},[]);return n}zt.validateTooManyAlts=Lj;function Tj(r,e,t){var i=[];return(0,br.forEach)(r,function(n){var s=new Nj;n.accept(s);var o=s.allProductions;(0,br.forEach)(o,function(a){var l=(0,qg.getProdType)(a),c=a.maxLookahead||e,u=a.idx,g=(0,qg.getLookaheadPathsForOptionalProd)(u,n,l,c),f=g[0];if((0,br.isEmpty)((0,br.flatten)(f))){var h=t.buildEmptyRepetitionError({topLevelRule:n,repetition:a});i.push({message:h,type:Do.ParserDefinitionErrorType.NO_NON_EMPTY_LOOKAHEAD,ruleName:n.name})}})}),i}zt.validateSomeNonEmptyLookaheadPath=Tj;function tIe(r,e,t,i){var n=[],s=(0,br.reduce)(r,function(a,l,c){return e.definition[c].ignoreAmbiguities===!0||(0,br.forEach)(l,function(u){var g=[c];(0,br.forEach)(r,function(f,h){c!==h&&(0,qg.containsPath)(f,u)&&e.definition[h].ignoreAmbiguities!==!0&&g.push(h)}),g.length>1&&!(0,qg.containsPath)(n,u)&&(n.push(u),a.push({alts:g,path:u}))}),a},[]),o=er.map(s,function(a){var l=(0,br.map)(a.alts,function(u){return u+1}),c=i.buildAlternationAmbiguityError({topLevelRule:t,alternation:e,ambiguityIndices:l,prefixPath:a.path});return{message:c,type:Do.ParserDefinitionErrorType.AMBIGUOUS_ALTS,ruleName:t.name,occurrence:e.idx,alternatives:[a.alts]}});return o}function Oj(r,e,t,i){var n=[],s=(0,br.reduce)(r,function(o,a,l){var c=(0,br.map)(a,function(u){return{idx:l,path:u}});return o.concat(c)},[]);return(0,br.forEach)(s,function(o){var a=e.definition[o.idx];if(a.ignoreAmbiguities!==!0){var l=o.idx,c=o.path,u=(0,br.findAll)(s,function(f){return e.definition[f.idx].ignoreAmbiguities!==!0&&f.idx{"use strict";Object.defineProperty(Jg,"__esModule",{value:!0});Jg.validateGrammar=Jg.resolveGrammar=void 0;var Gv=Gt(),iIe=Cj(),nIe=Hv(),Mj=Cd();function sIe(r){r=(0,Gv.defaults)(r,{errMsgProvider:Mj.defaultGrammarResolverErrorProvider});var e={};return(0,Gv.forEach)(r.rules,function(t){e[t.name]=t}),(0,iIe.resolveGrammar)(e,r.errMsgProvider)}Jg.resolveGrammar=sIe;function oIe(r){return r=(0,Gv.defaults)(r,{errMsgProvider:Mj.defaultGrammarValidatorErrorProvider}),(0,nIe.validateGrammar)(r.rules,r.maxLookahead,r.tokenTypes,r.errMsgProvider,r.grammarName)}Jg.validateGrammar=oIe});var Wg=w(mn=>{"use strict";var wd=mn&&mn.__extends||function(){var r=function(e,t){return r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(i,n){i.__proto__=n}||function(i,n){for(var s in n)Object.prototype.hasOwnProperty.call(n,s)&&(i[s]=n[s])},r(e,t)};return function(e,t){if(typeof t!="function"&&t!==null)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");r(e,t);function i(){this.constructor=e}e.prototype=t===null?Object.create(t):(i.prototype=t.prototype,new i)}}();Object.defineProperty(mn,"__esModule",{value:!0});mn.EarlyExitException=mn.NotAllInputParsedException=mn.NoViableAltException=mn.MismatchedTokenException=mn.isRecognitionException=void 0;var aIe=Gt(),Uj="MismatchedTokenException",Hj="NoViableAltException",Gj="EarlyExitException",Yj="NotAllInputParsedException",jj=[Uj,Hj,Gj,Yj];Object.freeze(jj);function AIe(r){return(0,aIe.contains)(jj,r.name)}mn.isRecognitionException=AIe;var ry=function(r){wd(e,r);function e(t,i){var n=this.constructor,s=r.call(this,t)||this;return s.token=i,s.resyncedTokens=[],Object.setPrototypeOf(s,n.prototype),Error.captureStackTrace&&Error.captureStackTrace(s,s.constructor),s}return e}(Error),lIe=function(r){wd(e,r);function e(t,i,n){var s=r.call(this,t,i)||this;return s.previousToken=n,s.name=Uj,s}return e}(ry);mn.MismatchedTokenException=lIe;var cIe=function(r){wd(e,r);function e(t,i,n){var s=r.call(this,t,i)||this;return s.previousToken=n,s.name=Hj,s}return e}(ry);mn.NoViableAltException=cIe;var uIe=function(r){wd(e,r);function e(t,i){var n=r.call(this,t,i)||this;return n.name=Yj,n}return e}(ry);mn.NotAllInputParsedException=uIe;var gIe=function(r){wd(e,r);function e(t,i,n){var s=r.call(this,t,i)||this;return s.previousToken=n,s.name=Gj,s}return e}(ry);mn.EarlyExitException=gIe});var jv=w(Mi=>{"use strict";Object.defineProperty(Mi,"__esModule",{value:!0});Mi.attemptInRepetitionRecovery=Mi.Recoverable=Mi.InRuleRecoveryException=Mi.IN_RULE_RECOVERY_EXCEPTION=Mi.EOF_FOLLOW_KEY=void 0;var iy=SA(),ls=Gt(),fIe=Wg(),hIe=kv(),pIe=Hn();Mi.EOF_FOLLOW_KEY={};Mi.IN_RULE_RECOVERY_EXCEPTION="InRuleRecoveryException";function Yv(r){this.name=Mi.IN_RULE_RECOVERY_EXCEPTION,this.message=r}Mi.InRuleRecoveryException=Yv;Yv.prototype=Error.prototype;var dIe=function(){function r(){}return r.prototype.initRecoverable=function(e){this.firstAfterRepMap={},this.resyncFollows={},this.recoveryEnabled=(0,ls.has)(e,"recoveryEnabled")?e.recoveryEnabled:pIe.DEFAULT_PARSER_CONFIG.recoveryEnabled,this.recoveryEnabled&&(this.attemptInRepetitionRecovery=qj)},r.prototype.getTokenToInsert=function(e){var t=(0,iy.createTokenInstance)(e,"",NaN,NaN,NaN,NaN,NaN,NaN);return t.isInsertedInRecovery=!0,t},r.prototype.canTokenTypeBeInsertedInRecovery=function(e){return!0},r.prototype.tryInRepetitionRecovery=function(e,t,i,n){for(var s=this,o=this.findReSyncTokenType(),a=this.exportLexerState(),l=[],c=!1,u=this.LA(1),g=this.LA(1),f=function(){var h=s.LA(0),p=s.errorMessageProvider.buildMismatchTokenMessage({expected:n,actual:u,previous:h,ruleName:s.getCurrRuleFullName()}),C=new fIe.MismatchedTokenException(p,u,s.LA(0));C.resyncedTokens=(0,ls.dropRight)(l),s.SAVE_ERROR(C)};!c;)if(this.tokenMatcher(g,n)){f();return}else if(i.call(this)){f(),e.apply(this,t);return}else this.tokenMatcher(g,o)?c=!0:(g=this.SKIP_TOKEN(),this.addToResyncTokens(g,l));this.importLexerState(a)},r.prototype.shouldInRepetitionRecoveryBeTried=function(e,t,i){return!(i===!1||e===void 0||t===void 0||this.tokenMatcher(this.LA(1),e)||this.isBackTracking()||this.canPerformInRuleRecovery(e,this.getFollowsForInRuleRecovery(e,t)))},r.prototype.getFollowsForInRuleRecovery=function(e,t){var i=this.getCurrentGrammarPath(e,t),n=this.getNextPossibleTokenTypes(i);return n},r.prototype.tryInRuleRecovery=function(e,t){if(this.canRecoverWithSingleTokenInsertion(e,t)){var i=this.getTokenToInsert(e);return i}if(this.canRecoverWithSingleTokenDeletion(e)){var n=this.SKIP_TOKEN();return this.consumeToken(),n}throw new Yv("sad sad panda")},r.prototype.canPerformInRuleRecovery=function(e,t){return this.canRecoverWithSingleTokenInsertion(e,t)||this.canRecoverWithSingleTokenDeletion(e)},r.prototype.canRecoverWithSingleTokenInsertion=function(e,t){var i=this;if(!this.canTokenTypeBeInsertedInRecovery(e)||(0,ls.isEmpty)(t))return!1;var n=this.LA(1),s=(0,ls.find)(t,function(o){return i.tokenMatcher(n,o)})!==void 0;return s},r.prototype.canRecoverWithSingleTokenDeletion=function(e){var t=this.tokenMatcher(this.LA(2),e);return t},r.prototype.isInCurrentRuleReSyncSet=function(e){var t=this.getCurrFollowKey(),i=this.getFollowSetFromFollowKey(t);return(0,ls.contains)(i,e)},r.prototype.findReSyncTokenType=function(){for(var e=this.flattenFollowSet(),t=this.LA(1),i=2;;){var n=t.tokenType;if((0,ls.contains)(e,n))return n;t=this.LA(i),i++}},r.prototype.getCurrFollowKey=function(){if(this.RULE_STACK.length===1)return Mi.EOF_FOLLOW_KEY;var e=this.getLastExplicitRuleShortName(),t=this.getLastExplicitRuleOccurrenceIndex(),i=this.getPreviousExplicitRuleShortName();return{ruleName:this.shortRuleNameToFullName(e),idxInCallingRule:t,inRule:this.shortRuleNameToFullName(i)}},r.prototype.buildFullFollowKeyStack=function(){var e=this,t=this.RULE_STACK,i=this.RULE_OCCURRENCE_STACK;return(0,ls.map)(t,function(n,s){return s===0?Mi.EOF_FOLLOW_KEY:{ruleName:e.shortRuleNameToFullName(n),idxInCallingRule:i[s],inRule:e.shortRuleNameToFullName(t[s-1])}})},r.prototype.flattenFollowSet=function(){var e=this,t=(0,ls.map)(this.buildFullFollowKeyStack(),function(i){return e.getFollowSetFromFollowKey(i)});return(0,ls.flatten)(t)},r.prototype.getFollowSetFromFollowKey=function(e){if(e===Mi.EOF_FOLLOW_KEY)return[iy.EOF];var t=e.ruleName+e.idxInCallingRule+hIe.IN+e.inRule;return this.resyncFollows[t]},r.prototype.addToResyncTokens=function(e,t){return this.tokenMatcher(e,iy.EOF)||t.push(e),t},r.prototype.reSyncTo=function(e){for(var t=[],i=this.LA(1);this.tokenMatcher(i,e)===!1;)i=this.SKIP_TOKEN(),this.addToResyncTokens(i,t);return(0,ls.dropRight)(t)},r.prototype.attemptInRepetitionRecovery=function(e,t,i,n,s,o,a){},r.prototype.getCurrentGrammarPath=function(e,t){var i=this.getHumanReadableRuleStack(),n=(0,ls.cloneArr)(this.RULE_OCCURRENCE_STACK),s={ruleStack:i,occurrenceStack:n,lastTok:e,lastTokOccurrence:t};return s},r.prototype.getHumanReadableRuleStack=function(){var e=this;return(0,ls.map)(this.RULE_STACK,function(t){return e.shortRuleNameToFullName(t)})},r}();Mi.Recoverable=dIe;function qj(r,e,t,i,n,s,o){var a=this.getKeyForAutomaticLookahead(i,n),l=this.firstAfterRepMap[a];if(l===void 0){var c=this.getCurrRuleFullName(),u=this.getGAstProductions()[c],g=new s(u,n);l=g.startWalking(),this.firstAfterRepMap[a]=l}var f=l.token,h=l.occurrence,p=l.isEndOfRule;this.RULE_STACK.length===1&&p&&f===void 0&&(f=iy.EOF,h=1),this.shouldInRepetitionRecoveryBeTried(f,h,o)&&this.tryInRepetitionRecovery(r,e,t,f)}Mi.attemptInRepetitionRecovery=qj});var ny=w(qt=>{"use strict";Object.defineProperty(qt,"__esModule",{value:!0});qt.getKeyForAutomaticLookahead=qt.AT_LEAST_ONE_SEP_IDX=qt.MANY_SEP_IDX=qt.AT_LEAST_ONE_IDX=qt.MANY_IDX=qt.OPTION_IDX=qt.OR_IDX=qt.BITS_FOR_ALT_IDX=qt.BITS_FOR_RULE_IDX=qt.BITS_FOR_OCCURRENCE_IDX=qt.BITS_FOR_METHOD_TYPE=void 0;qt.BITS_FOR_METHOD_TYPE=4;qt.BITS_FOR_OCCURRENCE_IDX=8;qt.BITS_FOR_RULE_IDX=12;qt.BITS_FOR_ALT_IDX=8;qt.OR_IDX=1<{"use strict";Object.defineProperty(sy,"__esModule",{value:!0});sy.LooksAhead=void 0;var Qa=Id(),Zs=Gt(),Jj=Hn(),ba=ny(),oc=dd(),mIe=function(){function r(){}return r.prototype.initLooksAhead=function(e){this.dynamicTokensEnabled=(0,Zs.has)(e,"dynamicTokensEnabled")?e.dynamicTokensEnabled:Jj.DEFAULT_PARSER_CONFIG.dynamicTokensEnabled,this.maxLookahead=(0,Zs.has)(e,"maxLookahead")?e.maxLookahead:Jj.DEFAULT_PARSER_CONFIG.maxLookahead,this.lookAheadFuncsCache=(0,Zs.isES2015MapSupported)()?new Map:[],(0,Zs.isES2015MapSupported)()?(this.getLaFuncFromCache=this.getLaFuncFromMap,this.setLaFuncCache=this.setLaFuncCacheUsingMap):(this.getLaFuncFromCache=this.getLaFuncFromObj,this.setLaFuncCache=this.setLaFuncUsingObj)},r.prototype.preComputeLookaheadFunctions=function(e){var t=this;(0,Zs.forEach)(e,function(i){t.TRACE_INIT(i.name+" Rule Lookahead",function(){var n=(0,oc.collectMethods)(i),s=n.alternation,o=n.repetition,a=n.option,l=n.repetitionMandatory,c=n.repetitionMandatoryWithSeparator,u=n.repetitionWithSeparator;(0,Zs.forEach)(s,function(g){var f=g.idx===0?"":g.idx;t.TRACE_INIT(""+(0,oc.getProductionDslName)(g)+f,function(){var h=(0,Qa.buildLookaheadFuncForOr)(g.idx,i,g.maxLookahead||t.maxLookahead,g.hasPredicates,t.dynamicTokensEnabled,t.lookAheadBuilderForAlternatives),p=(0,ba.getKeyForAutomaticLookahead)(t.fullRuleNameToShort[i.name],ba.OR_IDX,g.idx);t.setLaFuncCache(p,h)})}),(0,Zs.forEach)(o,function(g){t.computeLookaheadFunc(i,g.idx,ba.MANY_IDX,Qa.PROD_TYPE.REPETITION,g.maxLookahead,(0,oc.getProductionDslName)(g))}),(0,Zs.forEach)(a,function(g){t.computeLookaheadFunc(i,g.idx,ba.OPTION_IDX,Qa.PROD_TYPE.OPTION,g.maxLookahead,(0,oc.getProductionDslName)(g))}),(0,Zs.forEach)(l,function(g){t.computeLookaheadFunc(i,g.idx,ba.AT_LEAST_ONE_IDX,Qa.PROD_TYPE.REPETITION_MANDATORY,g.maxLookahead,(0,oc.getProductionDslName)(g))}),(0,Zs.forEach)(c,function(g){t.computeLookaheadFunc(i,g.idx,ba.AT_LEAST_ONE_SEP_IDX,Qa.PROD_TYPE.REPETITION_MANDATORY_WITH_SEPARATOR,g.maxLookahead,(0,oc.getProductionDslName)(g))}),(0,Zs.forEach)(u,function(g){t.computeLookaheadFunc(i,g.idx,ba.MANY_SEP_IDX,Qa.PROD_TYPE.REPETITION_WITH_SEPARATOR,g.maxLookahead,(0,oc.getProductionDslName)(g))})})})},r.prototype.computeLookaheadFunc=function(e,t,i,n,s,o){var a=this;this.TRACE_INIT(""+o+(t===0?"":t),function(){var l=(0,Qa.buildLookaheadFuncForOptionalProd)(t,e,s||a.maxLookahead,a.dynamicTokensEnabled,n,a.lookAheadBuilderForOptional),c=(0,ba.getKeyForAutomaticLookahead)(a.fullRuleNameToShort[e.name],i,t);a.setLaFuncCache(c,l)})},r.prototype.lookAheadBuilderForOptional=function(e,t,i){return(0,Qa.buildSingleAlternativeLookaheadFunction)(e,t,i)},r.prototype.lookAheadBuilderForAlternatives=function(e,t,i,n){return(0,Qa.buildAlternativesLookAheadFunc)(e,t,i,n)},r.prototype.getKeyForAutomaticLookahead=function(e,t){var i=this.getLastExplicitRuleShortName();return(0,ba.getKeyForAutomaticLookahead)(i,e,t)},r.prototype.getLaFuncFromCache=function(e){},r.prototype.getLaFuncFromMap=function(e){return this.lookAheadFuncsCache.get(e)},r.prototype.getLaFuncFromObj=function(e){return this.lookAheadFuncsCache[e]},r.prototype.setLaFuncCache=function(e,t){},r.prototype.setLaFuncCacheUsingMap=function(e,t){this.lookAheadFuncsCache.set(e,t)},r.prototype.setLaFuncUsingObj=function(e,t){this.lookAheadFuncsCache[e]=t},r}();sy.LooksAhead=mIe});var zj=w(ko=>{"use strict";Object.defineProperty(ko,"__esModule",{value:!0});ko.addNoneTerminalToCst=ko.addTerminalToCst=ko.setNodeLocationFull=ko.setNodeLocationOnlyOffset=void 0;function EIe(r,e){isNaN(r.startOffset)===!0?(r.startOffset=e.startOffset,r.endOffset=e.endOffset):r.endOffset{"use strict";Object.defineProperty(PA,"__esModule",{value:!0});PA.defineNameProp=PA.functionName=PA.classNameFromInstance=void 0;var BIe=Gt();function QIe(r){return Xj(r.constructor)}PA.classNameFromInstance=QIe;var Vj="name";function Xj(r){var e=r.name;return e||"anonymous"}PA.functionName=Xj;function bIe(r,e){var t=Object.getOwnPropertyDescriptor(r,Vj);return(0,BIe.isUndefined)(t)||t.configurable?(Object.defineProperty(r,Vj,{enumerable:!1,configurable:!0,writable:!1,value:e}),!0):!1}PA.defineNameProp=bIe});var tq=w(bi=>{"use strict";Object.defineProperty(bi,"__esModule",{value:!0});bi.validateRedundantMethods=bi.validateMissingCstMethods=bi.validateVisitor=bi.CstVisitorDefinitionError=bi.createBaseVisitorConstructorWithDefaults=bi.createBaseSemanticVisitorConstructor=bi.defaultVisit=void 0;var cs=Gt(),Bd=qv();function _j(r,e){for(var t=(0,cs.keys)(r),i=t.length,n=0;n: + `+(""+s.join(` + +`).replace(/\n/g,` + `)))}}};return t.prototype=i,t.prototype.constructor=t,t._RULE_NAMES=e,t}bi.createBaseSemanticVisitorConstructor=SIe;function vIe(r,e,t){var i=function(){};(0,Bd.defineNameProp)(i,r+"BaseSemanticsWithDefaults");var n=Object.create(t.prototype);return(0,cs.forEach)(e,function(s){n[s]=_j}),i.prototype=n,i.prototype.constructor=i,i}bi.createBaseVisitorConstructorWithDefaults=vIe;var Jv;(function(r){r[r.REDUNDANT_METHOD=0]="REDUNDANT_METHOD",r[r.MISSING_METHOD=1]="MISSING_METHOD"})(Jv=bi.CstVisitorDefinitionError||(bi.CstVisitorDefinitionError={}));function Zj(r,e){var t=$j(r,e),i=eq(r,e);return t.concat(i)}bi.validateVisitor=Zj;function $j(r,e){var t=(0,cs.map)(e,function(i){if(!(0,cs.isFunction)(r[i]))return{msg:"Missing visitor method: <"+i+"> on "+(0,Bd.functionName)(r.constructor)+" CST Visitor.",type:Jv.MISSING_METHOD,methodName:i}});return(0,cs.compact)(t)}bi.validateMissingCstMethods=$j;var xIe=["constructor","visit","validateVisitor"];function eq(r,e){var t=[];for(var i in r)(0,cs.isFunction)(r[i])&&!(0,cs.contains)(xIe,i)&&!(0,cs.contains)(e,i)&&t.push({msg:"Redundant visitor method: <"+i+"> on "+(0,Bd.functionName)(r.constructor)+` CST Visitor +There is no Grammar Rule corresponding to this method's name. +`,type:Jv.REDUNDANT_METHOD,methodName:i});return t}bi.validateRedundantMethods=eq});var iq=w(oy=>{"use strict";Object.defineProperty(oy,"__esModule",{value:!0});oy.TreeBuilder=void 0;var zg=zj(),Zr=Gt(),rq=tq(),PIe=Hn(),DIe=function(){function r(){}return r.prototype.initTreeBuilder=function(e){if(this.CST_STACK=[],this.outputCst=e.outputCst,this.nodeLocationTracking=(0,Zr.has)(e,"nodeLocationTracking")?e.nodeLocationTracking:PIe.DEFAULT_PARSER_CONFIG.nodeLocationTracking,!this.outputCst)this.cstInvocationStateUpdate=Zr.NOOP,this.cstFinallyStateUpdate=Zr.NOOP,this.cstPostTerminal=Zr.NOOP,this.cstPostNonTerminal=Zr.NOOP,this.cstPostRule=Zr.NOOP;else if(/full/i.test(this.nodeLocationTracking))this.recoveryEnabled?(this.setNodeLocationFromToken=zg.setNodeLocationFull,this.setNodeLocationFromNode=zg.setNodeLocationFull,this.cstPostRule=Zr.NOOP,this.setInitialNodeLocation=this.setInitialNodeLocationFullRecovery):(this.setNodeLocationFromToken=Zr.NOOP,this.setNodeLocationFromNode=Zr.NOOP,this.cstPostRule=this.cstPostRuleFull,this.setInitialNodeLocation=this.setInitialNodeLocationFullRegular);else if(/onlyOffset/i.test(this.nodeLocationTracking))this.recoveryEnabled?(this.setNodeLocationFromToken=zg.setNodeLocationOnlyOffset,this.setNodeLocationFromNode=zg.setNodeLocationOnlyOffset,this.cstPostRule=Zr.NOOP,this.setInitialNodeLocation=this.setInitialNodeLocationOnlyOffsetRecovery):(this.setNodeLocationFromToken=Zr.NOOP,this.setNodeLocationFromNode=Zr.NOOP,this.cstPostRule=this.cstPostRuleOnlyOffset,this.setInitialNodeLocation=this.setInitialNodeLocationOnlyOffsetRegular);else if(/none/i.test(this.nodeLocationTracking))this.setNodeLocationFromToken=Zr.NOOP,this.setNodeLocationFromNode=Zr.NOOP,this.cstPostRule=Zr.NOOP,this.setInitialNodeLocation=Zr.NOOP;else throw Error('Invalid config option: "'+e.nodeLocationTracking+'"')},r.prototype.setInitialNodeLocationOnlyOffsetRecovery=function(e){e.location={startOffset:NaN,endOffset:NaN}},r.prototype.setInitialNodeLocationOnlyOffsetRegular=function(e){e.location={startOffset:this.LA(1).startOffset,endOffset:NaN}},r.prototype.setInitialNodeLocationFullRecovery=function(e){e.location={startOffset:NaN,startLine:NaN,startColumn:NaN,endOffset:NaN,endLine:NaN,endColumn:NaN}},r.prototype.setInitialNodeLocationFullRegular=function(e){var t=this.LA(1);e.location={startOffset:t.startOffset,startLine:t.startLine,startColumn:t.startColumn,endOffset:NaN,endLine:NaN,endColumn:NaN}},r.prototype.cstInvocationStateUpdate=function(e,t){var i={name:e,children:{}};this.setInitialNodeLocation(i),this.CST_STACK.push(i)},r.prototype.cstFinallyStateUpdate=function(){this.CST_STACK.pop()},r.prototype.cstPostRuleFull=function(e){var t=this.LA(0),i=e.location;i.startOffset<=t.startOffset?(i.endOffset=t.endOffset,i.endLine=t.endLine,i.endColumn=t.endColumn):(i.startOffset=NaN,i.startLine=NaN,i.startColumn=NaN)},r.prototype.cstPostRuleOnlyOffset=function(e){var t=this.LA(0),i=e.location;i.startOffset<=t.startOffset?i.endOffset=t.endOffset:i.startOffset=NaN},r.prototype.cstPostTerminal=function(e,t){var i=this.CST_STACK[this.CST_STACK.length-1];(0,zg.addTerminalToCst)(i,t,e),this.setNodeLocationFromToken(i.location,t)},r.prototype.cstPostNonTerminal=function(e,t){var i=this.CST_STACK[this.CST_STACK.length-1];(0,zg.addNoneTerminalToCst)(i,t,e),this.setNodeLocationFromNode(i.location,e.location)},r.prototype.getBaseCstVisitorConstructor=function(){if((0,Zr.isUndefined)(this.baseCstVisitorConstructor)){var e=(0,rq.createBaseSemanticVisitorConstructor)(this.className,(0,Zr.keys)(this.gastProductionsCache));return this.baseCstVisitorConstructor=e,e}return this.baseCstVisitorConstructor},r.prototype.getBaseCstVisitorConstructorWithDefaults=function(){if((0,Zr.isUndefined)(this.baseCstVisitorWithDefaultsConstructor)){var e=(0,rq.createBaseVisitorConstructorWithDefaults)(this.className,(0,Zr.keys)(this.gastProductionsCache),this.getBaseCstVisitorConstructor());return this.baseCstVisitorWithDefaultsConstructor=e,e}return this.baseCstVisitorWithDefaultsConstructor},r.prototype.getLastExplicitRuleShortName=function(){var e=this.RULE_STACK;return e[e.length-1]},r.prototype.getPreviousExplicitRuleShortName=function(){var e=this.RULE_STACK;return e[e.length-2]},r.prototype.getLastExplicitRuleOccurrenceIndex=function(){var e=this.RULE_OCCURRENCE_STACK;return e[e.length-1]},r}();oy.TreeBuilder=DIe});var sq=w(ay=>{"use strict";Object.defineProperty(ay,"__esModule",{value:!0});ay.LexerAdapter=void 0;var nq=Hn(),kIe=function(){function r(){}return r.prototype.initLexerAdapter=function(){this.tokVector=[],this.tokVectorLength=0,this.currIdx=-1},Object.defineProperty(r.prototype,"input",{get:function(){return this.tokVector},set:function(e){if(this.selfAnalysisDone!==!0)throw Error("Missing invocation at the end of the Parser's constructor.");this.reset(),this.tokVector=e,this.tokVectorLength=e.length},enumerable:!1,configurable:!0}),r.prototype.SKIP_TOKEN=function(){return this.currIdx<=this.tokVector.length-2?(this.consumeToken(),this.LA(1)):nq.END_OF_FILE},r.prototype.LA=function(e){var t=this.currIdx+e;return t<0||this.tokVectorLength<=t?nq.END_OF_FILE:this.tokVector[t]},r.prototype.consumeToken=function(){this.currIdx++},r.prototype.exportLexerState=function(){return this.currIdx},r.prototype.importLexerState=function(e){this.currIdx=e},r.prototype.resetLexerState=function(){this.currIdx=-1},r.prototype.moveToTerminatedState=function(){this.currIdx=this.tokVector.length-1},r.prototype.getLexerPosition=function(){return this.exportLexerState()},r}();ay.LexerAdapter=kIe});var aq=w(Ay=>{"use strict";Object.defineProperty(Ay,"__esModule",{value:!0});Ay.RecognizerApi=void 0;var oq=Gt(),RIe=Wg(),Wv=Hn(),FIe=Cd(),NIe=Hv(),LIe=dn(),TIe=function(){function r(){}return r.prototype.ACTION=function(e){return e.call(this)},r.prototype.consume=function(e,t,i){return this.consumeInternal(t,e,i)},r.prototype.subrule=function(e,t,i){return this.subruleInternal(t,e,i)},r.prototype.option=function(e,t){return this.optionInternal(t,e)},r.prototype.or=function(e,t){return this.orInternal(t,e)},r.prototype.many=function(e,t){return this.manyInternal(e,t)},r.prototype.atLeastOne=function(e,t){return this.atLeastOneInternal(e,t)},r.prototype.CONSUME=function(e,t){return this.consumeInternal(e,0,t)},r.prototype.CONSUME1=function(e,t){return this.consumeInternal(e,1,t)},r.prototype.CONSUME2=function(e,t){return this.consumeInternal(e,2,t)},r.prototype.CONSUME3=function(e,t){return this.consumeInternal(e,3,t)},r.prototype.CONSUME4=function(e,t){return this.consumeInternal(e,4,t)},r.prototype.CONSUME5=function(e,t){return this.consumeInternal(e,5,t)},r.prototype.CONSUME6=function(e,t){return this.consumeInternal(e,6,t)},r.prototype.CONSUME7=function(e,t){return this.consumeInternal(e,7,t)},r.prototype.CONSUME8=function(e,t){return this.consumeInternal(e,8,t)},r.prototype.CONSUME9=function(e,t){return this.consumeInternal(e,9,t)},r.prototype.SUBRULE=function(e,t){return this.subruleInternal(e,0,t)},r.prototype.SUBRULE1=function(e,t){return this.subruleInternal(e,1,t)},r.prototype.SUBRULE2=function(e,t){return this.subruleInternal(e,2,t)},r.prototype.SUBRULE3=function(e,t){return this.subruleInternal(e,3,t)},r.prototype.SUBRULE4=function(e,t){return this.subruleInternal(e,4,t)},r.prototype.SUBRULE5=function(e,t){return this.subruleInternal(e,5,t)},r.prototype.SUBRULE6=function(e,t){return this.subruleInternal(e,6,t)},r.prototype.SUBRULE7=function(e,t){return this.subruleInternal(e,7,t)},r.prototype.SUBRULE8=function(e,t){return this.subruleInternal(e,8,t)},r.prototype.SUBRULE9=function(e,t){return this.subruleInternal(e,9,t)},r.prototype.OPTION=function(e){return this.optionInternal(e,0)},r.prototype.OPTION1=function(e){return this.optionInternal(e,1)},r.prototype.OPTION2=function(e){return this.optionInternal(e,2)},r.prototype.OPTION3=function(e){return this.optionInternal(e,3)},r.prototype.OPTION4=function(e){return this.optionInternal(e,4)},r.prototype.OPTION5=function(e){return this.optionInternal(e,5)},r.prototype.OPTION6=function(e){return this.optionInternal(e,6)},r.prototype.OPTION7=function(e){return this.optionInternal(e,7)},r.prototype.OPTION8=function(e){return this.optionInternal(e,8)},r.prototype.OPTION9=function(e){return this.optionInternal(e,9)},r.prototype.OR=function(e){return this.orInternal(e,0)},r.prototype.OR1=function(e){return this.orInternal(e,1)},r.prototype.OR2=function(e){return this.orInternal(e,2)},r.prototype.OR3=function(e){return this.orInternal(e,3)},r.prototype.OR4=function(e){return this.orInternal(e,4)},r.prototype.OR5=function(e){return this.orInternal(e,5)},r.prototype.OR6=function(e){return this.orInternal(e,6)},r.prototype.OR7=function(e){return this.orInternal(e,7)},r.prototype.OR8=function(e){return this.orInternal(e,8)},r.prototype.OR9=function(e){return this.orInternal(e,9)},r.prototype.MANY=function(e){this.manyInternal(0,e)},r.prototype.MANY1=function(e){this.manyInternal(1,e)},r.prototype.MANY2=function(e){this.manyInternal(2,e)},r.prototype.MANY3=function(e){this.manyInternal(3,e)},r.prototype.MANY4=function(e){this.manyInternal(4,e)},r.prototype.MANY5=function(e){this.manyInternal(5,e)},r.prototype.MANY6=function(e){this.manyInternal(6,e)},r.prototype.MANY7=function(e){this.manyInternal(7,e)},r.prototype.MANY8=function(e){this.manyInternal(8,e)},r.prototype.MANY9=function(e){this.manyInternal(9,e)},r.prototype.MANY_SEP=function(e){this.manySepFirstInternal(0,e)},r.prototype.MANY_SEP1=function(e){this.manySepFirstInternal(1,e)},r.prototype.MANY_SEP2=function(e){this.manySepFirstInternal(2,e)},r.prototype.MANY_SEP3=function(e){this.manySepFirstInternal(3,e)},r.prototype.MANY_SEP4=function(e){this.manySepFirstInternal(4,e)},r.prototype.MANY_SEP5=function(e){this.manySepFirstInternal(5,e)},r.prototype.MANY_SEP6=function(e){this.manySepFirstInternal(6,e)},r.prototype.MANY_SEP7=function(e){this.manySepFirstInternal(7,e)},r.prototype.MANY_SEP8=function(e){this.manySepFirstInternal(8,e)},r.prototype.MANY_SEP9=function(e){this.manySepFirstInternal(9,e)},r.prototype.AT_LEAST_ONE=function(e){this.atLeastOneInternal(0,e)},r.prototype.AT_LEAST_ONE1=function(e){return this.atLeastOneInternal(1,e)},r.prototype.AT_LEAST_ONE2=function(e){this.atLeastOneInternal(2,e)},r.prototype.AT_LEAST_ONE3=function(e){this.atLeastOneInternal(3,e)},r.prototype.AT_LEAST_ONE4=function(e){this.atLeastOneInternal(4,e)},r.prototype.AT_LEAST_ONE5=function(e){this.atLeastOneInternal(5,e)},r.prototype.AT_LEAST_ONE6=function(e){this.atLeastOneInternal(6,e)},r.prototype.AT_LEAST_ONE7=function(e){this.atLeastOneInternal(7,e)},r.prototype.AT_LEAST_ONE8=function(e){this.atLeastOneInternal(8,e)},r.prototype.AT_LEAST_ONE9=function(e){this.atLeastOneInternal(9,e)},r.prototype.AT_LEAST_ONE_SEP=function(e){this.atLeastOneSepFirstInternal(0,e)},r.prototype.AT_LEAST_ONE_SEP1=function(e){this.atLeastOneSepFirstInternal(1,e)},r.prototype.AT_LEAST_ONE_SEP2=function(e){this.atLeastOneSepFirstInternal(2,e)},r.prototype.AT_LEAST_ONE_SEP3=function(e){this.atLeastOneSepFirstInternal(3,e)},r.prototype.AT_LEAST_ONE_SEP4=function(e){this.atLeastOneSepFirstInternal(4,e)},r.prototype.AT_LEAST_ONE_SEP5=function(e){this.atLeastOneSepFirstInternal(5,e)},r.prototype.AT_LEAST_ONE_SEP6=function(e){this.atLeastOneSepFirstInternal(6,e)},r.prototype.AT_LEAST_ONE_SEP7=function(e){this.atLeastOneSepFirstInternal(7,e)},r.prototype.AT_LEAST_ONE_SEP8=function(e){this.atLeastOneSepFirstInternal(8,e)},r.prototype.AT_LEAST_ONE_SEP9=function(e){this.atLeastOneSepFirstInternal(9,e)},r.prototype.RULE=function(e,t,i){if(i===void 0&&(i=Wv.DEFAULT_RULE_CONFIG),(0,oq.contains)(this.definedRulesNames,e)){var n=FIe.defaultGrammarValidatorErrorProvider.buildDuplicateRuleNameError({topLevelRule:e,grammarName:this.className}),s={message:n,type:Wv.ParserDefinitionErrorType.DUPLICATE_RULE_NAME,ruleName:e};this.definitionErrors.push(s)}this.definedRulesNames.push(e);var o=this.defineRule(e,t,i);return this[e]=o,o},r.prototype.OVERRIDE_RULE=function(e,t,i){i===void 0&&(i=Wv.DEFAULT_RULE_CONFIG);var n=[];n=n.concat((0,NIe.validateRuleIsOverridden)(e,this.definedRulesNames,this.className)),this.definitionErrors=this.definitionErrors.concat(n);var s=this.defineRule(e,t,i);return this[e]=s,s},r.prototype.BACKTRACK=function(e,t){return function(){this.isBackTrackingStack.push(1);var i=this.saveRecogState();try{return e.apply(this,t),!0}catch(n){if((0,RIe.isRecognitionException)(n))return!1;throw n}finally{this.reloadRecogState(i),this.isBackTrackingStack.pop()}}},r.prototype.getGAstProductions=function(){return this.gastProductionsCache},r.prototype.getSerializedGastProductions=function(){return(0,LIe.serializeGrammar)((0,oq.values)(this.gastProductionsCache))},r}();Ay.RecognizerApi=TIe});var uq=w(cy=>{"use strict";Object.defineProperty(cy,"__esModule",{value:!0});cy.RecognizerEngine=void 0;var Pr=Gt(),Gn=ny(),ly=Wg(),Aq=Id(),Vg=Ed(),lq=Hn(),OIe=jv(),cq=SA(),Qd=Gg(),MIe=qv(),KIe=function(){function r(){}return r.prototype.initRecognizerEngine=function(e,t){if(this.className=(0,MIe.classNameFromInstance)(this),this.shortRuleNameToFull={},this.fullRuleNameToShort={},this.ruleShortNameIdx=256,this.tokenMatcher=Qd.tokenStructuredMatcherNoCategories,this.definedRulesNames=[],this.tokensMap={},this.isBackTrackingStack=[],this.RULE_STACK=[],this.RULE_OCCURRENCE_STACK=[],this.gastProductionsCache={},(0,Pr.has)(t,"serializedGrammar"))throw Error(`The Parser's configuration can no longer contain a property. + See: https://chevrotain.io/docs/changes/BREAKING_CHANGES.html#_6-0-0 + For Further details.`);if((0,Pr.isArray)(e)){if((0,Pr.isEmpty)(e))throw Error(`A Token Vocabulary cannot be empty. + Note that the first argument for the parser constructor + is no longer a Token vector (since v4.0).`);if(typeof e[0].startOffset=="number")throw Error(`The Parser constructor no longer accepts a token vector as the first argument. + See: https://chevrotain.io/docs/changes/BREAKING_CHANGES.html#_4-0-0 + For Further details.`)}if((0,Pr.isArray)(e))this.tokensMap=(0,Pr.reduce)(e,function(o,a){return o[a.name]=a,o},{});else if((0,Pr.has)(e,"modes")&&(0,Pr.every)((0,Pr.flatten)((0,Pr.values)(e.modes)),Qd.isTokenType)){var i=(0,Pr.flatten)((0,Pr.values)(e.modes)),n=(0,Pr.uniq)(i);this.tokensMap=(0,Pr.reduce)(n,function(o,a){return o[a.name]=a,o},{})}else if((0,Pr.isObject)(e))this.tokensMap=(0,Pr.cloneObj)(e);else throw new Error(" argument must be An Array of Token constructors, A dictionary of Token constructors or an IMultiModeLexerDefinition");this.tokensMap.EOF=cq.EOF;var s=(0,Pr.every)((0,Pr.values)(e),function(o){return(0,Pr.isEmpty)(o.categoryMatches)});this.tokenMatcher=s?Qd.tokenStructuredMatcherNoCategories:Qd.tokenStructuredMatcher,(0,Qd.augmentTokenTypes)((0,Pr.values)(this.tokensMap))},r.prototype.defineRule=function(e,t,i){if(this.selfAnalysisDone)throw Error("Grammar rule <"+e+`> may not be defined after the 'performSelfAnalysis' method has been called' +Make sure that all grammar rule definitions are done before 'performSelfAnalysis' is called.`);var n=(0,Pr.has)(i,"resyncEnabled")?i.resyncEnabled:lq.DEFAULT_RULE_CONFIG.resyncEnabled,s=(0,Pr.has)(i,"recoveryValueFunc")?i.recoveryValueFunc:lq.DEFAULT_RULE_CONFIG.recoveryValueFunc,o=this.ruleShortNameIdx<t},r.prototype.orInternal=function(e,t){var i=this.getKeyForAutomaticLookahead(Gn.OR_IDX,t),n=(0,Pr.isArray)(e)?e:e.DEF,s=this.getLaFuncFromCache(i),o=s.call(this,n);if(o!==void 0){var a=n[o];return a.ALT.call(this)}this.raiseNoAltException(t,e.ERR_MSG)},r.prototype.ruleFinallyStateUpdate=function(){if(this.RULE_STACK.pop(),this.RULE_OCCURRENCE_STACK.pop(),this.cstFinallyStateUpdate(),this.RULE_STACK.length===0&&this.isAtEndOfInput()===!1){var e=this.LA(1),t=this.errorMessageProvider.buildNotAllInputParsedMessage({firstRedundant:e,ruleName:this.getCurrRuleFullName()});this.SAVE_ERROR(new ly.NotAllInputParsedException(t,e))}},r.prototype.subruleInternal=function(e,t,i){var n;try{var s=i!==void 0?i.ARGS:void 0;return n=e.call(this,t,s),this.cstPostNonTerminal(n,i!==void 0&&i.LABEL!==void 0?i.LABEL:e.ruleName),n}catch(o){this.subruleInternalError(o,i,e.ruleName)}},r.prototype.subruleInternalError=function(e,t,i){throw(0,ly.isRecognitionException)(e)&&e.partialCstResult!==void 0&&(this.cstPostNonTerminal(e.partialCstResult,t!==void 0&&t.LABEL!==void 0?t.LABEL:i),delete e.partialCstResult),e},r.prototype.consumeInternal=function(e,t,i){var n;try{var s=this.LA(1);this.tokenMatcher(s,e)===!0?(this.consumeToken(),n=s):this.consumeInternalError(e,s,i)}catch(o){n=this.consumeInternalRecovery(e,t,o)}return this.cstPostTerminal(i!==void 0&&i.LABEL!==void 0?i.LABEL:e.name,n),n},r.prototype.consumeInternalError=function(e,t,i){var n,s=this.LA(0);throw i!==void 0&&i.ERR_MSG?n=i.ERR_MSG:n=this.errorMessageProvider.buildMismatchTokenMessage({expected:e,actual:t,previous:s,ruleName:this.getCurrRuleFullName()}),this.SAVE_ERROR(new ly.MismatchedTokenException(n,t,s))},r.prototype.consumeInternalRecovery=function(e,t,i){if(this.recoveryEnabled&&i.name==="MismatchedTokenException"&&!this.isBackTracking()){var n=this.getFollowsForInRuleRecovery(e,t);try{return this.tryInRuleRecovery(e,n)}catch(s){throw s.name===OIe.IN_RULE_RECOVERY_EXCEPTION?i:s}}else throw i},r.prototype.saveRecogState=function(){var e=this.errors,t=(0,Pr.cloneArr)(this.RULE_STACK);return{errors:e,lexerState:this.exportLexerState(),RULE_STACK:t,CST_STACK:this.CST_STACK}},r.prototype.reloadRecogState=function(e){this.errors=e.errors,this.importLexerState(e.lexerState),this.RULE_STACK=e.RULE_STACK},r.prototype.ruleInvocationStateUpdate=function(e,t,i){this.RULE_OCCURRENCE_STACK.push(i),this.RULE_STACK.push(e),this.cstInvocationStateUpdate(t,e)},r.prototype.isBackTracking=function(){return this.isBackTrackingStack.length!==0},r.prototype.getCurrRuleFullName=function(){var e=this.getLastExplicitRuleShortName();return this.shortRuleNameToFull[e]},r.prototype.shortRuleNameToFullName=function(e){return this.shortRuleNameToFull[e]},r.prototype.isAtEndOfInput=function(){return this.tokenMatcher(this.LA(1),cq.EOF)},r.prototype.reset=function(){this.resetLexerState(),this.isBackTrackingStack=[],this.errors=[],this.RULE_STACK=[],this.CST_STACK=[],this.RULE_OCCURRENCE_STACK=[]},r}();cy.RecognizerEngine=KIe});var fq=w(uy=>{"use strict";Object.defineProperty(uy,"__esModule",{value:!0});uy.ErrorHandler=void 0;var zv=Wg(),Vv=Gt(),gq=Id(),UIe=Hn(),HIe=function(){function r(){}return r.prototype.initErrorHandler=function(e){this._errors=[],this.errorMessageProvider=(0,Vv.has)(e,"errorMessageProvider")?e.errorMessageProvider:UIe.DEFAULT_PARSER_CONFIG.errorMessageProvider},r.prototype.SAVE_ERROR=function(e){if((0,zv.isRecognitionException)(e))return e.context={ruleStack:this.getHumanReadableRuleStack(),ruleOccurrenceStack:(0,Vv.cloneArr)(this.RULE_OCCURRENCE_STACK)},this._errors.push(e),e;throw Error("Trying to save an Error which is not a RecognitionException")},Object.defineProperty(r.prototype,"errors",{get:function(){return(0,Vv.cloneArr)(this._errors)},set:function(e){this._errors=e},enumerable:!1,configurable:!0}),r.prototype.raiseEarlyExitException=function(e,t,i){for(var n=this.getCurrRuleFullName(),s=this.getGAstProductions()[n],o=(0,gq.getLookaheadPathsForOptionalProd)(e,s,t,this.maxLookahead),a=o[0],l=[],c=1;c<=this.maxLookahead;c++)l.push(this.LA(c));var u=this.errorMessageProvider.buildEarlyExitMessage({expectedIterationPaths:a,actual:l,previous:this.LA(0),customUserDescription:i,ruleName:n});throw this.SAVE_ERROR(new zv.EarlyExitException(u,this.LA(1),this.LA(0)))},r.prototype.raiseNoAltException=function(e,t){for(var i=this.getCurrRuleFullName(),n=this.getGAstProductions()[i],s=(0,gq.getLookaheadPathsForOr)(e,n,this.maxLookahead),o=[],a=1;a<=this.maxLookahead;a++)o.push(this.LA(a));var l=this.LA(0),c=this.errorMessageProvider.buildNoViableAltMessage({expectedPathsPerAlt:s,actual:o,previous:l,customUserDescription:t,ruleName:this.getCurrRuleFullName()});throw this.SAVE_ERROR(new zv.NoViableAltException(c,this.LA(1),l))},r}();uy.ErrorHandler=HIe});var dq=w(gy=>{"use strict";Object.defineProperty(gy,"__esModule",{value:!0});gy.ContentAssist=void 0;var hq=Ed(),pq=Gt(),GIe=function(){function r(){}return r.prototype.initContentAssist=function(){},r.prototype.computeContentAssist=function(e,t){var i=this.gastProductionsCache[e];if((0,pq.isUndefined)(i))throw Error("Rule ->"+e+"<- does not exist in this grammar.");return(0,hq.nextPossibleTokensAfter)([i],t,this.tokenMatcher,this.maxLookahead)},r.prototype.getNextPossibleTokenTypes=function(e){var t=(0,pq.first)(e.ruleStack),i=this.getGAstProductions(),n=i[t],s=new hq.NextAfterTokenWalker(n,e).startWalking();return s},r}();gy.ContentAssist=GIe});var Qq=w(py=>{"use strict";Object.defineProperty(py,"__esModule",{value:!0});py.GastRecorder=void 0;var En=Gt(),Ro=dn(),YIe=gd(),Iq=Gg(),yq=SA(),jIe=Hn(),qIe=ny(),hy={description:"This Object indicates the Parser is during Recording Phase"};Object.freeze(hy);var Cq=!0,mq=Math.pow(2,qIe.BITS_FOR_OCCURRENCE_IDX)-1,wq=(0,yq.createToken)({name:"RECORDING_PHASE_TOKEN",pattern:YIe.Lexer.NA});(0,Iq.augmentTokenTypes)([wq]);var Bq=(0,yq.createTokenInstance)(wq,`This IToken indicates the Parser is in Recording Phase + See: https://chevrotain.io/docs/guide/internals.html#grammar-recording for details`,-1,-1,-1,-1,-1,-1);Object.freeze(Bq);var JIe={name:`This CSTNode indicates the Parser is in Recording Phase + See: https://chevrotain.io/docs/guide/internals.html#grammar-recording for details`,children:{}},WIe=function(){function r(){}return r.prototype.initGastRecorder=function(e){this.recordingProdStack=[],this.RECORDING_PHASE=!1},r.prototype.enableRecording=function(){var e=this;this.RECORDING_PHASE=!0,this.TRACE_INIT("Enable Recording",function(){for(var t=function(n){var s=n>0?n:"";e["CONSUME"+s]=function(o,a){return this.consumeInternalRecord(o,n,a)},e["SUBRULE"+s]=function(o,a){return this.subruleInternalRecord(o,n,a)},e["OPTION"+s]=function(o){return this.optionInternalRecord(o,n)},e["OR"+s]=function(o){return this.orInternalRecord(o,n)},e["MANY"+s]=function(o){this.manyInternalRecord(n,o)},e["MANY_SEP"+s]=function(o){this.manySepFirstInternalRecord(n,o)},e["AT_LEAST_ONE"+s]=function(o){this.atLeastOneInternalRecord(n,o)},e["AT_LEAST_ONE_SEP"+s]=function(o){this.atLeastOneSepFirstInternalRecord(n,o)}},i=0;i<10;i++)t(i);e.consume=function(n,s,o){return this.consumeInternalRecord(s,n,o)},e.subrule=function(n,s,o){return this.subruleInternalRecord(s,n,o)},e.option=function(n,s){return this.optionInternalRecord(s,n)},e.or=function(n,s){return this.orInternalRecord(s,n)},e.many=function(n,s){this.manyInternalRecord(n,s)},e.atLeastOne=function(n,s){this.atLeastOneInternalRecord(n,s)},e.ACTION=e.ACTION_RECORD,e.BACKTRACK=e.BACKTRACK_RECORD,e.LA=e.LA_RECORD})},r.prototype.disableRecording=function(){var e=this;this.RECORDING_PHASE=!1,this.TRACE_INIT("Deleting Recording methods",function(){for(var t=0;t<10;t++){var i=t>0?t:"";delete e["CONSUME"+i],delete e["SUBRULE"+i],delete e["OPTION"+i],delete e["OR"+i],delete e["MANY"+i],delete e["MANY_SEP"+i],delete e["AT_LEAST_ONE"+i],delete e["AT_LEAST_ONE_SEP"+i]}delete e.consume,delete e.subrule,delete e.option,delete e.or,delete e.many,delete e.atLeastOne,delete e.ACTION,delete e.BACKTRACK,delete e.LA})},r.prototype.ACTION_RECORD=function(e){},r.prototype.BACKTRACK_RECORD=function(e,t){return function(){return!0}},r.prototype.LA_RECORD=function(e){return jIe.END_OF_FILE},r.prototype.topLevelRuleRecord=function(e,t){try{var i=new Ro.Rule({definition:[],name:e});return i.name=e,this.recordingProdStack.push(i),t.call(this),this.recordingProdStack.pop(),i}catch(n){if(n.KNOWN_RECORDER_ERROR!==!0)try{n.message=n.message+` + This error was thrown during the "grammar recording phase" For more info see: + https://chevrotain.io/docs/guide/internals.html#grammar-recording`}catch{throw n}throw n}},r.prototype.optionInternalRecord=function(e,t){return bd.call(this,Ro.Option,e,t)},r.prototype.atLeastOneInternalRecord=function(e,t){bd.call(this,Ro.RepetitionMandatory,t,e)},r.prototype.atLeastOneSepFirstInternalRecord=function(e,t){bd.call(this,Ro.RepetitionMandatoryWithSeparator,t,e,Cq)},r.prototype.manyInternalRecord=function(e,t){bd.call(this,Ro.Repetition,t,e)},r.prototype.manySepFirstInternalRecord=function(e,t){bd.call(this,Ro.RepetitionWithSeparator,t,e,Cq)},r.prototype.orInternalRecord=function(e,t){return zIe.call(this,e,t)},r.prototype.subruleInternalRecord=function(e,t,i){if(fy(t),!e||(0,En.has)(e,"ruleName")===!1){var n=new Error(" argument is invalid"+(" expecting a Parser method reference but got: <"+JSON.stringify(e)+">")+(` + inside top level rule: <`+this.recordingProdStack[0].name+">"));throw n.KNOWN_RECORDER_ERROR=!0,n}var s=(0,En.peek)(this.recordingProdStack),o=e.ruleName,a=new Ro.NonTerminal({idx:t,nonTerminalName:o,label:i==null?void 0:i.LABEL,referencedRule:void 0});return s.definition.push(a),this.outputCst?JIe:hy},r.prototype.consumeInternalRecord=function(e,t,i){if(fy(t),!(0,Iq.hasShortKeyProperty)(e)){var n=new Error(" argument is invalid"+(" expecting a TokenType reference but got: <"+JSON.stringify(e)+">")+(` + inside top level rule: <`+this.recordingProdStack[0].name+">"));throw n.KNOWN_RECORDER_ERROR=!0,n}var s=(0,En.peek)(this.recordingProdStack),o=new Ro.Terminal({idx:t,terminalType:e,label:i==null?void 0:i.LABEL});return s.definition.push(o),Bq},r}();py.GastRecorder=WIe;function bd(r,e,t,i){i===void 0&&(i=!1),fy(t);var n=(0,En.peek)(this.recordingProdStack),s=(0,En.isFunction)(e)?e:e.DEF,o=new r({definition:[],idx:t});return i&&(o.separator=e.SEP),(0,En.has)(e,"MAX_LOOKAHEAD")&&(o.maxLookahead=e.MAX_LOOKAHEAD),this.recordingProdStack.push(o),s.call(this),n.definition.push(o),this.recordingProdStack.pop(),hy}function zIe(r,e){var t=this;fy(e);var i=(0,En.peek)(this.recordingProdStack),n=(0,En.isArray)(r)===!1,s=n===!1?r:r.DEF,o=new Ro.Alternation({definition:[],idx:e,ignoreAmbiguities:n&&r.IGNORE_AMBIGUITIES===!0});(0,En.has)(r,"MAX_LOOKAHEAD")&&(o.maxLookahead=r.MAX_LOOKAHEAD);var a=(0,En.some)(s,function(l){return(0,En.isFunction)(l.GATE)});return o.hasPredicates=a,i.definition.push(o),(0,En.forEach)(s,function(l){var c=new Ro.Alternative({definition:[]});o.definition.push(c),(0,En.has)(l,"IGNORE_AMBIGUITIES")?c.ignoreAmbiguities=l.IGNORE_AMBIGUITIES:(0,En.has)(l,"GATE")&&(c.ignoreAmbiguities=!0),t.recordingProdStack.push(c),l.ALT.call(t),t.recordingProdStack.pop()}),hy}function Eq(r){return r===0?"":""+r}function fy(r){if(r<0||r>mq){var e=new Error("Invalid DSL Method idx value: <"+r+`> + `+("Idx value must be a none negative value smaller than "+(mq+1)));throw e.KNOWN_RECORDER_ERROR=!0,e}}});var Sq=w(dy=>{"use strict";Object.defineProperty(dy,"__esModule",{value:!0});dy.PerformanceTracer=void 0;var bq=Gt(),VIe=Hn(),XIe=function(){function r(){}return r.prototype.initPerformanceTracer=function(e){if((0,bq.has)(e,"traceInitPerf")){var t=e.traceInitPerf,i=typeof t=="number";this.traceInitMaxIdent=i?t:1/0,this.traceInitPerf=i?t>0:t}else this.traceInitMaxIdent=0,this.traceInitPerf=VIe.DEFAULT_PARSER_CONFIG.traceInitPerf;this.traceInitIndent=-1},r.prototype.TRACE_INIT=function(e,t){if(this.traceInitPerf===!0){this.traceInitIndent++;var i=new Array(this.traceInitIndent+1).join(" ");this.traceInitIndent <"+e+">");var n=(0,bq.timer)(t),s=n.time,o=n.value,a=s>10?console.warn:console.log;return this.traceInitIndent time: "+s+"ms"),this.traceInitIndent--,o}else return t()},r}();dy.PerformanceTracer=XIe});var vq=w(Cy=>{"use strict";Object.defineProperty(Cy,"__esModule",{value:!0});Cy.applyMixins=void 0;function _Ie(r,e){e.forEach(function(t){var i=t.prototype;Object.getOwnPropertyNames(i).forEach(function(n){if(n!=="constructor"){var s=Object.getOwnPropertyDescriptor(i,n);s&&(s.get||s.set)?Object.defineProperty(r.prototype,n,s):r.prototype[n]=t.prototype[n]}})})}Cy.applyMixins=_Ie});var Hn=w(dr=>{"use strict";var Dq=dr&&dr.__extends||function(){var r=function(e,t){return r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(i,n){i.__proto__=n}||function(i,n){for(var s in n)Object.prototype.hasOwnProperty.call(n,s)&&(i[s]=n[s])},r(e,t)};return function(e,t){if(typeof t!="function"&&t!==null)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");r(e,t);function i(){this.constructor=e}e.prototype=t===null?Object.create(t):(i.prototype=t.prototype,new i)}}();Object.defineProperty(dr,"__esModule",{value:!0});dr.EmbeddedActionsParser=dr.CstParser=dr.Parser=dr.EMPTY_ALT=dr.ParserDefinitionErrorType=dr.DEFAULT_RULE_CONFIG=dr.DEFAULT_PARSER_CONFIG=dr.END_OF_FILE=void 0;var Xi=Gt(),ZIe=fj(),xq=SA(),kq=Cd(),Pq=Kj(),$Ie=jv(),eye=Wj(),tye=iq(),rye=sq(),iye=aq(),nye=uq(),sye=fq(),oye=dq(),aye=Qq(),Aye=Sq(),lye=vq();dr.END_OF_FILE=(0,xq.createTokenInstance)(xq.EOF,"",NaN,NaN,NaN,NaN,NaN,NaN);Object.freeze(dr.END_OF_FILE);dr.DEFAULT_PARSER_CONFIG=Object.freeze({recoveryEnabled:!1,maxLookahead:3,dynamicTokensEnabled:!1,outputCst:!0,errorMessageProvider:kq.defaultParserErrorProvider,nodeLocationTracking:"none",traceInitPerf:!1,skipValidations:!1});dr.DEFAULT_RULE_CONFIG=Object.freeze({recoveryValueFunc:function(){},resyncEnabled:!0});var cye;(function(r){r[r.INVALID_RULE_NAME=0]="INVALID_RULE_NAME",r[r.DUPLICATE_RULE_NAME=1]="DUPLICATE_RULE_NAME",r[r.INVALID_RULE_OVERRIDE=2]="INVALID_RULE_OVERRIDE",r[r.DUPLICATE_PRODUCTIONS=3]="DUPLICATE_PRODUCTIONS",r[r.UNRESOLVED_SUBRULE_REF=4]="UNRESOLVED_SUBRULE_REF",r[r.LEFT_RECURSION=5]="LEFT_RECURSION",r[r.NONE_LAST_EMPTY_ALT=6]="NONE_LAST_EMPTY_ALT",r[r.AMBIGUOUS_ALTS=7]="AMBIGUOUS_ALTS",r[r.CONFLICT_TOKENS_RULES_NAMESPACE=8]="CONFLICT_TOKENS_RULES_NAMESPACE",r[r.INVALID_TOKEN_NAME=9]="INVALID_TOKEN_NAME",r[r.NO_NON_EMPTY_LOOKAHEAD=10]="NO_NON_EMPTY_LOOKAHEAD",r[r.AMBIGUOUS_PREFIX_ALTS=11]="AMBIGUOUS_PREFIX_ALTS",r[r.TOO_MANY_ALTS=12]="TOO_MANY_ALTS"})(cye=dr.ParserDefinitionErrorType||(dr.ParserDefinitionErrorType={}));function uye(r){return r===void 0&&(r=void 0),function(){return r}}dr.EMPTY_ALT=uye;var my=function(){function r(e,t){this.definitionErrors=[],this.selfAnalysisDone=!1;var i=this;if(i.initErrorHandler(t),i.initLexerAdapter(),i.initLooksAhead(t),i.initRecognizerEngine(e,t),i.initRecoverable(t),i.initTreeBuilder(t),i.initContentAssist(),i.initGastRecorder(t),i.initPerformanceTracer(t),(0,Xi.has)(t,"ignoredIssues"))throw new Error(`The IParserConfig property has been deprecated. + Please use the flag on the relevant DSL method instead. + See: https://chevrotain.io/docs/guide/resolving_grammar_errors.html#IGNORING_AMBIGUITIES + For further details.`);this.skipValidations=(0,Xi.has)(t,"skipValidations")?t.skipValidations:dr.DEFAULT_PARSER_CONFIG.skipValidations}return r.performSelfAnalysis=function(e){throw Error("The **static** `performSelfAnalysis` method has been deprecated. \nUse the **instance** method with the same name instead.")},r.prototype.performSelfAnalysis=function(){var e=this;this.TRACE_INIT("performSelfAnalysis",function(){var t;e.selfAnalysisDone=!0;var i=e.className;e.TRACE_INIT("toFastProps",function(){(0,Xi.toFastProperties)(e)}),e.TRACE_INIT("Grammar Recording",function(){try{e.enableRecording(),(0,Xi.forEach)(e.definedRulesNames,function(s){var o=e[s],a=o.originalGrammarAction,l=void 0;e.TRACE_INIT(s+" Rule",function(){l=e.topLevelRuleRecord(s,a)}),e.gastProductionsCache[s]=l})}finally{e.disableRecording()}});var n=[];if(e.TRACE_INIT("Grammar Resolving",function(){n=(0,Pq.resolveGrammar)({rules:(0,Xi.values)(e.gastProductionsCache)}),e.definitionErrors=e.definitionErrors.concat(n)}),e.TRACE_INIT("Grammar Validations",function(){if((0,Xi.isEmpty)(n)&&e.skipValidations===!1){var s=(0,Pq.validateGrammar)({rules:(0,Xi.values)(e.gastProductionsCache),maxLookahead:e.maxLookahead,tokenTypes:(0,Xi.values)(e.tokensMap),errMsgProvider:kq.defaultGrammarValidatorErrorProvider,grammarName:i});e.definitionErrors=e.definitionErrors.concat(s)}}),(0,Xi.isEmpty)(e.definitionErrors)&&(e.recoveryEnabled&&e.TRACE_INIT("computeAllProdsFollows",function(){var s=(0,ZIe.computeAllProdsFollows)((0,Xi.values)(e.gastProductionsCache));e.resyncFollows=s}),e.TRACE_INIT("ComputeLookaheadFunctions",function(){e.preComputeLookaheadFunctions((0,Xi.values)(e.gastProductionsCache))})),!r.DEFER_DEFINITION_ERRORS_HANDLING&&!(0,Xi.isEmpty)(e.definitionErrors))throw t=(0,Xi.map)(e.definitionErrors,function(s){return s.message}),new Error(`Parser Definition Errors detected: + `+t.join(` +------------------------------- +`))})},r.DEFER_DEFINITION_ERRORS_HANDLING=!1,r}();dr.Parser=my;(0,lye.applyMixins)(my,[$Ie.Recoverable,eye.LooksAhead,tye.TreeBuilder,rye.LexerAdapter,nye.RecognizerEngine,iye.RecognizerApi,sye.ErrorHandler,oye.ContentAssist,aye.GastRecorder,Aye.PerformanceTracer]);var gye=function(r){Dq(e,r);function e(t,i){i===void 0&&(i=dr.DEFAULT_PARSER_CONFIG);var n=this,s=(0,Xi.cloneObj)(i);return s.outputCst=!0,n=r.call(this,t,s)||this,n}return e}(my);dr.CstParser=gye;var fye=function(r){Dq(e,r);function e(t,i){i===void 0&&(i=dr.DEFAULT_PARSER_CONFIG);var n=this,s=(0,Xi.cloneObj)(i);return s.outputCst=!1,n=r.call(this,t,s)||this,n}return e}(my);dr.EmbeddedActionsParser=fye});var Fq=w(Ey=>{"use strict";Object.defineProperty(Ey,"__esModule",{value:!0});Ey.createSyntaxDiagramsCode=void 0;var Rq=pv();function hye(r,e){var t=e===void 0?{}:e,i=t.resourceBase,n=i===void 0?"https://unpkg.com/chevrotain@"+Rq.VERSION+"/diagrams/":i,s=t.css,o=s===void 0?"https://unpkg.com/chevrotain@"+Rq.VERSION+"/diagrams/diagrams.css":s,a=` + + + + + +`,l=` + +`,c=` + - {{/if}} - - - - - - - - - - - - - - - - - - - {{#if livereload}} - - - {{/if}} - - {{#if google_analytics}} - - - {{/if}} - - {{#if playground_line_numbers}} - - {{/if}} - - {{#if playground_copyable}} - - {{/if}} - - {{#if playground_js}} - - - - - - {{/if}} - - {{#if search_js}} - - - - {{/if}} - - - - - - - {{#each additional_js}} - - {{/each}} - - {{#if is_print}} - {{#if mathjax_support}} - - {{else}} - - {{/if}} - {{/if}} - - - \ No newline at end of file diff --git a/circuits/specs/theme/sidebar.js b/circuits/specs/theme/sidebar.js deleted file mode 100644 index 785fac18dae..00000000000 --- a/circuits/specs/theme/sidebar.js +++ /dev/null @@ -1,66 +0,0 @@ -// Un-active everything when you click it -Array.prototype.forEach.call(document.getElementsByClassName("pagetoc")[0].children, function(el) { - el.addEventHandler("click", function() { - Array.prototype.forEach.call(document.getElementsByClassName("pagetoc")[0].children, function(el) { - el.classList.remove("active"); - }); - el.classList.add("active"); - }); -}); - -var updateFunction = function() { - - var id; - var elements = document.getElementsByClassName("header"); - Array.prototype.forEach.call(elements, function(el) { - if (window.pageYOffset >= el.offsetTop) { - id = el; - } - }); - - Array.prototype.forEach.call(document.getElementsByClassName("pagetoc")[0].children, function(el) { - el.classList.remove("active"); - }); - - Array.prototype.forEach.call(document.getElementsByClassName("pagetoc")[0].children, function(el) { - if (id.href.localeCompare(el.href) == 0) { - el.classList.add("active"); - } - }); -}; - -// Populate sidebar on load -window.addEventListener('load', function() { - var pagetoc = document.getElementsByClassName("pagetoc")[0]; - var elements = document.getElementsByClassName("header"); - Array.prototype.forEach.call(elements, function(el) { - var link = document.createElement("a"); - - // Indent shows hierarchy - var indent = ""; - switch (el.parentElement.tagName) { - case "H2": - indent = "20px"; - break; - case "H3": - indent = "40px"; - break; - case "H4": - indent = "60px"; - break; - default: - break; - } - - link.appendChild(document.createTextNode(el.text)); - link.style.paddingLeft = indent; - link.href = el.href; - pagetoc.appendChild(link); - }); - updateFunction.call(); -}); - - - -// Handle active elements on scroll -window.addEventListener("scroll", updateFunction); \ No newline at end of file From 53dff4f98666abf795121bfe8b285361d1f82626 Mon Sep 17 00:00:00 2001 From: Lasse Herskind <16536249+LHerskind@users.noreply.github.com> Date: Wed, 12 Apr 2023 17:15:19 +0100 Subject: [PATCH 156/166] feat: reusable rollup components (#183) * add rollup subtree height * just use one type of public inputs for base/merge (#168) * fix: re-usable rollup components * fix: hash_multiple -> hash_pair_native --------- Co-authored-by: Rahul Kothari --- .../base/native_base_rollup_circuit.cpp | 139 +++++------------- .../circuits/rollup/components/components.cpp | 128 ++++++++++++++++ .../circuits/rollup/components/components.hpp | 73 +++++++++ .../circuits/rollup/components/init.hpp | 29 ++++ .../merge/native_merge_rollup_circuit.cpp | 124 +--------------- .../merge/native_merge_rollup_circuit.hpp | 16 -- .../src/aztec3/circuits/rollup/root/init.hpp | 2 - .../root/native_root_rollup_circuit.cpp | 88 +++-------- 8 files changed, 296 insertions(+), 303 deletions(-) create mode 100644 circuits/cpp/src/aztec3/circuits/rollup/components/components.cpp create mode 100644 circuits/cpp/src/aztec3/circuits/rollup/components/components.hpp create mode 100644 circuits/cpp/src/aztec3/circuits/rollup/components/init.hpp diff --git a/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp b/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp index 8d249eea937..9fac1b9b2f2 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp @@ -7,6 +7,7 @@ #include "barretenberg/stdlib/merkle_tree/memory_tree.hpp" #include "barretenberg/stdlib/merkle_tree/merkle_tree.hpp" #include "init.hpp" +#include "aztec3/circuits/rollup/components/components.hpp" #include #include @@ -100,54 +101,7 @@ std::vector calculate_contract_leaves(BaseRollupInputs const& baseRollup return contract_leaves; } -template -NT::fr iterate_through_tree_via_sibling_path(NT::fr leaf, - NT::uint32 const& leafIndex, - std::array const& siblingPath) -{ - for (size_t i = 0; i < siblingPath.size(); i++) { - if (leafIndex & (1 << i)) { - leaf = proof_system::plonk::stdlib::merkle_tree::hash_pair_native(siblingPath[i], leaf); - } else { - leaf = proof_system::plonk::stdlib::merkle_tree::hash_pair_native(leaf, siblingPath[i]); - } - } - return leaf; -} - -template -void check_membership(DummyComposer& composer, - NT::fr const& leaf, - NT::uint32 const& leafIndex, - std::array const& siblingPath, - NT::fr const& root) -{ - auto calculatedRoot = iterate_through_tree_via_sibling_path(leaf, leafIndex, siblingPath); - // TODO: update tests to build the correct trees - composer.do_assert(calculatedRoot == root, "Membership check failed"); -} - -template -AppendOnlySnapshot insert_subtree_to_snapshot_tree(std::array const& siblingPath, - NT::uint32 const& nextAvailableLeafIndex, - NT::fr const& subtreeRootToInsert, - uint8_t const& subtreeDepth) -{ - // TODO: Sanity check len of siblingPath > height of subtree - // TODO: Ensure height of subtree is correct (eg 3 for commitments, 1 for contracts) - - // if index of leaf is x, index of its parent is x/2 or x >> 1. We need to find the parent `subtreeDepth` levels up. - auto leafIndexAtDepth = nextAvailableLeafIndex >> subtreeDepth; - auto new_root = iterate_through_tree_via_sibling_path(subtreeRootToInsert, leafIndexAtDepth, siblingPath); - // 2^subtreeDepth is the number of leaves added. 2^x = 1 << x - auto new_next_available_leaf_index = nextAvailableLeafIndex + (uint8_t(1) << subtreeDepth); - - AppendOnlySnapshot newTreeSnapshot = { .root = new_root, - .next_available_leaf_index = new_next_available_leaf_index }; - return newTreeSnapshot; -} - -NT::fr calculate_contract_subtree(std::vector const& contract_leaves) +NT::fr calculate_contract_subtree(std::vector contract_leaves) { MerkleTree contracts_tree = MerkleTree(CONTRACT_SUBTREE_DEPTH); @@ -260,7 +214,7 @@ void perform_historical_private_data_tree_membership_checks(DummyComposer& compo abis::MembershipWitness historic_root_witness = baseRollupInputs.historic_private_data_tree_root_membership_witnesses[i]; - check_membership( + components::check_membership( composer, leaf, historic_root_witness.leaf_index, historic_root_witness.sibling_path, historic_root); } } @@ -275,7 +229,7 @@ void perform_historical_contract_data_tree_membership_checks(DummyComposer& comp abis::MembershipWitness historic_root_witness = baseRollupInputs.historic_contract_tree_root_membership_witnesses[i]; - check_membership( + components::check_membership( composer, leaf, historic_root_witness.leaf_index, historic_root_witness.sibling_path, historic_root); } } @@ -389,11 +343,11 @@ AppendOnlySnapshot check_nullifier_tree_non_membership_and_insert_to_tree(DummyC }; // perform membership check for the low nullifier against the original root - check_membership(composer, - original_low_nullifier.hash(), - witness.leaf_index, - witness.sibling_path, - current_nullifier_tree_root); + components::check_membership(composer, + original_low_nullifier.hash(), + witness.leaf_index, + witness.sibling_path, + current_nullifier_tree_root); // Calculate the new value of the low_nullifier_leaf NullifierLeaf updated_low_nullifier = NullifierLeaf{ .value = low_nullifier_preimage.leaf_value, @@ -401,7 +355,7 @@ AppendOnlySnapshot check_nullifier_tree_non_membership_and_insert_to_tree(DummyC .nextValue = nullifier }; // We need another set of witness values for this - current_nullifier_tree_root = iterate_through_tree_via_sibling_path( + current_nullifier_tree_root = components::iterate_through_tree_via_sibling_path( updated_low_nullifier.hash(), witness.leaf_index, witness.sibling_path); } @@ -428,8 +382,8 @@ AppendOnlySnapshot check_nullifier_tree_non_membership_and_insert_to_tree(DummyC // Calculate the new root // We are inserting a subtree rather than a full tree here auto subtree_index = start_insertion_index >> (NULLIFIER_SUBTREE_DEPTH); - auto new_root = - iterate_through_tree_via_sibling_path(nullifier_subtree_root, subtree_index, nullifier_sibling_path); + auto new_root = components::iterate_through_tree_via_sibling_path( + nullifier_subtree_root, subtree_index, nullifier_sibling_path); // Return the new state of the nullifier tree return { @@ -453,57 +407,36 @@ BaseOrMergeRollupPublicInputs base_rollup_circuit(DummyComposer& composer, BaseR // First we compute the contract tree leaves std::vector contract_leaves = calculate_contract_leaves(baseRollupInputs); - // Perform merkle membership check with the provided sibling path up to the root - // Note - the subtree hasn't been created (i.e. it is empty) so you check that the sibling path corresponds to - // an empty tree - - // check for commitments/private_data - // next_available_leaf_index is at the leaf level. We need at the subtree level (say height 3). So divide by 8. - // (if leaf is at index x, its parent is at index floor >> depth) - auto leafIndexAtSubtreeDepth = - baseRollupInputs.start_private_data_tree_snapshot.next_available_leaf_index >> (PRIVATE_DATA_SUBTREE_DEPTH); - check_membership(composer, - EMPTY_COMMITMENTS_SUBTREE_ROOT, - leafIndexAtSubtreeDepth, - baseRollupInputs.new_commitments_subtree_sibling_path, - baseRollupInputs.start_private_data_tree_snapshot.root); - - // check for contracts - auto leafIndexContractsSubtreeDepth = - baseRollupInputs.start_contract_tree_snapshot.next_available_leaf_index >> CONTRACT_SUBTREE_DEPTH; - check_membership(composer, - EMPTY_CONTRACTS_SUBTREE_ROOT, - leafIndexContractsSubtreeDepth, - baseRollupInputs.new_contracts_subtree_sibling_path, - baseRollupInputs.start_contract_tree_snapshot.root); - - // check for nullifiers - auto leafIndexNullifierSubtreeDepth = - baseRollupInputs.start_nullifier_tree_snapshot.next_available_leaf_index >> NULLIFIER_SUBTREE_DEPTH; - check_membership(composer, - EMPTY_NULLIFIER_SUBTREE_ROOT, - leafIndexNullifierSubtreeDepth, - baseRollupInputs.new_nullifiers_subtree_sibling_path, - baseRollupInputs.start_nullifier_tree_snapshot.root); - // Check contracts and commitments subtrees NT::fr contracts_tree_subroot = calculate_contract_subtree(contract_leaves); NT::fr commitments_tree_subroot = calculate_commitments_subtree(composer, baseRollupInputs); - // Insert subtrees to the tree: + // Insert commitment subtrees: auto end_private_data_tree_snapshot = - insert_subtree_to_snapshot_tree(baseRollupInputs.new_commitments_subtree_sibling_path, - baseRollupInputs.start_private_data_tree_snapshot.next_available_leaf_index, - commitments_tree_subroot, - PRIVATE_DATA_SUBTREE_DEPTH); - + components::insert_subtree_to_snapshot_tree(composer, + baseRollupInputs.start_private_data_tree_snapshot, + baseRollupInputs.new_commitments_subtree_sibling_path, + EMPTY_COMMITMENTS_SUBTREE_ROOT, + commitments_tree_subroot, + PRIVATE_DATA_SUBTREE_DEPTH); + + // Insert contract subtrees: auto end_contract_tree_snapshot = - insert_subtree_to_snapshot_tree(baseRollupInputs.new_contracts_subtree_sibling_path, - baseRollupInputs.start_contract_tree_snapshot.next_available_leaf_index, - contracts_tree_subroot, - CONTRACT_SUBTREE_DEPTH); - - // Check nullifiers and check new subtree insertion + components::insert_subtree_to_snapshot_tree(composer, + baseRollupInputs.start_contract_tree_snapshot, + baseRollupInputs.new_contracts_subtree_sibling_path, + EMPTY_CONTRACTS_SUBTREE_ROOT, + contracts_tree_subroot, + CONTRACT_SUBTREE_DEPTH); + + // Update nullifier tree and insert new subtree + auto leafIndexNullifierSubtreeDepth = + baseRollupInputs.start_nullifier_tree_snapshot.next_available_leaf_index >> NULLIFIER_SUBTREE_DEPTH; + components::check_membership(composer, + EMPTY_NULLIFIER_SUBTREE_ROOT, + leafIndexNullifierSubtreeDepth, + baseRollupInputs.new_nullifiers_subtree_sibling_path, + baseRollupInputs.start_nullifier_tree_snapshot.root); AppendOnlySnapshot end_nullifier_tree_snapshot = check_nullifier_tree_non_membership_and_insert_to_tree(composer, baseRollupInputs); diff --git a/circuits/cpp/src/aztec3/circuits/rollup/components/components.cpp b/circuits/cpp/src/aztec3/circuits/rollup/components/components.cpp new file mode 100644 index 00000000000..94f9c52c98a --- /dev/null +++ b/circuits/cpp/src/aztec3/circuits/rollup/components/components.cpp @@ -0,0 +1,128 @@ +#include "aztec3/circuits/abis/rollup/base/base_or_merge_rollup_public_inputs.hpp" +#include "aztec3/constants.hpp" +#include "barretenberg/crypto/pedersen_hash/pedersen.hpp" +#include "barretenberg/crypto/sha256/sha256.hpp" +#include "barretenberg/ecc/curves/bn254/fr.hpp" +#include "barretenberg/stdlib/hash/pedersen/pedersen.hpp" +#include "init.hpp" + +#include +#include +#include +#include +#include +#include + +namespace aztec3::circuits::rollup::components { + +/** + * @brief Create an aggregation object for the proofs that are provided + * - We add points P0 for each of our proofs + * - We add points P1 for each of our proofs + * - We concat our public inputs + * + * @param mergeRollupInputs + * @return AggregationObject + */ +AggregationObject aggregate_proofs(BaseOrMergeRollupPublicInputs const& left, + BaseOrMergeRollupPublicInputs const& right) +{ + // TODO: NOTE: for now we simply return the aggregation object from the first proof + (void)right; + return left.end_aggregation_object; +} + +/** + * @brief Asserts that the rollup types are the same + * + * @param left - The public inputs of the left rollup (base or merge) + * @param right - The public inputs of the right rollup (base or merge) + */ +void assert_both_input_proofs_of_same_rollup_type(DummyComposer& composer, + BaseOrMergeRollupPublicInputs const& left, + BaseOrMergeRollupPublicInputs const& right) +{ + composer.do_assert(left.rollup_type == right.rollup_type, "input proofs are of different rollup types"); +} + +/** + * @brief Asserts that the rollup subtree heights are the same and returns the height + * + * @param left - The public inputs of the left rollup (base or merge) + * @param right - The public inputs of the right rollup (base or merge) + * @return NT::fr - The height of the rollup subtrees + */ +NT::fr assert_both_input_proofs_of_same_height_and_return(DummyComposer& composer, + BaseOrMergeRollupPublicInputs const& left, + BaseOrMergeRollupPublicInputs const& right) +{ + composer.do_assert(left.rollup_subtree_height == right.rollup_subtree_height, + "input proofs are of different rollup heights"); + return left.rollup_subtree_height; +} + +/** + * @brief Asserts that the constants used in the left and right child are identical + * + * @param left - The public inputs of the left rollup (base or merge) + * @param right - The public inputs of the right rollup (base or merge) + */ +void assert_equal_constants(DummyComposer& composer, + BaseOrMergeRollupPublicInputs const& left, + BaseOrMergeRollupPublicInputs const& right) +{ + composer.do_assert(left.constants == right.constants, "input proofs have different constants"); +} + +// Generates a 512 bit input from right and left 256 bit hashes. Then computes the sha256, and splits the hash into two +// field elements, a high and a low that is returned. +std::array compute_calldata_hash(std::array, 2> previous_rollup_data) +{ + // Generate a 512 bit input from right and left 256 bit hashes + std::array calldata_hash_input_bytes; + for (uint8_t i = 0; i < 2; i++) { + std::array calldata_hash_fr = previous_rollup_data[i].base_or_merge_rollup_public_inputs.calldata_hash; + + auto high_buffer = calldata_hash_fr[0].to_buffer(); + auto low_buffer = calldata_hash_fr[1].to_buffer(); + + for (uint8_t j = 0; j < 16; ++j) { + calldata_hash_input_bytes[i * 32 + j] = high_buffer[16 + j]; + calldata_hash_input_bytes[i * 32 + 16 + j] = low_buffer[16 + j]; + } + } + + // Compute the sha256 + std::vector calldata_hash_input_bytes_vec(calldata_hash_input_bytes.begin(), + calldata_hash_input_bytes.end()); + auto h = sha256::sha256(calldata_hash_input_bytes_vec); + + // Split the hash into two fields, a high and a low + std::array buf_1, buf_2; + for (uint8_t i = 0; i < 16; i++) { + buf_1[i] = 0; + buf_1[16 + i] = h[i]; + buf_2[i] = 0; + buf_2[16 + i] = h[i + 16]; + } + auto high = fr::serialize_from_buffer(buf_1.data()); + auto low = fr::serialize_from_buffer(buf_2.data()); + + return { high, low }; +} + +// asserts that the end snapshot of previous_rollup 0 equals the start snapshot of previous_rollup 1 (i.e. ensure they +// follow on from one-another). Ensures that right uses the tres that was updated by left. +void assert_prev_rollups_follow_on_from_each_other(DummyComposer& composer, + BaseOrMergeRollupPublicInputs const& left, + BaseOrMergeRollupPublicInputs const& right) +{ + composer.do_assert(left.end_private_data_tree_snapshot == right.start_private_data_tree_snapshot, + "input proofs have different private data tree snapshots"); + composer.do_assert(left.end_nullifier_tree_snapshot == right.start_nullifier_tree_snapshot, + "input proofs have different nullifier tree snapshots"); + composer.do_assert(left.end_contract_tree_snapshot == right.start_contract_tree_snapshot, + "input proofs have different contract tree snapshots"); +} + +} // namespace aztec3::circuits::rollup::components \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/rollup/components/components.hpp b/circuits/cpp/src/aztec3/circuits/rollup/components/components.hpp new file mode 100644 index 00000000000..f19d623b2e0 --- /dev/null +++ b/circuits/cpp/src/aztec3/circuits/rollup/components/components.hpp @@ -0,0 +1,73 @@ +#pragma once + +#include "init.hpp" + +namespace aztec3::circuits::rollup::components { +std::array compute_calldata_hash(std::array, 2> previous_rollup_data); +void assert_prev_rollups_follow_on_from_each_other(DummyComposer& composer, + BaseOrMergeRollupPublicInputs const& left, + BaseOrMergeRollupPublicInputs const& right); +void assert_both_input_proofs_of_same_rollup_type(DummyComposer& composer, + BaseOrMergeRollupPublicInputs const& left, + BaseOrMergeRollupPublicInputs const& right); +NT::fr assert_both_input_proofs_of_same_height_and_return(DummyComposer& composer, + BaseOrMergeRollupPublicInputs const& left, + BaseOrMergeRollupPublicInputs const& right); +void assert_equal_constants(DummyComposer& composer, + BaseOrMergeRollupPublicInputs const& left, + BaseOrMergeRollupPublicInputs const& right); + +AggregationObject aggregate_proofs(BaseOrMergeRollupPublicInputs const& left, + BaseOrMergeRollupPublicInputs const& right); + +template +NT::fr iterate_through_tree_via_sibling_path(NT::fr leaf, NT::uint32 leafIndex, std::array siblingPath) +{ + for (size_t i = 0; i < siblingPath.size(); i++) { + if (leafIndex & (1 << i)) { + leaf = proof_system::plonk::stdlib::merkle_tree::hash_pair_native(siblingPath[i], leaf); + } else { + leaf = proof_system::plonk::stdlib::merkle_tree::hash_pair_native(leaf, siblingPath[i]); + } + } + return leaf; +} + +template +void check_membership(DummyComposer& composer, + NT::fr const& leaf, + NT::uint32 const& leafIndex, + std::array const& siblingPath, + NT::fr const& root) +{ + auto calculatedRoot = iterate_through_tree_via_sibling_path(leaf, leafIndex, siblingPath); + // TODO: update tests to build the correct trees + composer.do_assert(calculatedRoot == root, "Membership check failed"); +} + +template +AppendOnlySnapshot insert_subtree_to_snapshot_tree(DummyComposer& composer, + AppendOnlySnapshot snapshot, + std::array siblingPath, + NT::fr emptySubtreeRoot, + NT::fr subtreeRootToInsert, + uint8_t subtreeDepth) +{ + // TODO: Sanity check len of siblingPath > height of subtree + // TODO: Ensure height of subtree is correct (eg 3 for commitments, 1 for contracts) + auto leafIndexAtDepth = snapshot.next_available_leaf_index >> subtreeDepth; + + // Check that the current root is correct and that there is an empty subtree at the insertion location + check_membership(composer, emptySubtreeRoot, leafIndexAtDepth, siblingPath, snapshot.root); + + // if index of leaf is x, index of its parent is x/2 or x >> 1. We need to find the parent `subtreeDepth` levels up. + auto new_root = iterate_through_tree_via_sibling_path(subtreeRootToInsert, leafIndexAtDepth, siblingPath); + + // 2^subtreeDepth is the number of leaves added. 2^x = 1 << x + auto new_next_available_leaf_index = snapshot.next_available_leaf_index + (uint8_t(1) << subtreeDepth); + + AppendOnlySnapshot newTreeSnapshot = { .root = new_root, + .next_available_leaf_index = new_next_available_leaf_index }; + return newTreeSnapshot; +} +} // namespace aztec3::circuits::rollup::components \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/rollup/components/init.hpp b/circuits/cpp/src/aztec3/circuits/rollup/components/init.hpp new file mode 100644 index 00000000000..77f8138d368 --- /dev/null +++ b/circuits/cpp/src/aztec3/circuits/rollup/components/init.hpp @@ -0,0 +1,29 @@ + +#pragma once + +#include "aztec3/circuits/abis/append_only_tree_snapshot.hpp" +#include "aztec3/circuits/abis/rollup/constant_rollup_data.hpp" +#include "aztec3/circuits/abis/rollup/base/base_or_merge_rollup_public_inputs.hpp" +#include "aztec3/circuits/abis/rollup/merge/merge_rollup_inputs.hpp" +#include +#include +#include "aztec3/utils/dummy_composer.hpp" + +#include +#include +#include +#include +#include + +namespace aztec3::circuits::rollup::components { + +using NT = aztec3::utils::types::NativeTypes; + +// Params +using NT = aztec3::utils::types::NativeTypes; +using AggregationObject = aztec3::utils::types::NativeTypes::AggregationObject; +using BaseOrMergeRollupPublicInputs = aztec3::circuits::abis::BaseOrMergeRollupPublicInputs; +using AppendOnlySnapshot = abis::AppendOnlyTreeSnapshot; +using DummyComposer = aztec3::utils::DummyComposer; + +} // namespace aztec3::circuits::rollup::components \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/rollup/merge/native_merge_rollup_circuit.cpp b/circuits/cpp/src/aztec3/circuits/rollup/merge/native_merge_rollup_circuit.cpp index 1d70f858517..4368235f75a 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/merge/native_merge_rollup_circuit.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/merge/native_merge_rollup_circuit.cpp @@ -9,6 +9,8 @@ #include "barretenberg/stdlib/merkle_tree/merkle_tree.hpp" #include "init.hpp" +#include + #include #include #include @@ -18,116 +20,6 @@ namespace aztec3::circuits::rollup::native_merge_rollup { -/** - * @brief Create an aggregation object for the proofs that are provided - * - We add points P0 for each of our proofs - * - We add points P1 for each of our proofs - * - We concat our public inputs - * - * @param mergeRollupInputs - * @return AggregationObject - */ -AggregationObject aggregate_proofs(BaseOrMergeRollupPublicInputs const& left, - BaseOrMergeRollupPublicInputs const& right) -{ - // TODO: NOTE: for now we simply return the aggregation object from the first proof - (void)right; - return left.end_aggregation_object; -} - -/** - * @brief Asserts that the rollup types are the same - * - * @param left - The public inputs of the left rollup (base or merge) - * @param right - The public inputs of the right rollup (base or merge) - */ -void assert_both_input_proofs_of_same_rollup_type(DummyComposer& composer, - BaseOrMergeRollupPublicInputs const& left, - BaseOrMergeRollupPublicInputs const& right) -{ - composer.do_assert(left.rollup_type == right.rollup_type, "input proofs are of different rollup types"); -} - -/** - * @brief Asserts that the rollup subtree heights are the same and returns the height - * - * @param left - The public inputs of the left rollup (base or merge) - * @param right - The public inputs of the right rollup (base or merge) - * @return NT::fr - The height of the rollup subtrees - */ -NT::fr assert_both_input_proofs_of_same_height_and_return(DummyComposer& composer, - BaseOrMergeRollupPublicInputs const& left, - BaseOrMergeRollupPublicInputs const& right) -{ - composer.do_assert(left.rollup_subtree_height == right.rollup_subtree_height, - "input proofs are of different rollup heights"); - return left.rollup_subtree_height; -} - -/** - * @brief Asserts that the constants used in the left and right child are identical - * - * @param left - The public inputs of the left rollup (base or merge) - * @param right - The public inputs of the right rollup (base or merge) - */ -void assert_equal_constants(DummyComposer& composer, - BaseOrMergeRollupPublicInputs const& left, - BaseOrMergeRollupPublicInputs const& right) -{ - composer.do_assert(left.constants == right.constants, "input proofs have different constants"); -} - -// Generates a 512 bit input from right and left 256 bit hashes. Then computes the sha256, and splits the hash into two -// field elements, a high and a low that is returned. -std::array compute_calldata_hash(std::array, 2> const& previous_rollup_data) -{ - // Generate a 512 bit input from right and left 256 bit hashes - std::array calldata_hash_input_bytes; - for (uint8_t i = 0; i < 2; i++) { - std::array calldata_hash_fr = previous_rollup_data[i].base_or_merge_rollup_public_inputs.calldata_hash; - - auto high_buffer = calldata_hash_fr[0].to_buffer(); - auto low_buffer = calldata_hash_fr[1].to_buffer(); - - for (uint8_t j = 0; j < 16; ++j) { - calldata_hash_input_bytes[i * 32 + j] = high_buffer[16 + j]; - calldata_hash_input_bytes[i * 32 + 16 + j] = low_buffer[16 + j]; - } - } - - // Compute the sha256 - std::vector calldata_hash_input_bytes_vec(calldata_hash_input_bytes.begin(), - calldata_hash_input_bytes.end()); - auto h = sha256::sha256(calldata_hash_input_bytes_vec); - - // Split the hash into two fields, a high and a low - std::array buf_1, buf_2; - for (uint8_t i = 0; i < 16; i++) { - buf_1[i] = 0; - buf_1[16 + i] = h[i]; - buf_2[i] = 0; - buf_2[16 + i] = h[i + 16]; - } - auto high = fr::serialize_from_buffer(buf_1.data()); - auto low = fr::serialize_from_buffer(buf_2.data()); - - return { high, low }; -} - -// asserts that the end snapshot of previous_rollup 0 equals the start snapshot of previous_rollup 1 (i.e. ensure they -// follow on from one-another). Ensures that right uses the tres that was updated by left. -void assert_prev_rollups_follow_on_from_each_other(DummyComposer& composer, - BaseOrMergeRollupPublicInputs const& left, - BaseOrMergeRollupPublicInputs const& right) -{ - composer.do_assert(left.end_private_data_tree_snapshot == right.start_private_data_tree_snapshot, - "input proofs have different private data tree snapshots"); - composer.do_assert(left.end_nullifier_tree_snapshot == right.start_nullifier_tree_snapshot, - "input proofs have different nullifier tree snapshots"); - composer.do_assert(left.end_contract_tree_snapshot == right.start_contract_tree_snapshot, - "input proofs have different contract tree snapshots"); -} - BaseOrMergeRollupPublicInputs merge_rollup_circuit(DummyComposer& composer, MergeRollupInputs const& mergeRollupInputs) { // TODO: Verify the previous rollup proofs @@ -139,14 +31,14 @@ BaseOrMergeRollupPublicInputs merge_rollup_circuit(DummyComposer& composer, Merg // check that both input proofs are either both "BASE" or "MERGE" and not a mix! // this prevents having wonky commitment, nullifier and contract subtrees. - AggregationObject aggregation_object = aggregate_proofs(left, right); - assert_both_input_proofs_of_same_rollup_type(composer, left, right); - auto current_height = assert_both_input_proofs_of_same_height_and_return(composer, left, right); - assert_equal_constants(composer, left, right); - assert_prev_rollups_follow_on_from_each_other(composer, left, right); + AggregationObject aggregation_object = components::aggregate_proofs(left, right); + components::assert_both_input_proofs_of_same_rollup_type(composer, left, right); + auto current_height = components::assert_both_input_proofs_of_same_height_and_return(composer, left, right); + components::assert_equal_constants(composer, left, right); + components::assert_prev_rollups_follow_on_from_each_other(composer, left, right); // compute calldata hash: - auto new_calldata_hash = compute_calldata_hash(mergeRollupInputs.previous_rollup_data); + auto new_calldata_hash = components::compute_calldata_hash(mergeRollupInputs.previous_rollup_data); BaseOrMergeRollupPublicInputs public_inputs = { .rollup_type = abis::MERGE_ROLLUP_TYPE, diff --git a/circuits/cpp/src/aztec3/circuits/rollup/merge/native_merge_rollup_circuit.hpp b/circuits/cpp/src/aztec3/circuits/rollup/merge/native_merge_rollup_circuit.hpp index a7bda0ec25f..ec7f50978ee 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/merge/native_merge_rollup_circuit.hpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/merge/native_merge_rollup_circuit.hpp @@ -13,20 +13,4 @@ namespace aztec3::circuits::rollup::native_merge_rollup { BaseOrMergeRollupPublicInputs merge_rollup_circuit(DummyComposer& composer, MergeRollupInputs const& mergeRollupInputs); - -std::array compute_calldata_hash(std::array, 2> const& previous_rollup_data); -void assert_prev_rollups_follow_on_from_each_other(DummyComposer& composer, - BaseOrMergeRollupPublicInputs const& left, - BaseOrMergeRollupPublicInputs const& right); -void assert_both_input_proofs_of_same_rollup_type(DummyComposer& composer, - BaseOrMergeRollupPublicInputs const& left, - BaseOrMergeRollupPublicInputs const& right); -NT::fr assert_both_input_proofs_of_same_height_and_return(DummyComposer& composer, - BaseOrMergeRollupPublicInputs const& left, - BaseOrMergeRollupPublicInputs const& right); -void assert_equal_constants(DummyComposer& composer, - BaseOrMergeRollupPublicInputs const& left, - BaseOrMergeRollupPublicInputs const& right); -AggregationObject aggregate_proofs(BaseOrMergeRollupPublicInputs const& left, - BaseOrMergeRollupPublicInputs const& right); } // namespace aztec3::circuits::rollup::native_merge_rollup \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/rollup/root/init.hpp b/circuits/cpp/src/aztec3/circuits/rollup/root/init.hpp index bd8f1e9b8dd..5b8776ca2cd 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/root/init.hpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/root/init.hpp @@ -26,7 +26,5 @@ using RootRollupInputs = abis::RootRollupInputs; using RootRollupPublicInputs = abis::RootRollupPublicInputs; using Aggregator = aztec3::circuits::recursion::Aggregator; -using AggregationObject = utils::types::NativeTypes::AggregationObject; -using AppendOnlySnapshot = abis::AppendOnlyTreeSnapshot; } // namespace aztec3::circuits::rollup::native_root_rollup \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/rollup/root/native_root_rollup_circuit.cpp b/circuits/cpp/src/aztec3/circuits/rollup/root/native_root_rollup_circuit.cpp index 10adc7f1375..75e07a4ee29 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/root/native_root_rollup_circuit.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/root/native_root_rollup_circuit.cpp @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include @@ -26,55 +26,7 @@ namespace aztec3::circuits::rollup::native_root_rollup { // Access Native types through NT namespace -template -NT::fr iterate_through_tree_via_sibling_path(NT::fr leaf, - NT::uint32 const& leafIndex, - std::array const& siblingPath) -{ - for (size_t i = 0; i < siblingPath.size(); i++) { - if (leafIndex & (1 << i)) { - leaf = proof_system::plonk::stdlib::merkle_tree::hash_pair_native(siblingPath[i], leaf); - } else { - leaf = proof_system::plonk::stdlib::merkle_tree::hash_pair_native(leaf, siblingPath[i]); - } - } - return leaf; -} - -template -void check_membership(DummyComposer& composer, - NT::fr const& leaf, - NT::uint32 const& leafIndex, - std::array const& siblingPath, - NT::fr const& root) -{ - auto computed_root = iterate_through_tree_via_sibling_path(leaf, leafIndex, siblingPath); - composer.do_assert(root == computed_root, "Membership check failed"); -} - -template -AppendOnlySnapshot insert_at_empty_in_snapshot_tree(DummyComposer& composer, - AppendOnlySnapshot const& old_snapshot, - std::array const& siblingPath, - NT::fr leaf) -{ - // check that the value is zero at the path (unused) - // TODO: We should be able to actually skip this, because the contract will be indirectly enforce it through - // old_snapshot.next_available_leaf_index - check_membership(composer, fr::zero(), old_snapshot.next_available_leaf_index, siblingPath, old_snapshot.root); - - // Compute the new root after the update - auto new_root = iterate_through_tree_via_sibling_path(leaf, old_snapshot.next_available_leaf_index, siblingPath); - - return { .root = new_root, .next_available_leaf_index = old_snapshot.next_available_leaf_index + 1 }; -} - -// Important types: -// - BaseRollupPublicInputs - where we want to put our return values -// -// TODO: replace auto -RootRollupPublicInputs root_rollup_circuit(aztec3::utils::DummyComposer& composer, - RootRollupInputs const& rootRollupInputs) +RootRollupPublicInputs root_rollup_circuit(DummyComposer& composer, RootRollupInputs const& rootRollupInputs) { // TODO: Verify the previous rollup proofs // TODO: Check both previous rollup vks (in previous_rollup_data) against the permitted set of kernel vks. @@ -83,25 +35,29 @@ RootRollupPublicInputs root_rollup_circuit(aztec3::utils::DummyComposer& compose auto left = rootRollupInputs.previous_rollup_data[0].base_or_merge_rollup_public_inputs; auto right = rootRollupInputs.previous_rollup_data[1].base_or_merge_rollup_public_inputs; - AggregationObject aggregation_object = native_merge_rollup::aggregate_proofs(left, right); - native_merge_rollup::assert_both_input_proofs_of_same_rollup_type(composer, left, right); - native_merge_rollup::assert_both_input_proofs_of_same_height_and_return(composer, left, right); - native_merge_rollup::assert_equal_constants(composer, left, right); - native_merge_rollup::assert_prev_rollups_follow_on_from_each_other(composer, left, right); + auto aggregation_object = components::aggregate_proofs(left, right); + components::assert_both_input_proofs_of_same_rollup_type(composer, left, right); + components::assert_both_input_proofs_of_same_height_and_return(composer, left, right); + components::assert_equal_constants(composer, left, right); + components::assert_prev_rollups_follow_on_from_each_other(composer, left, right); // Update the historic private data tree - AppendOnlySnapshot end_tree_of_historic_private_data_tree_roots_snapshot = - insert_at_empty_in_snapshot_tree(composer, - left.constants.start_tree_of_historic_private_data_tree_roots_snapshot, - rootRollupInputs.new_historic_private_data_tree_root_sibling_path, - right.end_private_data_tree_snapshot.root); + auto end_tree_of_historic_private_data_tree_roots_snapshot = components::insert_subtree_to_snapshot_tree( + composer, + left.constants.start_tree_of_historic_private_data_tree_roots_snapshot, + rootRollupInputs.new_historic_private_data_tree_root_sibling_path, + fr::zero(), + right.end_private_data_tree_snapshot.root, + 0); // Update the historic private data tree - AppendOnlySnapshot end_tree_of_historic_contract_tree_roots_snapshot = - insert_at_empty_in_snapshot_tree(composer, - left.constants.start_tree_of_historic_contract_tree_roots_snapshot, - rootRollupInputs.new_historic_contract_tree_root_sibling_path, - right.end_contract_tree_snapshot.root); + auto end_tree_of_historic_contract_tree_roots_snapshot = + components::insert_subtree_to_snapshot_tree(composer, + left.constants.start_tree_of_historic_contract_tree_roots_snapshot, + rootRollupInputs.new_historic_contract_tree_root_sibling_path, + fr::zero(), + right.end_contract_tree_snapshot.root, + 0); RootRollupPublicInputs public_inputs = { .end_aggregation_object = aggregation_object, @@ -117,7 +73,7 @@ RootRollupPublicInputs root_rollup_circuit(aztec3::utils::DummyComposer& compose .start_tree_of_historic_contract_tree_roots_snapshot = left.constants.start_tree_of_historic_contract_tree_roots_snapshot, .end_tree_of_historic_contract_tree_roots_snapshot = end_tree_of_historic_contract_tree_roots_snapshot, - .calldata_hash = native_merge_rollup::compute_calldata_hash(rootRollupInputs.previous_rollup_data), + .calldata_hash = components::compute_calldata_hash(rootRollupInputs.previous_rollup_data), }; return public_inputs; From 9079a03a75727d07c91361baa0a5f852a62d467d Mon Sep 17 00:00:00 2001 From: Maddiaa <47148561+cheethas@users.noreply.github.com> Date: Wed, 12 Apr 2023 13:49:31 -0700 Subject: [PATCH 157/166] fix: Nullifier tree bug (#231) * fix: small nullifier tree issue * clean * fix: add negative test * revert hash_pair -> hash_multiple change * add new cmake instruction (issue #236) - point to suyashes pedersen branch --------- Co-authored-by: cheethas --- circuits/cpp/CMakeLists.txt | 10 ++ circuits/cpp/barretenberg | 2 +- .../src/aztec3/circuits/rollup/base/.test.cpp | 60 ++++++-- .../base/native_base_rollup_circuit.cpp | 25 ++-- .../base/nullifier_tree_testing_harness.cpp | 133 ++++++++++++++++-- .../base/nullifier_tree_testing_harness.hpp | 10 +- .../src/aztec3/circuits/rollup/base/utils.cpp | 79 ++++++++--- .../src/aztec3/circuits/rollup/base/utils.hpp | 18 ++- .../src/aztec3/circuits/rollup/root/.test.cpp | 12 -- 9 files changed, 275 insertions(+), 74 deletions(-) diff --git a/circuits/cpp/CMakeLists.txt b/circuits/cpp/CMakeLists.txt index a7693fb6902..832a811a9f7 100644 --- a/circuits/cpp/CMakeLists.txt +++ b/circuits/cpp/CMakeLists.txt @@ -29,6 +29,16 @@ option(DISABLE_TBB "Intel Thread Building Blocks" ON) option(COVERAGE "Enable collecting coverage from tests" OFF) option(ENABLE_HEAVY_TESTS "Enable heavy tests when collecting coverage" OFF) +# NOTE: investigate issue: +# https://github.com/AztecProtocol/aztec3-circuits/issues/236 +option(USE_TURBO "Enable the use of TurboPlonk in barretenberg." OFF) +if(USE_TURBO) + message(STATUS "Building barretenberg for TurboPlonk Composer.") + add_definitions(-DUSE_TURBO) +else() + message(STATUS "Building barretenberg for UltraPlonk Composer.") +endif() + if(ENABLE_ASAN) add_compile_options(-fsanitize=address) add_link_options(-fsanitize=address) diff --git a/circuits/cpp/barretenberg b/circuits/cpp/barretenberg index c6b26c4edb3..6b4eaa9e547 160000 --- a/circuits/cpp/barretenberg +++ b/circuits/cpp/barretenberg @@ -1 +1 @@ -Subproject commit c6b26c4edb350716257507bd7733eed95b58de16 +Subproject commit 6b4eaa9e5474de9af1e893b94e1b47c28a5e83ec diff --git a/circuits/cpp/src/aztec3/circuits/rollup/base/.test.cpp b/circuits/cpp/src/aztec3/circuits/rollup/base/.test.cpp index bc5d42e7855..52eda38267b 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/base/.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/base/.test.cpp @@ -1,8 +1,3 @@ -// #include -// #include -// #include -// #include -// #include #include "aztec3/circuits/abis/append_only_tree_snapshot.hpp" #include "aztec3/circuits/abis/membership_witness.hpp" #include "aztec3/circuits/abis/private_kernel/new_contract_data.hpp" @@ -36,12 +31,9 @@ #include #include #include -// #include -// #include #include -// #include #include #include @@ -469,12 +461,60 @@ TEST_F(base_rollup_tests, new_nullifier_tree_sparse) ASSERT_EQ(outputs.end_nullifier_tree_snapshot, nullifier_tree_end_snapshot); } +TEST_F(base_rollup_tests, nullifier_tree_regression) +{ + // Regression test caught when testing the typescript nullifier tree implementation + DummyComposer composer = DummyComposer(); + BaseRollupInputs empty_inputs = dummy_base_rollup_inputs_with_vk_proof(); + + // This test runs after some data has already been inserted into the tree + // This test will pre-populate the tree with 24 values (0 item + 23 more) simulating that a rollup inserting two + // random values has already succeeded. This rollup then adds two further random values that will end up having + // their low nullifiers point at each other + std::vector initial_values(23, 0); + for (size_t i = 0; i < 7; i++) { + initial_values[i] = i + 1; + } + // Note these are hex representations + initial_values[7] = uint256_t("2bb9aa4a22a6ae7204f2c67abaab59cead6558cde4ee25ce3464704cb2e38136"); + initial_values[8] = uint256_t("16a732095298ccca828c4d747813f8bd46e188079ed17904e2c9de50760833c8"); + + std::array new_nullifiers = { 0 }; + new_nullifiers[0] = uint256_t("16da4f27fb78de7e0db4c5a04b569bc46382c5f471da2f7d670beff1614e0118"), + new_nullifiers[1] = uint256_t("26ab07ce103a55e29f11478eaa36cebd10c4834b143a7debcc7ef53bfdb547dd"); + + std::tuple, AppendOnlyTreeSnapshot> inputs_and_snapshots = + utils::generate_nullifier_tree_testing_values(empty_inputs, new_nullifiers, initial_values); + BaseRollupInputs testing_inputs = std::get<0>(inputs_and_snapshots); + AppendOnlyTreeSnapshot nullifier_tree_start_snapshot = std::get<1>(inputs_and_snapshots); + AppendOnlyTreeSnapshot nullifier_tree_end_snapshot = std::get<2>(inputs_and_snapshots); + + /** + * RUN + */ + + // Run the circuit + BaseOrMergeRollupPublicInputs outputs = + aztec3::circuits::rollup::native_base_rollup::base_rollup_circuit(composer, testing_inputs); + + /** + * ASSERT + */ + // Start state + ASSERT_EQ(outputs.start_nullifier_tree_snapshot, nullifier_tree_start_snapshot); + + // End state + ASSERT_EQ(outputs.end_nullifier_tree_snapshot, nullifier_tree_end_snapshot); +} + +// Note leaving this test here as there are no negative tests, even though it no longer passes TEST_F(base_rollup_tests, new_nullifier_tree_sparse_attack) { // @todo THIS SHOULD NOT BE PASSING. The circuit should fail with an assert as we are trying to double-spend. /** * DESCRIPTION */ + DummyComposer composer = DummyComposer(); BaseRollupInputs empty_inputs = dummy_base_rollup_inputs_with_vk_proof(); @@ -486,9 +526,9 @@ TEST_F(base_rollup_tests, new_nullifier_tree_sparse_attack) // Run the circuit (SHOULD FAIL WITH AN ASSERT INSTEAD OF THIS!) BaseOrMergeRollupPublicInputs outputs = aztec3::circuits::rollup::native_base_rollup::base_rollup_circuit(composer, testing_inputs); -} -// TEST_F(base_rollup_tests, new_commitments_tree) {} + EXPECT_EQ(composer.has_failed(), true); +} TEST_F(base_rollup_tests, empty_block_calldata_hash) { diff --git a/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp b/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp index 9fac1b9b2f2..47c1aa671f7 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp @@ -273,7 +273,7 @@ AppendOnlySnapshot check_nullifier_tree_non_membership_and_insert_to_tree(DummyC // 2. If we receive the 0 nullifier leaf (where all values are 0, we skip insertion and leave a sparse subtree) // New nullifier subtree - std::array nullifier_leaves; + std::array nullifier_insertion_subtree; // This will update on each iteration auto current_nullifier_tree_root = baseRollupInputs.start_nullifier_tree_snapshot.root; @@ -291,6 +291,7 @@ AppendOnlySnapshot check_nullifier_tree_non_membership_and_insert_to_tree(DummyC // Witness containing index and path auto nullifier_index = 4 * i + j; + auto witness = baseRollupInputs.low_nullifier_membership_witness[nullifier_index]; // Preimage of the lo-index required for a non-membership proof auto low_nullifier_preimage = baseRollupInputs.low_nullifier_leaf_preimages[nullifier_index]; @@ -313,13 +314,19 @@ AppendOnlySnapshot check_nullifier_tree_non_membership_and_insert_to_tree(DummyC // TODO: this is a hack, and insecure, we need to fix this bool matched = false; for (size_t k = 0; k < nullifier_index; k++) { - if ((uint256_t(nullifier_leaves[k].nextValue) > uint256_t(nullifier) && - uint256_t(nullifier_leaves[k].value) < uint256_t(nullifier)) || - (nullifier_leaves[k].nextValue == 0 && nullifier_leaves[k].nextIndex == 0)) { + if ((uint256_t(nullifier_insertion_subtree[k].nextValue) > uint256_t(nullifier) && + uint256_t(nullifier_insertion_subtree[k].value) < uint256_t(nullifier)) || + (nullifier_insertion_subtree[k].nextValue == 0 && + nullifier_insertion_subtree[k].nextIndex == 0)) { matched = true; - nullifier_leaves[k].nextIndex = new_index; - nullifier_leaves[k].nextValue = nullifier; + // Update pointers + new_nullifier_leaf.nextIndex = nullifier_insertion_subtree[k].nextIndex; + new_nullifier_leaf.nextValue = nullifier_insertion_subtree[k].nextValue; + + // Update child + nullifier_insertion_subtree[k].nextIndex = new_index; + nullifier_insertion_subtree[k].nextValue = nullifier; } } // if not matched, our subtree will misformed - we must reject @@ -359,7 +366,7 @@ AppendOnlySnapshot check_nullifier_tree_non_membership_and_insert_to_tree(DummyC updated_low_nullifier.hash(), witness.leaf_index, witness.sibling_path); } - nullifier_leaves[nullifier_index] = new_nullifier_leaf; + nullifier_insertion_subtree[nullifier_index] = new_nullifier_leaf; } else { // 0 case NullifierLeaf new_nullifier_leaf = { @@ -367,7 +374,7 @@ AppendOnlySnapshot check_nullifier_tree_non_membership_and_insert_to_tree(DummyC .nextIndex = 0, .nextValue = 0, }; - nullifier_leaves[nullifier_index] = new_nullifier_leaf; + nullifier_insertion_subtree[nullifier_index] = new_nullifier_leaf; } // increment insertion index @@ -377,7 +384,7 @@ AppendOnlySnapshot check_nullifier_tree_non_membership_and_insert_to_tree(DummyC // Create new nullifier subtree to insert into the whole nullifier tree auto nullifier_sibling_path = baseRollupInputs.new_nullifiers_subtree_sibling_path; - auto nullifier_subtree_root = create_nullifier_subtree(nullifier_leaves); + auto nullifier_subtree_root = create_nullifier_subtree(nullifier_insertion_subtree); // Calculate the new root // We are inserting a subtree rather than a full tree here diff --git a/circuits/cpp/src/aztec3/circuits/rollup/base/nullifier_tree_testing_harness.cpp b/circuits/cpp/src/aztec3/circuits/rollup/base/nullifier_tree_testing_harness.cpp index 14c1d001df7..3c44dd7f92b 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/base/nullifier_tree_testing_harness.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/base/nullifier_tree_testing_harness.cpp @@ -1,6 +1,7 @@ #include "nullifier_tree_testing_harness.hpp" #include #include +#include #include using NullifierMemoryTree = proof_system::plonk::stdlib::merkle_tree::NullifierMemoryTree; @@ -10,13 +11,74 @@ NullifierMemoryTreeTestingHarness::NullifierMemoryTreeTestingHarness(size_t dept : NullifierMemoryTree(depth) {} +// Check for a larger value in an array +bool check_has_lesser_value(std::vector const& values, fr const& value) +{ + // Must perform comparisons on integers + uint256_t value_as_uint = uint256_t(value); + for (auto const& v : values) { + if (uint256_t(v) < value_as_uint) { + return true; + } + } + return false; +} + +// TODO: test +fr NullifierMemoryTreeTestingHarness::append_value(fr const& value) +{ + // If the value is 0, then we force insert the value to increase the size of the tree + // TODO: this is a hack + if (value == 0) { + nullifier_leaf new_leaf = { .value = 0, .nextIndex = 0, .nextValue = 0 }; + auto new_leaf_hash = new_leaf.hash(); + leaves_.push_back(new_leaf); + size_t new_leaf_index = leaves_.size() - 1; + auto root = update_element(new_leaf_index, new_leaf_hash); + return root; + } + + // Find the leaf with the value closest and less than `value` + size_t current; + bool is_already_present; + std::tie(current, is_already_present) = find_closest_leaf(leaves_, value); + + nullifier_leaf new_leaf = { .value = value, + .nextIndex = leaves_[current].nextIndex, + .nextValue = leaves_[current].nextValue }; + if (!is_already_present) { + // Update the current leaf to point it to the new leaf + leaves_[current].nextIndex = leaves_.size(); + leaves_[current].nextValue = value; + + // Insert the new leaf with (nextIndex, nextValue) of the current leaf + leaves_.push_back(new_leaf); + } + + // Update the old leaf in the tree + auto old_leaf_hash = leaves_[current].hash(); + size_t old_leaf_index = current; + auto root = update_element(old_leaf_index, old_leaf_hash); + + // Insert the new leaf in the tree + auto new_leaf_hash = new_leaf.hash(); + + size_t new_leaf_index = is_already_present ? old_leaf_index : leaves_.size() - 1; + root = update_element(new_leaf_index, new_leaf_hash); + + return root; +} + // handle synthetic membership assertions std::tuple, std::vector>, std::vector> -NullifierMemoryTreeTestingHarness::circuit_prep_batch_insert(std::vector const& values, - std::vector const& insertion_locations) +NullifierMemoryTreeTestingHarness::circuit_prep_batch_insert(std::vector const& values) { + // Start insertion index + fr start_insertion_index = this->size(); + // Low nullifiers std::vector low_nullifiers; + std::vector pending_insertion_tree; // Low nullifier sibling paths std::vector> sibling_paths; @@ -25,31 +87,76 @@ NullifierMemoryTreeTestingHarness::circuit_prep_batch_insert(std::vector con std::vector low_nullifier_indexes; // Keep track of the currently touched nodes while updating - std::set touched_nodes; + std::map> touched_nodes; + + // Keep track of 0 values + std::vector empty_sp(depth_, 0); + nullifier_leaf empty_leaf = { 0, 0, 0 }; + uint32_t empty_index = 0; // Find the leaf with the value closest and less than `value` for each value for (size_t i = 0; i < values.size(); ++i) { - auto value = values[i]; - auto insertion_index = uint256_t(insertion_locations[i]); + auto new_value = values[i]; + auto insertion_index = start_insertion_index + i; size_t current; bool is_already_present; + std::tie(current, is_already_present) = find_closest_leaf(leaves_, new_value); - std::tie(current, is_already_present) = find_closest_leaf(leaves_, value); + // If the inserted value is 0, then we ignore and provide a dummy low nullifier + if (new_value == 0) { + sibling_paths.push_back(empty_sp); + low_nullifier_indexes.push_back(empty_index); + low_nullifiers.push_back(empty_leaf); + } // If the low_nullifier node has been touched this sub tree insertion, we provide a dummy sibling path // It will be up to the circuit to check if the included node is valid vs the other nodes that have been // inserted before it If it has not been touched, we provide a sibling path then update the nodes pointers - if (touched_nodes.contains(current)) { - std::vector sp(depth_, 0); - auto empty_leaf = nullifier_leaf{ 0, 0, 0 }; + auto prev_nodes = touched_nodes.find(current); + + bool has_lesser_value = false; + if (prev_nodes != touched_nodes.end()) { + has_lesser_value = check_has_lesser_value(prev_nodes->second, new_value); + } + // If there is a lower value in the tree, we need to check the current low nullifiers for one that can be used + // if (current == 0 || has_lesser_value) { + if (has_lesser_value) { + + for (size_t j = 0; j < pending_insertion_tree.size(); ++j) { + // Skip checking empty values + if (pending_insertion_tree[j].value == 0) { + continue; + } + + if (pending_insertion_tree[j].value < new_value && + (pending_insertion_tree[j].nextValue > new_value || pending_insertion_tree[j].nextValue == 0)) { + // Add a new pending low nullifier for this value + nullifier_leaf new_leaf = { .value = new_value, + .nextIndex = pending_insertion_tree[j].nextIndex, + .nextValue = pending_insertion_tree[j].nextValue }; + pending_insertion_tree.push_back(new_leaf); + + // Update the pending low nullifier to point at the new value + pending_insertion_tree[j].nextIndex = insertion_index; + pending_insertion_tree[j].nextValue = new_value; + + break; + } + } // empty low nullifier - sibling_paths.push_back(sp); - low_nullifier_indexes.push_back(0); + sibling_paths.push_back(empty_sp); + low_nullifier_indexes.push_back(empty_index); low_nullifiers.push_back(empty_leaf); } else { - touched_nodes.insert(current); + // Update the touched mapping + if (prev_nodes == touched_nodes.end()) { + std::vector new_touched_values = { new_value }; + touched_nodes[current] = new_touched_values; + } else { + prev_nodes->second.push_back(new_value); + } nullifier_leaf low_nullifier = leaves_[current]; std::vector sibling_path = this->get_sibling_path(current); @@ -61,7 +168,7 @@ NullifierMemoryTreeTestingHarness::circuit_prep_batch_insert(std::vector con // Update the current low nullifier nullifier_leaf new_leaf = { .value = low_nullifier.value, .nextIndex = insertion_index, - .nextValue = value }; + .nextValue = new_value }; // Update the old leaf in the tree update_element(current, new_leaf.hash()); diff --git a/circuits/cpp/src/aztec3/circuits/rollup/base/nullifier_tree_testing_harness.hpp b/circuits/cpp/src/aztec3/circuits/rollup/base/nullifier_tree_testing_harness.hpp index f199730b1af..4a8a8411b4c 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/base/nullifier_tree_testing_harness.hpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/base/nullifier_tree_testing_harness.hpp @@ -28,13 +28,19 @@ class NullifierMemoryTreeTestingHarness : public proof_system::plonk::stdlib::me // Get the value immediately lower than the given value std::pair find_lower(fr const& value); + // Append a value to the tree, even zeros + fr append_value(fr const& value); + // Utilities to inspect tree - fr size() const { return total_size_; } + fr total_size() const { return total_size_; } fr depth() const { return depth_; } + // Current size of the tree + fr size() { return leaves_.size(); } + // Get all of the sibling paths and low nullifier values required to craft an non membership / inclusion proofs std::tuple, std::vector>, std::vector> - circuit_prep_batch_insert(std::vector const& values, std::vector const& insertion_locations); + circuit_prep_batch_insert(std::vector const& values); protected: using MemoryTree::depth_; diff --git a/circuits/cpp/src/aztec3/circuits/rollup/base/utils.cpp b/circuits/cpp/src/aztec3/circuits/rollup/base/utils.cpp index 228953f1ce1..b97b6e22500 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/base/utils.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/base/utils.cpp @@ -89,17 +89,35 @@ BaseRollupInputs dummy_base_rollup_inputs_with_vk_proof() return baseRollupInputs; } -NullifierMemoryTreeTestingHarness get_initial_nullifier_tree(size_t spacing = 5) +/** + * @brief Get initial nullifier tree object + * + * @param initial_values values to pre-populate the tree + * @return NullifierMemoryTreeTestingHarness + */ +NullifierMemoryTreeTestingHarness get_initial_nullifier_tree(std::vector initial_values) { - // Create a nullifier tree with 8 nullifiers, this padding is required so that the default 0 value in an indexed - // merkle tree does not affect our tests Nullifier tree at the start NullifierMemoryTreeTestingHarness nullifier_tree = NullifierMemoryTreeTestingHarness(NULLIFIER_TREE_HEIGHT); - // Start from 1 as 0 is always inserted + for (size_t i = 0; i < initial_values.size(); ++i) { + nullifier_tree.append_value(initial_values[i]); + } + return nullifier_tree; +} + +/** + * @brief An extension of `get_initial_nullifier_tree` that will populate with linearly spaced values + * + * @param spacing + * @return NullifierMemoryTreeTestingHarness + */ +NullifierMemoryTreeTestingHarness get_initial_nullifier_tree_lin_space(size_t spacing = 5, size_t start = 0) +{ + std::vector nullifiers; for (size_t i = 1; i < 8; ++i) { // insert 5, 10, 15, 20 ... - nullifier_tree.update_element(i * spacing); + nullifiers.push_back(start + (i * spacing)); } - return nullifier_tree; + return get_initial_nullifier_tree(nullifiers); } std::tuple, AppendOnlyTreeSnapshot, AppendOnlyTreeSnapshot> @@ -113,22 +131,43 @@ generate_nullifier_tree_testing_values(BaseRollupInputs inputs, auto insertion_val = (starting_insertion_value + i * spacing); nullifiers[i] = fr(insertion_val); } - return generate_nullifier_tree_testing_values(inputs, nullifiers, spacing); + + // Generate initial values lin spaved + std::vector initial_values; + for (size_t i = 1; i < 8; ++i) { + initial_values.push_back(i * spacing); + } + + return generate_nullifier_tree_testing_values(inputs, nullifiers, initial_values); +} + +std::tuple, AppendOnlyTreeSnapshot, AppendOnlyTreeSnapshot> +generate_nullifier_tree_testing_values(BaseRollupInputs inputs, + std::array new_nullifiers, + size_t spacing = 5) +{ + // Generate initial values lin spaced + std::vector initial_values; + for (size_t i = 1; i < 8; ++i) { + initial_values.push_back(i * spacing); + } + + return generate_nullifier_tree_testing_values(inputs, new_nullifiers, initial_values); } std::tuple, AppendOnlyTreeSnapshot, AppendOnlyTreeSnapshot> generate_nullifier_tree_testing_values(BaseRollupInputs rollupInputs, std::array new_nullifiers, - size_t spacing_prefill = 1) + std::vector initial_values) { + size_t start_tree_size = initial_values.size() + 1; // Generate nullifier tree testing values - - NullifierMemoryTreeTestingHarness nullifier_tree = get_initial_nullifier_tree(spacing_prefill); - NullifierMemoryTreeTestingHarness parallel_insertion_tree = get_initial_nullifier_tree(spacing_prefill); + NullifierMemoryTreeTestingHarness nullifier_tree = get_initial_nullifier_tree(initial_values); + NullifierMemoryTreeTestingHarness reference_tree = get_initial_nullifier_tree(initial_values); AppendOnlyTreeSnapshot nullifier_tree_start_snapshot = { .root = nullifier_tree.root(), - .next_available_leaf_index = uint32_t(8), + .next_available_leaf_index = uint32_t(start_tree_size), }; const size_t NUMBER_OF_NULLIFIERS = KERNEL_NEW_NULLIFIERS_LENGTH * 2; @@ -140,7 +179,6 @@ generate_nullifier_tree_testing_values(BaseRollupInputs rollupInputs, // Calculate the predecessor nullifier pre-images // Get insertion values std::vector insertion_values; - std::vector insertion_locations; std::array new_nullifiers_kernel_1; std::array new_nullifiers_kernel_2; @@ -151,13 +189,13 @@ generate_nullifier_tree_testing_values(BaseRollupInputs rollupInputs, } else { new_nullifiers_kernel_2[i - KERNEL_NEW_NULLIFIERS_LENGTH] = insertion_val; } - insertion_locations.push_back(NUMBER_OF_NULLIFIERS + i); insertion_values.push_back(insertion_val); - parallel_insertion_tree.update_element(insertion_val); + reference_tree.append_value(insertion_val); + auto hashes = reference_tree.get_hashes(); } // Get the hash paths etc from the insertion values - auto witnesses_and_preimages = nullifier_tree.circuit_prep_batch_insert(insertion_values, insertion_locations); + auto witnesses_and_preimages = nullifier_tree.circuit_prep_batch_insert(insertion_values); auto new_nullifier_leaves_preimages = std::get<0>(witnesses_and_preimages); auto new_nullifier_leaves_sibling_paths = std::get<1>(witnesses_and_preimages); @@ -188,17 +226,16 @@ generate_nullifier_tree_testing_values(BaseRollupInputs rollupInputs, } // Get expected root with subtrees inserted correctly - fr end_root = parallel_insertion_tree.root(); - // Expected end state AppendOnlyTreeSnapshot nullifier_tree_end_snapshot = { - .root = end_root, - .next_available_leaf_index = 16, + .root = reference_tree.root(), + .next_available_leaf_index = uint32_t(reference_tree.size()), }; // Get the sibling path, we should be able to use the same path to get to the end root - std::vector sibling_path = parallel_insertion_tree.get_sibling_path(8); + std::vector sibling_path = reference_tree.get_sibling_path(start_tree_size); std::array sibling_path_array; + // Chop the first 3 levels from the sibling_path sibling_path.erase(sibling_path.begin(), sibling_path.begin() + NULLIFIER_SUBTREE_DEPTH); std::copy(sibling_path.begin(), sibling_path.end(), sibling_path_array.begin()); diff --git a/circuits/cpp/src/aztec3/circuits/rollup/base/utils.hpp b/circuits/cpp/src/aztec3/circuits/rollup/base/utils.hpp index 86ebc0ba45b..fae81e6dfc7 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/base/utils.hpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/base/utils.hpp @@ -8,6 +8,8 @@ namespace aztec3::circuits::rollup::base::utils { namespace { using NT = aztec3::utils::types::NativeTypes; using aztec3::circuits::abis::BaseRollupInputs; +using nullifier_tree_testing_values = + std::tuple, abis::AppendOnlyTreeSnapshot, abis::AppendOnlyTreeSnapshot>; } // namespace BaseRollupInputs dummy_base_rollup_inputs_with_vk_proof(); @@ -15,12 +17,16 @@ BaseRollupInputs dummy_base_rollup_inputs_with_vk_proof(); NullifierMemoryTreeTestingHarness get_initial_nullifier_tree(size_t spacing); abis::AppendOnlyTreeSnapshot get_snapshot_of_tree_state(NullifierMemoryTreeTestingHarness nullifier_tree); -std::tuple, abis::AppendOnlyTreeSnapshot, abis::AppendOnlyTreeSnapshot> -generate_nullifier_tree_testing_values(BaseRollupInputs inputs, size_t starting_insertion_value, size_t spacing); +nullifier_tree_testing_values generate_nullifier_tree_testing_values(BaseRollupInputs inputs, + size_t starting_insertion_value, + size_t spacing); -std::tuple, abis::AppendOnlyTreeSnapshot, abis::AppendOnlyTreeSnapshot> -generate_nullifier_tree_testing_values(BaseRollupInputs inputs, - std::array new_nullifiers, - size_t spacing_prefill); +nullifier_tree_testing_values generate_nullifier_tree_testing_values( + BaseRollupInputs inputs, + std::array new_nullifiers, + std::vector initial_values); + +nullifier_tree_testing_values generate_nullifier_tree_testing_values( + BaseRollupInputs inputs, std::array new_nullifiers, size_t spacing); } // namespace aztec3::circuits::rollup::base::utils \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/rollup/root/.test.cpp b/circuits/cpp/src/aztec3/circuits/rollup/root/.test.cpp index 03712594fa9..6600ebeff45 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/root/.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/root/.test.cpp @@ -1,8 +1,3 @@ -// #include -// #include -// #include -// #include -// #include #include "aztec3/circuits/abis/append_only_tree_snapshot.hpp" #include "aztec3/circuits/abis/membership_witness.hpp" #include "aztec3/circuits/abis/private_kernel/new_contract_data.hpp" @@ -39,12 +34,9 @@ #include #include #include -// #include -// #include #include -// #include #include #include @@ -55,10 +47,6 @@ #include #include -// #include -// #include -// #include - namespace { using aztec3::circuits::abis::CallContext; From 9719e83a41d6ec3d5bc55cce3688ffaf6f553d5e Mon Sep 17 00:00:00 2001 From: Maddiaa <47148561+cheethas@users.noreply.github.com> Date: Wed, 12 Apr 2023 15:07:51 -0700 Subject: [PATCH 158/166] fix: update bootstrap to specify turbo (#237) Co-authored-by: cheethas --- circuits/cpp/bootstrap.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/circuits/cpp/bootstrap.sh b/circuits/cpp/bootstrap.sh index b70d56eada9..7a9bcb72975 100755 --- a/circuits/cpp/bootstrap.sh +++ b/circuits/cpp/bootstrap.sh @@ -68,7 +68,7 @@ echo "# When running cmake directly, remember to use: --build --preset $PRESET" echo "#################################" # Build native. -cmake --preset $PRESET -DCMAKE_BUILD_TYPE=RelWithAssert +cmake --preset $PRESET -DCMAKE_BUILD_TYPE=RelWithAssert -USE_TURBO=true cmake --build --preset $PRESET ${@/#/--target } # Install the webassembly toolchain. @@ -77,5 +77,5 @@ if ! [ -d "./barretenberg/cpp/src/wasi-sdk-$WASI_VERSION.0" ] ; then fi # Build WASM. -cmake --preset wasm +cmake --preset wasm -USE_TURBO=true cmake --build --preset wasm From f5cd775236a61b0b81b2da290e4c5007d3f994ea Mon Sep 17 00:00:00 2001 From: Rahul Kothari Date: Thu, 13 Apr 2023 02:31:01 +0100 Subject: [PATCH 159/166] add cbinds for merge (#227) --- .../aztec3/circuits/rollup/merge/.test.cpp | 52 ++++++++++++++++++- .../aztec3/circuits/rollup/merge/c_bind.cpp | 37 +++++++++++++ .../src/aztec3/circuits/rollup/merge/c_bind.h | 10 ++++ 3 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 circuits/cpp/src/aztec3/circuits/rollup/merge/c_bind.cpp create mode 100644 circuits/cpp/src/aztec3/circuits/rollup/merge/c_bind.h diff --git a/circuits/cpp/src/aztec3/circuits/rollup/merge/.test.cpp b/circuits/cpp/src/aztec3/circuits/rollup/merge/.test.cpp index 73b6ee14813..ecfa5171635 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/merge/.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/merge/.test.cpp @@ -2,6 +2,7 @@ #include #include "aztec3/circuits/rollup/merge/init.hpp" #include "aztec3/circuits/rollup/merge/utils.hpp" +#include "c_bind.h" namespace { using aztec3::circuits::rollup::merge::utils::dummy_merge_rollup_inputs_with_vk_proof; @@ -14,7 +15,49 @@ using DummyComposer = aztec3::utils::DummyComposer; } // namespace namespace aztec3::circuits::rollup::merge::native_merge_rollup_circuit { -class merge_rollup_tests : public ::testing::Test {}; +class merge_rollup_tests : public ::testing::Test { + protected: + void run_cbind(MergeRollupInputs& merge_rollup_inputs, + BaseOrMergeRollupPublicInputs& expected_public_inputs, + bool compare_pubins = true) + { + std::vector merge_rollup_inputs_vec; + write(merge_rollup_inputs_vec, merge_rollup_inputs); + + uint8_t const* public_inputs_buf; + info("creating proof"); + size_t public_inputs_size = merge_rollup__sim(merge_rollup_inputs_vec.data(), &public_inputs_buf); + info("PublicInputs size: ", public_inputs_size); + + if (compare_pubins) { + BaseOrMergeRollupPublicInputs public_inputs; + info("about to read..."); + uint8_t const* public_inputs_buf_tmp = public_inputs_buf; + read(public_inputs_buf_tmp, public_inputs); + info("about to assert..."); + ASSERT_EQ(public_inputs.calldata_hash.size(), expected_public_inputs.calldata_hash.size()); + for (size_t i = 0; i < public_inputs.calldata_hash.size(); i++) { + ASSERT_EQ(public_inputs.calldata_hash[i], expected_public_inputs.calldata_hash[i]); + } + + info("about to write expected..."); + std::vector expected_public_inputs_vec; + write(expected_public_inputs_vec, expected_public_inputs); + + info("about to assert buffers eq..."); + ASSERT_EQ(public_inputs_size, expected_public_inputs_vec.size()); + // Just compare the first 10 bytes of the serialized public outputs + if (public_inputs_size > 10) { + // for (size_t 0; i < public_inputs_size; i++) { + for (size_t i = 0; i < 10; i++) { + ASSERT_EQ(public_inputs_buf[i], expected_public_inputs_vec[i]); + } + } + } + free((void*)public_inputs_buf); + info("finished retesting via cbinds..."); + } +}; TEST_F(merge_rollup_tests, test_different_rollup_type_fails) { @@ -189,4 +232,11 @@ TEST_F(merge_rollup_tests, test_aggregate) ASSERT_EQ(inputs.previous_rollup_data[0].base_or_merge_rollup_public_inputs.end_aggregation_object.public_inputs, outputs.end_aggregation_object.public_inputs); } + +TEST_F(merge_rollup_tests, test_merge_cbind) +{ + MergeRollupInputs inputs = dummy_merge_rollup_inputs_with_vk_proof(); + BaseOrMergeRollupPublicInputs ignored_public_inputs; + run_cbind(inputs, ignored_public_inputs, false); +} } // namespace aztec3::circuits::rollup::merge::native_merge_rollup_circuit diff --git a/circuits/cpp/src/aztec3/circuits/rollup/merge/c_bind.cpp b/circuits/cpp/src/aztec3/circuits/rollup/merge/c_bind.cpp new file mode 100644 index 00000000000..1e19e95a09e --- /dev/null +++ b/circuits/cpp/src/aztec3/circuits/rollup/merge/c_bind.cpp @@ -0,0 +1,37 @@ +#include "aztec3/utils/dummy_composer.hpp" +#include "index.hpp" +#include "init.hpp" +#include "c_bind.h" + +namespace { +using NT = aztec3::utils::types::NativeTypes; +using DummyComposer = aztec3::utils::DummyComposer; +using aztec3::circuits::abis::BaseOrMergeRollupPublicInputs; +using aztec3::circuits::abis::MergeRollupInputs; +using aztec3::circuits::rollup::native_merge_rollup::merge_rollup_circuit; + +} // namespace +#define WASM_EXPORT __attribute__((visibility("default"))) +// WASM Cbinds +extern "C" { + +WASM_EXPORT size_t merge_rollup__sim(uint8_t const* merge_rollup_inputs_buf, + uint8_t const** merge_rollup_public_inputs_buf) +{ + DummyComposer composer = DummyComposer(); + MergeRollupInputs merge_rollup_inputs; + read(merge_rollup_inputs_buf, merge_rollup_inputs); + + BaseOrMergeRollupPublicInputs public_inputs = merge_rollup_circuit(composer, merge_rollup_inputs); + + // serialize public inputs to bytes vec + std::vector public_inputs_vec; + write(public_inputs_vec, public_inputs); + // copy public inputs to output buffer + auto raw_public_inputs_buf = (uint8_t*)malloc(public_inputs_vec.size()); + memcpy(raw_public_inputs_buf, (void*)public_inputs_vec.data(), public_inputs_vec.size()); + *merge_rollup_public_inputs_buf = raw_public_inputs_buf; + + return public_inputs_vec.size(); +} +} // extern "C" \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/rollup/merge/c_bind.h b/circuits/cpp/src/aztec3/circuits/rollup/merge/c_bind.h new file mode 100644 index 00000000000..b298f75338a --- /dev/null +++ b/circuits/cpp/src/aztec3/circuits/rollup/merge/c_bind.h @@ -0,0 +1,10 @@ +#include +#include + +#define WASM_EXPORT __attribute__((visibility("default"))) + +extern "C" { + +WASM_EXPORT size_t merge_rollup__sim(uint8_t const* merge_rollup_inputs_buf, + uint8_t const** merge_rollup_public_inputs_buf); +} \ No newline at end of file From c07a6fcab77def489583bad2793302378fde935e Mon Sep 17 00:00:00 2001 From: David Banks <47112877+dbanks12@users.noreply.github.com> Date: Thu, 13 Apr 2023 04:29:39 -0400 Subject: [PATCH 160/166] chore: zero-initialize all structs & their members and arrays (#233) * zero-initialize all abi and kernel structs. helper function to zero-init arrays of frs * revert uint32 assignments to 0 * better struct initialization in app circuits files * revert bad zero init of string * dont need to do as much in base utils since structs are sanely zero-initialized * format comment fix * use fill to initialize array of fields to zero --- .../abis/append_only_tree_snapshot.hpp | 4 +- .../src/aztec3/circuits/abis/call_context.hpp | 7 +- .../aztec3/circuits/abis/call_stack_item.hpp | 16 ++-- .../abis/contract_deployment_data.hpp | 8 +- .../aztec3/circuits/abis/function_data.hpp | 2 - .../circuits/abis/function_leaf_preimage.hpp | 6 +- .../circuits/abis/membership_witness.hpp | 4 +- .../abis/optionally_revealed_data.hpp | 12 +-- .../abis/private_circuit_public_inputs.hpp | 29 ++++---- .../abis/private_kernel/accumulated_data.hpp | 26 ++++--- .../abis/private_kernel/constant_data.hpp | 4 +- .../circuits/abis/private_kernel/globals.hpp | 2 +- .../abis/private_kernel/new_contract_data.hpp | 6 +- .../abis/private_kernel/old_tree_roots.hpp | 8 +- .../private_kernel/previous_kernel_data.hpp | 6 +- .../abis/private_kernel/private_call_data.hpp | 15 ++-- .../abis/private_kernel/private_inputs.hpp | 6 +- .../abis/private_kernel/public_inputs.hpp | 4 +- .../abis/public_circuit_public_inputs.hpp | 19 ++--- .../abis/rollup/constant_rollup_data.hpp | 14 ++-- .../abis/rollup/nullifier_leaf_preimage.hpp | 6 +- .../circuits/abis/signed_tx_request.hpp | 4 +- .../src/aztec3/circuits/abis/state_read.hpp | 6 +- .../aztec3/circuits/abis/state_transition.hpp | 8 +- .../src/aztec3/circuits/abis/tx_context.hpp | 4 +- .../src/aztec3/circuits/abis/tx_request.hpp | 18 ++--- .../apps/function_execution_context.hpp | 4 +- .../cpp/src/aztec3/circuits/apps/l1_call.hpp | 6 +- .../circuits/apps/l1_function_interface.hpp | 6 +- .../default_private_note/note_preimage.hpp | 1 - .../apps/state_vars/field_state_var.hpp | 2 +- .../apps/state_vars/state_var_base.hpp | 2 +- .../src/aztec3/circuits/apps/utxo_datum.hpp | 8 +- .../aztec3/circuits/kernel/private/utils.cpp | 74 +------------------ .../src/aztec3/circuits/rollup/base/utils.cpp | 36 +-------- circuits/cpp/src/aztec3/utils/array.hpp | 18 +++++ .../src/aztec3/utils/types/native_types.hpp | 3 - 37 files changed, 154 insertions(+), 250 deletions(-) diff --git a/circuits/cpp/src/aztec3/circuits/abis/append_only_tree_snapshot.hpp b/circuits/cpp/src/aztec3/circuits/abis/append_only_tree_snapshot.hpp index 34b66cfc495..2eaf8c8763b 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/append_only_tree_snapshot.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/append_only_tree_snapshot.hpp @@ -12,12 +12,10 @@ template struct AppendOnlyTreeSnapshot { typedef typename NCT::fr fr; typedef typename NCT::uint32 uint32; - fr root; + fr root = 0; uint32 next_available_leaf_index; bool operator==(AppendOnlyTreeSnapshot const&) const = default; - - static AppendOnlyTreeSnapshot empty() { return { 0, 0 }; }; }; template void read(uint8_t const*& it, AppendOnlyTreeSnapshot& obj) diff --git a/circuits/cpp/src/aztec3/circuits/abis/call_context.hpp b/circuits/cpp/src/aztec3/circuits/abis/call_context.hpp index 193eb7b07e2..ebfba426d73 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/call_context.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/call_context.hpp @@ -15,13 +15,12 @@ using aztec3::utils::types::NativeTypes; template struct CallContext { typedef typename NCT::address address; - typedef typename NCT::grumpkin_point grumpkin_point; typedef typename NCT::fr fr; typedef typename NCT::boolean boolean; - address msg_sender; - address storage_contract_address; - fr portal_contract_address; + address msg_sender = 0; + address storage_contract_address = 0; + fr portal_contract_address = 0; boolean is_delegate_call = false; boolean is_static_call = false; diff --git a/circuits/cpp/src/aztec3/circuits/abis/call_stack_item.hpp b/circuits/cpp/src/aztec3/circuits/abis/call_stack_item.hpp index 37d051e45eb..e1b77bd1eb5 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/call_stack_item.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/call_stack_item.hpp @@ -29,14 +29,14 @@ template struct CallStackItem { using PublicInputs = typename std:: conditional, PrivateCircuitPublicInputs>::type; - address - contract_address; // This is the _actual_ contract address relating to where this function's code resides in the - // contract tree. Regardless of whether this is a call or delegatecall, this - // `contract_address` _does not change_. Amongst other things, it's used as a lookup for - // getting the correct code from the tree. There is a separate `storage_contract_address` - // within a CallStackItem which varies depending on whether this is a call or delegatecall. - FunctionData function_data; - PublicInputs public_inputs; + // This is the _actual_ contract address relating to where this function's code resides in the + // contract tree. Regardless of whether this is a call or delegatecall, this + // `contract_address` _does not change_. Amongst other things, it's used as a lookup for + // getting the correct code from the tree. There is a separate `storage_contract_address` + // within a CallStackItem which varies depending on whether this is a call or delegatecall. + address contract_address = 0; + FunctionData function_data{}; + PublicInputs public_inputs{}; boolean operator==(CallContext const& other) const { diff --git a/circuits/cpp/src/aztec3/circuits/abis/contract_deployment_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/contract_deployment_data.hpp index 82a5f89740f..dd52a09065d 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/contract_deployment_data.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/contract_deployment_data.hpp @@ -18,10 +18,10 @@ template struct ContractDeploymentData { typedef typename NCT::fr fr; typedef typename NCT::boolean boolean; - fr constructor_vk_hash; - fr function_tree_root; - fr contract_address_salt; - address portal_contract_address; + fr constructor_vk_hash = 0; + fr function_tree_root = 0; + fr contract_address_salt = 0; + address portal_contract_address = 0; boolean operator==(ContractDeploymentData const& other) const { diff --git a/circuits/cpp/src/aztec3/circuits/abis/function_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/function_data.hpp index 0fbf6558aad..66d2a84f396 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/function_data.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/function_data.hpp @@ -12,10 +12,8 @@ using aztec3::utils::types::NativeTypes; using std::is_same; template struct FunctionData { - // typedef typename NCT::address address; typedef typename NCT::uint32 uint32; typedef typename NCT::boolean boolean; - // typedef typename NCT::grumpkin_point grumpkin_point; typedef typename NCT::fr fr; uint32 function_selector; // e.g. 1st 4-bytes of abi-encoding of function. diff --git a/circuits/cpp/src/aztec3/circuits/abis/function_leaf_preimage.hpp b/circuits/cpp/src/aztec3/circuits/abis/function_leaf_preimage.hpp index ac4292ee01f..1963518c773 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/function_leaf_preimage.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/function_leaf_preimage.hpp @@ -30,10 +30,10 @@ template struct FunctionLeafPreimage { typedef typename NCT::boolean boolean; typedef typename NCT::fr fr; - fr function_selector; + fr function_selector = 0; boolean is_private = false; - fr vk_hash; - fr acir_hash; + fr vk_hash = 0; + fr acir_hash = 0; boolean operator==(FunctionLeafPreimage const& other) const { diff --git a/circuits/cpp/src/aztec3/circuits/abis/membership_witness.hpp b/circuits/cpp/src/aztec3/circuits/abis/membership_witness.hpp index 7083b400aa5..22be93ee2e8 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/membership_witness.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/membership_witness.hpp @@ -1,9 +1,11 @@ #pragma once +#include #include "aztec3/utils/types/circuit_types.hpp" #include "aztec3/utils/types/convert.hpp" namespace aztec3::circuits::abis { +using aztec3::utils::zero_array; using aztec3::utils::types::CircuitTypes; using aztec3::utils::types::NativeTypes; using std::is_same; @@ -15,7 +17,7 @@ template struct MembershipWitness { typedef typename NCT::boolean boolean; uint32 leaf_index; - std::array sibling_path = { 0 }; + std::array sibling_path = zero_array(); boolean operator==(MembershipWitness const& other) const { diff --git a/circuits/cpp/src/aztec3/circuits/abis/optionally_revealed_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/optionally_revealed_data.hpp index c80ec60c5c6..c86f936b44e 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/optionally_revealed_data.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/optionally_revealed_data.hpp @@ -1,11 +1,13 @@ #pragma once #include "function_data.hpp" #include +#include #include #include #include namespace aztec3::circuits::abis { +using aztec3::utils::zero_array; using aztec3::utils::types::CircuitTypes; using aztec3::utils::types::NativeTypes; @@ -14,11 +16,11 @@ template struct OptionallyRevealedData { typedef typename NCT::boolean boolean; typedef typename NCT::fr fr; - fr call_stack_item_hash; - FunctionData function_data = FunctionData(); - std::array emitted_events = { 0 }; - fr vk_hash; - address portal_contract_address; + fr call_stack_item_hash = 0; + FunctionData function_data{}; + std::array emitted_events = zero_array(); + fr vk_hash = 0; + address portal_contract_address = 0; boolean pay_fee_from_l1 = false; boolean pay_fee_from_public_l2 = false; boolean called_from_l1 = false; diff --git a/circuits/cpp/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp index d1ecbe9190b..1c3e287bc4e 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp @@ -8,40 +8,41 @@ #include #include #include +#include #include #include #include namespace aztec3::circuits::abis { +using aztec3::utils::zero_array; using aztec3::utils::types::CircuitTypes; using aztec3::utils::types::NativeTypes; -using plonk::stdlib::witness_t; template class PrivateCircuitPublicInputs { typedef typename NCT::fr fr; typedef typename NCT::boolean boolean; public: - CallContext call_context = CallContext(); + CallContext call_context{}; - std::array args = { 0 }; - std::array return_values = { 0 }; + std::array args = zero_array(); + std::array return_values = zero_array(); - std::array emitted_events = { 0 }; + std::array emitted_events = zero_array(); - std::array new_commitments = { 0 }; - std::array new_nullifiers = { 0 }; + std::array new_commitments = zero_array(); + std::array new_nullifiers = zero_array(); - std::array private_call_stack = { 0 }; - std::array public_call_stack = { 0 }; - std::array l1_msg_stack = { 0 }; + std::array private_call_stack = zero_array(); + std::array public_call_stack = zero_array(); + std::array l1_msg_stack = zero_array(); - fr historic_private_data_tree_root; - fr historic_nullifier_tree_root; - fr historic_contract_tree_root; + fr historic_private_data_tree_root = 0; + fr historic_nullifier_tree_root = 0; + fr historic_contract_tree_root = 0; - ContractDeploymentData contract_deployment_data = ContractDeploymentData(); + ContractDeploymentData contract_deployment_data{}; boolean operator==(PrivateCircuitPublicInputs const& other) const { diff --git a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/accumulated_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/accumulated_data.hpp index 3447d44f7e5..f089eb98cc8 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/accumulated_data.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/accumulated_data.hpp @@ -1,18 +1,20 @@ #pragma once #include "../optionally_revealed_data.hpp" #include "aztec3/circuits/abis/private_kernel/new_contract_data.hpp" +#include "aztec3/constants.hpp" #include #include #include +#include #include #include #include namespace aztec3::circuits::abis::private_kernel { +using aztec3::utils::zero_array; using aztec3::utils::types::CircuitTypes; using aztec3::utils::types::NativeTypes; -using plonk::stdlib::witness_t; using std::is_same; template struct AccumulatedData { @@ -20,22 +22,22 @@ template struct AccumulatedData { typedef typename NCT::boolean boolean; typedef typename NCT::AggregationObject AggregationObject; - AggregationObject aggregation_object; + AggregationObject aggregation_object{}; - fr private_call_count; + fr private_call_count = 0; - std::array new_commitments = { 0 }; - std::array new_nullifiers = { 0 }; + std::array new_commitments = zero_array(); + std::array new_nullifiers = zero_array(); - std::array private_call_stack = { 0 }; - std::array public_call_stack = { 0 }; - std::array l1_msg_stack = { 0 }; + std::array private_call_stack = + zero_array(); + std::array public_call_stack = + zero_array(); + std::array l1_msg_stack = zero_array(); - std::array, KERNEL_NEW_CONTRACTS_LENGTH> new_contracts = { NewContractData() }; + std::array, KERNEL_NEW_CONTRACTS_LENGTH> new_contracts{}; - std::array, KERNEL_OPTIONALLY_REVEALED_DATA_LENGTH> optionally_revealed_data = { - OptionallyRevealedData() - }; + std::array, KERNEL_OPTIONALLY_REVEALED_DATA_LENGTH> optionally_revealed_data{}; boolean operator==(AccumulatedData const& other) const { diff --git a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/constant_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/constant_data.hpp index 77d7739b629..7728739ea4e 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/constant_data.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/constant_data.hpp @@ -19,8 +19,8 @@ template struct ConstantData { typedef typename NCT::fr fr; typedef typename NCT::boolean boolean; - OldTreeRoots old_tree_roots; - TxContext tx_context; + OldTreeRoots old_tree_roots{}; + TxContext tx_context{}; boolean operator==(ConstantData const& other) const { diff --git a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/globals.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/globals.hpp index 4e8fd7252ce..fb4b4bdd486 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/globals.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/globals.hpp @@ -14,7 +14,7 @@ template struct Globals { typedef typename NCT::fr fr; typedef typename NCT::boolean boolean; - fr min_timestamp; + fr min_timestamp = 0; boolean operator==(Globals const& other) const { return min_timestamp == other.min_timestamp; }; diff --git a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/new_contract_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/new_contract_data.hpp index 809387ed1c6..eb9ba995ce9 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/new_contract_data.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/new_contract_data.hpp @@ -16,9 +16,9 @@ template struct NewContractData { typedef typename NCT::fr fr; typedef typename NCT::boolean boolean; - address contract_address; - address portal_contract_address; - fr function_tree_root; + address contract_address = 0; + address portal_contract_address = 0; + fr function_tree_root = 0; boolean operator==(NewContractData const& other) const { diff --git a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/old_tree_roots.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/old_tree_roots.hpp index eea3409deb7..9d2715738ce 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/old_tree_roots.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/old_tree_roots.hpp @@ -15,10 +15,10 @@ template struct OldTreeRoots { typedef typename NCT::fr fr; typedef typename NCT::boolean boolean; - fr private_data_tree_root; - fr nullifier_tree_root; - fr contract_tree_root; - fr private_kernel_vk_tree_root; // TODO: future enhancement + fr private_data_tree_root = 0; + fr nullifier_tree_root = 0; + fr contract_tree_root = 0; + fr private_kernel_vk_tree_root = 0; // TODO: future enhancement boolean operator==(OldTreeRoots const& other) const { diff --git a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp index d031abfdb83..74fce6048f7 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/previous_kernel_data.hpp @@ -20,14 +20,14 @@ template struct PreviousKernelData { typedef typename NCT::VK VK; typedef typename NCT::uint32 uint32; - PublicInputs public_inputs; // TODO: not needed as already contained in proof? - NativeTypes::Proof proof; // TODO: how to express proof as native/circuit type when it gets used as a buffer? + PublicInputs public_inputs{}; // TODO: not needed as already contained in proof? + NativeTypes::Proof proof{}; // TODO: how to express proof as native/circuit type when it gets used as a buffer? std::shared_ptr vk; // TODO: this index and path are meant to be those of a leaf within the tree of _kernel circuit_ vks; not the tree // of functions within the contract tree. uint32 vk_index; - std::array vk_path = { 0 }; + std::array vk_path = zero_array(); boolean operator==(PreviousKernelData const& other) const { diff --git a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/private_call_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/private_call_data.hpp index 36cb9595600..37dcbe58a3e 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/private_call_data.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/private_call_data.hpp @@ -1,6 +1,7 @@ #pragma once #include "aztec3/constants.hpp" +#include "aztec3/utils/array.hpp" #include "call_context_reconciliation_data.hpp" #include "../call_stack_item.hpp" #include "../membership_witness.hpp" @@ -24,20 +25,20 @@ template struct PrivateCallData { typedef typename NCT::boolean boolean; typedef typename NCT::VK VK; - CallStackItem call_stack_item; + CallStackItem call_stack_item{}; - std::array, PRIVATE_CALL_STACK_LENGTH> private_call_stack_preimages; + std::array, PRIVATE_CALL_STACK_LENGTH> private_call_stack_preimages{}; // std::array, PUBLIC_CALL_STACK_LENGTH> public_call_stack_preimages; - NativeTypes::Proof proof; // TODO: how to express proof as native/circuit type when it gets used as a buffer? + NativeTypes::Proof proof{}; // TODO: how to express proof as native/circuit type when it gets used as a buffer? std::shared_ptr vk; - MembershipWitness function_leaf_membership_witness; - MembershipWitness contract_leaf_membership_witness; + MembershipWitness function_leaf_membership_witness{}; + MembershipWitness contract_leaf_membership_witness{}; - fr portal_contract_address; // an ETH address - fr acir_hash; + fr portal_contract_address = 0; // an ETH address + fr acir_hash = 0; boolean operator==(PrivateCallData const& other) const { diff --git a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/private_inputs.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/private_inputs.hpp index 9d55a69300e..e5fa856686b 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/private_inputs.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/private_inputs.hpp @@ -20,9 +20,9 @@ template struct PrivateInputs { typedef typename NCT::fr fr; typedef typename NCT::boolean boolean; - SignedTxRequest signed_tx_request = SignedTxRequest(); - PreviousKernelData previous_kernel = PreviousKernelData(); - PrivateCallData private_call = PrivateCallData(); + SignedTxRequest signed_tx_request{}; + PreviousKernelData previous_kernel{}; + PrivateCallData private_call{}; boolean operator==(PublicInputs const& other) const { diff --git a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/public_inputs.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/public_inputs.hpp index 42df468e415..7006f493491 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/public_inputs.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/public_inputs.hpp @@ -17,8 +17,8 @@ template struct PublicInputs { typedef typename NCT::fr fr; typedef typename NCT::boolean boolean; - AccumulatedData end = AccumulatedData(); - ConstantData constants = ConstantData(); + AccumulatedData end{}; + ConstantData constants{}; boolean is_private = true; // TODO: might need to instantiate from witness! diff --git a/circuits/cpp/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp b/circuits/cpp/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp index 62b651a3e39..0e58caca152 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/public_circuit_public_inputs.hpp @@ -7,32 +7,33 @@ #include #include +#include #include #include namespace aztec3::circuits::abis { +using aztec3::utils::zero_array; using aztec3::utils::types::CircuitTypes; using aztec3::utils::types::NativeTypes; -using plonk::stdlib::witness_t; template struct PublicCircuitPublicInputs { typedef typename NCT::fr fr; typedef typename NCT::boolean boolean; typedef typename NCT::address address; - CallContext call_context = CallContext(); + CallContext call_context{}; - std::array args = { 0 }; - std::array return_values = { 0 }; + std::array args = zero_array(); + std::array return_values = zero_array(); - std::array emitted_events = { 0 }; + std::array emitted_events = zero_array(); - std::array, STATE_TRANSITIONS_LENGTH> state_transitions = StateTransition(); - std::array, STATE_READS_LENGTH> state_reads = StateRead(); + std::array, STATE_TRANSITIONS_LENGTH> state_transitions{}; + std::array, STATE_READS_LENGTH> state_reads{}; - std::array public_call_stack = { 0 }; - std::array l1_msg_stack = { 0 }; + std::array public_call_stack = zero_array(); + std::array l1_msg_stack = zero_array(); fr historic_private_data_tree_root; diff --git a/circuits/cpp/src/aztec3/circuits/abis/rollup/constant_rollup_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/rollup/constant_rollup_data.hpp index 7d0b7077be4..4f1f1ef5322 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/rollup/constant_rollup_data.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/rollup/constant_rollup_data.hpp @@ -12,15 +12,15 @@ template struct ConstantRollupData { typedef typename NCT::fr fr; // The very latest roots as at the very beginning of the entire rollup: - AppendOnlyTreeSnapshot start_tree_of_historic_private_data_tree_roots_snapshot; - AppendOnlyTreeSnapshot start_tree_of_historic_contract_tree_roots_snapshot; - AppendOnlyTreeSnapshot tree_of_historic_l1_to_l2_msg_tree_roots_snapshot; + AppendOnlyTreeSnapshot start_tree_of_historic_private_data_tree_roots_snapshot{}; + AppendOnlyTreeSnapshot start_tree_of_historic_contract_tree_roots_snapshot{}; + AppendOnlyTreeSnapshot tree_of_historic_l1_to_l2_msg_tree_roots_snapshot{}; // Some members of this struct tbd: - fr private_kernel_vk_tree_root; - fr public_kernel_vk_tree_root; - fr base_rollup_vk_hash; - fr merge_rollup_vk_hash; + fr private_kernel_vk_tree_root = 0; + fr public_kernel_vk_tree_root = 0; + fr base_rollup_vk_hash = 0; + fr merge_rollup_vk_hash = 0; bool operator==(ConstantRollupData const&) const = default; }; diff --git a/circuits/cpp/src/aztec3/circuits/abis/rollup/nullifier_leaf_preimage.hpp b/circuits/cpp/src/aztec3/circuits/abis/rollup/nullifier_leaf_preimage.hpp index d30123c2c6b..35dc3f1ceba 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/rollup/nullifier_leaf_preimage.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/rollup/nullifier_leaf_preimage.hpp @@ -14,14 +14,12 @@ template struct NullifierLeafPreimage { typedef typename NCT::fr fr; typedef typename NCT::uint32 uint32; - fr leaf_value; + fr leaf_value = 0; uint32 next_index; - fr next_value; + fr next_value = 0; bool operator==(NullifierLeafPreimage const&) const = default; - static NullifierLeafPreimage empty() { return { 0, 0, 0 }; }; - fr hash() const { return stdlib::merkle_tree::hash_multiple_native({ leaf_value, next_index, next_value }); } }; diff --git a/circuits/cpp/src/aztec3/circuits/abis/signed_tx_request.hpp b/circuits/cpp/src/aztec3/circuits/abis/signed_tx_request.hpp index a721d0a38d6..87f2edd606d 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/signed_tx_request.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/signed_tx_request.hpp @@ -16,8 +16,8 @@ template struct SignedTxRequest { typedef typename NCT::boolean boolean; typedef typename NCT::ecdsa_signature Signature; - TxRequest tx_request = TxRequest(); - Signature signature = Signature(); + TxRequest tx_request{}; + Signature signature{}; boolean operator==(SignedTxRequest const& other) const { diff --git a/circuits/cpp/src/aztec3/circuits/abis/state_read.hpp b/circuits/cpp/src/aztec3/circuits/abis/state_read.hpp index de45f65cc09..8c9bd74b5d5 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/state_read.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/state_read.hpp @@ -13,13 +13,11 @@ using plonk::stdlib::witness_t; template struct StateRead { typedef typename NCT::fr fr; - fr storage_slot; - fr current_value; + fr storage_slot = 0; + fr current_value = 0; bool operator==(StateRead const&) const = default; - static StateRead empty() { return { 0, 0 }; }; - template StateRead> to_circuit_type(Composer& composer) const { static_assert((std::is_same::value)); diff --git a/circuits/cpp/src/aztec3/circuits/abis/state_transition.hpp b/circuits/cpp/src/aztec3/circuits/abis/state_transition.hpp index 410e547ac19..576fe719d3e 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/state_transition.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/state_transition.hpp @@ -13,14 +13,12 @@ using plonk::stdlib::witness_t; template struct StateTransition { typedef typename NCT::fr fr; - fr storage_slot; - fr old_value; - fr new_value; + fr storage_slot = 0; + fr old_value = 0; + fr new_value = 0; bool operator==(StateTransition const&) const = default; - static StateTransition empty() { return { 0, 0, 0 }; }; - template StateTransition> to_circuit_type(Composer& composer) const { static_assert((std::is_same::value)); diff --git a/circuits/cpp/src/aztec3/circuits/abis/tx_context.hpp b/circuits/cpp/src/aztec3/circuits/abis/tx_context.hpp index 359fae76370..0283cfda2de 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/tx_context.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/tx_context.hpp @@ -12,11 +12,9 @@ namespace aztec3::circuits::abis { using aztec3::utils::types::CircuitTypes; using aztec3::utils::types::NativeTypes; -using plonk::stdlib::witness_t; template struct TxContext { typedef typename NCT::address address; - // typedef typename NCT::grumpkin_point grumpkin_point; typedef typename NCT::fr fr; typedef typename NCT::boolean boolean; @@ -24,7 +22,7 @@ template struct TxContext { boolean is_rebate_payment_tx = false; boolean is_contract_deployment_tx = false; - ContractDeploymentData contract_deployment_data = ContractDeploymentData(); + ContractDeploymentData contract_deployment_data{}; boolean operator==(TxContext const& other) const { diff --git a/circuits/cpp/src/aztec3/circuits/abis/tx_request.hpp b/circuits/cpp/src/aztec3/circuits/abis/tx_request.hpp index 1472a7bb7d1..17adfad3eba 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/tx_request.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/tx_request.hpp @@ -2,29 +2,29 @@ #include "function_data.hpp" #include "tx_context.hpp" #include +#include #include #include #include namespace aztec3::circuits::abis { +using aztec3::utils::zero_array; using aztec3::utils::types::CircuitTypes; using aztec3::utils::types::NativeTypes; -using plonk::stdlib::witness_t; template struct TxRequest { typedef typename NCT::address address; - // typedef typename NCT::grumpkin_point grumpkin_point; typedef typename NCT::fr fr; typedef typename NCT::boolean boolean; - address from; - address to; - FunctionData function_data = FunctionData(); - std::array args = { 0 }; - fr nonce; - TxContext tx_context = TxContext(); - fr chain_id; + address from = 0; + address to = 0; + FunctionData function_data{}; + std::array args = zero_array(); + fr nonce = 0; + TxContext tx_context{}; + fr chain_id = 0; boolean operator==(TxContext const& other) const { diff --git a/circuits/cpp/src/aztec3/circuits/apps/function_execution_context.hpp b/circuits/cpp/src/aztec3/circuits/apps/function_execution_context.hpp index 555f73b1e55..26413df1a19 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/function_execution_context.hpp +++ b/circuits/cpp/src/aztec3/circuits/apps/function_execution_context.hpp @@ -58,7 +58,7 @@ template class FunctionExecutionContext { nested_private_call_exec_ctxs; // TODO: make this private! - OptionalPrivateCircuitPublicInputs private_circuit_public_inputs; + OptionalPrivateCircuitPublicInputs private_circuit_public_inputs{}; private: std::vector>> new_notes; @@ -68,7 +68,7 @@ template class FunctionExecutionContext { std::vector>> nullified_notes; std::vector new_nullifiers; - PrivateCircuitPublicInputs final_private_circuit_public_inputs; + PrivateCircuitPublicInputs final_private_circuit_public_inputs{}; bool is_finalised = false; diff --git a/circuits/cpp/src/aztec3/circuits/apps/l1_call.hpp b/circuits/cpp/src/aztec3/circuits/apps/l1_call.hpp index e7f22fbcdd1..97e6bd5f693 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/l1_call.hpp +++ b/circuits/cpp/src/aztec3/circuits/apps/l1_call.hpp @@ -19,8 +19,8 @@ template class L1Call { public: L1FunctionInterface& l1_function; std::vector args; - fr hash_of_argument_encodings; - fr partial_l1_call_stack_item; // keccak(function_selector, hash_of_argument_encodings) + fr hash_of_argument_encodings = 0; + fr partial_l1_call_stack_item = 0; // keccak(function_selector, hash_of_argument_encodings) L1Call(L1FunctionInterface const& l1_function, std::vector const& args) : l1_function(l1_function) @@ -37,8 +37,6 @@ template class L1Call { bool operator==(L1Call const&) const = default; - // static L1Call empty() { return { 0, 0, 0, 0, 0 }; }; - template L1Call> to_circuit_type(Composer& composer) const { static_assert((std::is_same::value)); diff --git a/circuits/cpp/src/aztec3/circuits/apps/l1_function_interface.hpp b/circuits/cpp/src/aztec3/circuits/apps/l1_function_interface.hpp index 70c665dcc1f..b3a9ef6a7e3 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/l1_function_interface.hpp +++ b/circuits/cpp/src/aztec3/circuits/apps/l1_function_interface.hpp @@ -17,7 +17,7 @@ template struct L1FunctionInterfaceStruct { typedef typename NCT::fr fr; std::string function_name; - fr function_selector; + fr function_selector = 0; size_t num_params = 0; }; @@ -27,8 +27,8 @@ template class L1FunctionInterface { public: Contract* contract; std::string function_name; - fr function_selector; - size_t num_params; + fr function_selector = 0; + size_t num_params = 0; L1FunctionInterface(){}; diff --git a/circuits/cpp/src/aztec3/circuits/apps/notes/default_private_note/note_preimage.hpp b/circuits/cpp/src/aztec3/circuits/apps/notes/default_private_note/note_preimage.hpp index fb01629bf70..a74fe5a4390 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/notes/default_private_note/note_preimage.hpp +++ b/circuits/cpp/src/aztec3/circuits/apps/notes/default_private_note/note_preimage.hpp @@ -17,7 +17,6 @@ using crypto::generators::generator_index_t; template struct DefaultPrivateNotePreimage { typedef typename NCT::fr fr; - typedef typename NCT::grumpkin_point grumpkin_point; typedef typename NCT::address address; typedef typename NCT::boolean boolean; diff --git a/circuits/cpp/src/aztec3/circuits/apps/state_vars/field_state_var.hpp b/circuits/cpp/src/aztec3/circuits/apps/state_vars/field_state_var.hpp index 37bdf9bfc54..f16a5315262 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/state_vars/field_state_var.hpp +++ b/circuits/cpp/src/aztec3/circuits/apps/state_vars/field_state_var.hpp @@ -19,7 +19,7 @@ template class FieldStateVar : public StateVar { typedef typename CT::fr fr; typedef typename CT::grumpkin_point grumpkin_point; - fr value; + fr value = 0; FieldStateVar& operator=(fr&& other) { diff --git a/circuits/cpp/src/aztec3/circuits/apps/state_vars/state_var_base.hpp b/circuits/cpp/src/aztec3/circuits/apps/state_vars/state_var_base.hpp index 2c425b3b563..bcf10f7dbe9 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/state_vars/state_var_base.hpp +++ b/circuits/cpp/src/aztec3/circuits/apps/state_vars/state_var_base.hpp @@ -37,7 +37,7 @@ template class StateVar { // based on the ordering of declarations of the _names_ of states. For container types (mappings/arrays/structs), // the state variable might be able to access multiple storage slots. The start slot is the 'starting point' for // deriving such slots. - fr start_slot; + fr start_slot = 0; // The 'storage slot point' of the state variable. Having a _point_ for every storage slot allows for // partial-commitment functionality. diff --git a/circuits/cpp/src/aztec3/circuits/apps/utxo_datum.hpp b/circuits/cpp/src/aztec3/circuits/apps/utxo_datum.hpp index dd2ce3526b7..eb5c07b3106 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/utxo_datum.hpp +++ b/circuits/cpp/src/aztec3/circuits/apps/utxo_datum.hpp @@ -19,13 +19,13 @@ template struct UTXOSLoadDatum { typedef typename NCT::address address; typedef typename NCT::uint32 uint32; - fr commitment; - address contract_address; - NotePreimage preimage; + fr commitment = 0; + address contract_address = 0; + NotePreimage preimage{}; std::vector sibling_path; uint32 leaf_index; - fr historic_private_data_tree_root; + fr historic_private_data_tree_root = 0; template auto to_circuit_type(Composer& composer) const { diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/utils.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/utils.cpp index b44a72b70ee..65e2814ae48 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/utils.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/utils.cpp @@ -7,88 +7,16 @@ namespace { using NT = aztec3::utils::types::NativeTypes; using AggregationObject = aztec3::utils::types::NativeTypes::AggregationObject; -using aztec3::circuits::abis::FunctionData; -using aztec3::circuits::abis::OptionallyRevealedData; -using aztec3::circuits::abis::TxContext; -using aztec3::circuits::abis::private_kernel::AccumulatedData; -using aztec3::circuits::abis::private_kernel::NewContractData; -using aztec3::circuits::abis::private_kernel::OldTreeRoots; using aztec3::circuits::abis::private_kernel::PreviousKernelData; -using aztec3::circuits::abis::private_kernel::PublicInputs; using aztec3::circuits::mock::mock_kernel_circuit; -using plonk::TurboComposer; } // namespace namespace aztec3::circuits::kernel::private_kernel::utils { -PreviousKernelData very_empty_previous_kernel() -{ - - std::array, KERNEL_NEW_CONTRACTS_LENGTH> new_contracts; - new_contracts.fill(NewContractData{ - .contract_address = fr::zero(), .portal_contract_address = fr::zero(), .function_tree_root = fr::zero() }); - - std::array, KERNEL_OPTIONALLY_REVEALED_DATA_LENGTH> optionally_revealed_data; - - optionally_revealed_data.fill(OptionallyRevealedData{ .call_stack_item_hash = fr::zero(), - .function_data = FunctionData(), - .emitted_events = { 0 }, - .vk_hash = fr::zero(), - .portal_contract_address = { 0 }, - .pay_fee_from_l1 = false, - .pay_fee_from_public_l2 = false, - .called_from_l1 = false, - .called_from_public_l2 = false }); - - AccumulatedData accumulated_data = { - .aggregation_object = AggregationObject{}, // TODO initialize members to 0 - .private_call_count = fr::zero(), - .new_commitments = { 0 }, - .new_nullifiers = { 0 }, - .private_call_stack = { 0 }, - .public_call_stack = { 0 }, - .l1_msg_stack = { 0 }, - .new_contracts = new_contracts, - .optionally_revealed_data = optionally_revealed_data, - }; - - OldTreeRoots old_tree_roots = { - .private_data_tree_root = fr::zero(), - .nullifier_tree_root = fr::zero(), - .contract_tree_root = fr::zero(), - .private_kernel_vk_tree_root = fr::zero(), - }; - - TxContext tx_context = { - .is_fee_payment_tx = false, - .is_rebate_payment_tx = false, - .is_contract_deployment_tx = false, - .contract_deployment_data = { - .constructor_vk_hash = fr::zero(), - .function_tree_root = fr::zero(), - .contract_address_salt = fr::zero(), - .portal_contract_address = fr::zero(), - }, - }; - - PublicInputs kernel_public_inputs = { - .end = accumulated_data, - .constants = { .old_tree_roots = old_tree_roots, .tx_context = tx_context }, - .is_private = true, - }; - - PreviousKernelData kernel_data = { - .public_inputs = kernel_public_inputs, - }; - - return kernel_data; -} - PreviousKernelData dummy_previous_kernel_with_vk_proof() { - // TODO confirm this is the right way to initialize struct of 0s - auto init_previous_kernel = very_empty_previous_kernel(); + PreviousKernelData init_previous_kernel{}; auto crs_factory = std::make_shared(); Composer mock_kernel_composer = Composer(crs_factory); diff --git a/circuits/cpp/src/aztec3/circuits/rollup/base/utils.cpp b/circuits/cpp/src/aztec3/circuits/rollup/base/utils.cpp index b97b6e22500..d4a0da2689a 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/base/utils.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/base/utils.cpp @@ -13,16 +13,12 @@ using NT = aztec3::utils::types::NativeTypes; using AggregationObject = aztec3::utils::types::NativeTypes::AggregationObject; using aztec3::circuits::abis::AppendOnlyTreeSnapshot; -using aztec3::circuits::abis::BaseOrMergeRollupPublicInputs; using aztec3::circuits::abis::BaseRollupInputs; using aztec3::circuits::abis::ConstantRollupData; using aztec3::circuits::abis::MembershipWitness; using aztec3::circuits::abis::NullifierLeafPreimage; -using aztec3::circuits::abis::private_kernel::NewContractData; using aztec3::circuits::kernel::private_kernel::utils::dummy_previous_kernel_with_vk_proof; - -using plonk::TurboComposer; } // namespace namespace aztec3::circuits::rollup::base::utils { @@ -39,25 +35,7 @@ BaseRollupInputs dummy_base_rollup_inputs_with_vk_proof() .root = native_base_rollup::MerkleTree(CONTRACT_TREE_ROOTS_TREE_HEIGHT).root(), .next_available_leaf_index = 0, }; - - std::array, 2 * KERNEL_NEW_NULLIFIERS_LENGTH> low_nullifier_leaf_preimages; - std::array, 2 * KERNEL_NEW_NULLIFIERS_LENGTH> - low_nullifier_membership_witness; - - for (size_t i = 0; i < 2 * KERNEL_NEW_NULLIFIERS_LENGTH; ++i) { - low_nullifier_leaf_preimages[i] = NullifierLeafPreimage(); - low_nullifier_membership_witness[i] = MembershipWitness(); - } - - std::array, 2> - historic_private_data_tree_root_membership_witnesses = { - MembershipWitness(), - MembershipWitness() - }; - - std::array, 2> - historic_contract_tree_root_membership_witnesses = { MembershipWitness(), - MembershipWitness() }; + // constantRollupData.tree_of_historic_l1_to_l2_msg_tree_roots_snapshot = // Kernels std::array, 2> kernel_data; @@ -70,20 +48,11 @@ BaseRollupInputs dummy_base_rollup_inputs_with_vk_proof() .root = native_base_rollup::MerkleTree(PRIVATE_DATA_TREE_HEIGHT).root(), .next_available_leaf_index = 0, }, - .start_nullifier_tree_snapshot = AppendOnlyTreeSnapshot(), + //.start_nullifier_tree_snapshot = .start_contract_tree_snapshot = { .root = native_base_rollup::MerkleTree(CONTRACT_TREE_HEIGHT).root(), .next_available_leaf_index = 0, }, - .low_nullifier_leaf_preimages = low_nullifier_leaf_preimages, - .low_nullifier_membership_witness = low_nullifier_membership_witness, - .new_commitments_subtree_sibling_path = { 0 }, - .new_nullifiers_subtree_sibling_path = { 0 }, - .new_contracts_subtree_sibling_path = { 0 }, - .historic_private_data_tree_root_membership_witnesses = - historic_private_data_tree_root_membership_witnesses, - .historic_contract_tree_root_membership_witnesses = - historic_contract_tree_root_membership_witnesses, .constants = constantRollupData }; return baseRollupInputs; @@ -172,7 +141,6 @@ generate_nullifier_tree_testing_values(BaseRollupInputs rollupInputs, const size_t NUMBER_OF_NULLIFIERS = KERNEL_NEW_NULLIFIERS_LENGTH * 2; std::array, NUMBER_OF_NULLIFIERS> new_nullifier_leaves; - std::array, NUMBER_OF_NULLIFIERS> low_nullifier_leaves_preimages; std::array, NUMBER_OF_NULLIFIERS> low_nullifier_leaves_preimages_witnesses; diff --git a/circuits/cpp/src/aztec3/utils/array.hpp b/circuits/cpp/src/aztec3/utils/array.hpp index dabb20b202a..bf7a2e1aec9 100644 --- a/circuits/cpp/src/aztec3/utils/array.hpp +++ b/circuits/cpp/src/aztec3/utils/array.hpp @@ -1,3 +1,4 @@ +#pragma once #include "./types/native_types.hpp" #include "barretenberg/common/throw_or_abort.hpp" @@ -8,6 +9,23 @@ namespace aztec3::utils { using NT = types::NativeTypes; +/** + * @brief Creates an array of zeros. + * + * @details This is necessary when a type (like fr) has a default constructor + * that doesn't initialize members to zero. + * + * @tparam ELEMS_TYPE array element type + * @tparam ARRAY_LEN + * @return std::array the zero-initialized array + */ +template std::array zero_array() +{ + std::array arr; + arr.fill(ELEMS_TYPE(0)); // Assumes that integer type can be used here in initialization + return arr; +} + /** * Gets the number of contiguous nonzero values of an array from the start. * Note: This assumes `0` always means 'not used', so be careful. As soon as we locate 0, we stop the counting. diff --git a/circuits/cpp/src/aztec3/utils/types/native_types.hpp b/circuits/cpp/src/aztec3/utils/types/native_types.hpp index 3abb1dcf432..1f7dc0788d3 100644 --- a/circuits/cpp/src/aztec3/utils/types/native_types.hpp +++ b/circuits/cpp/src/aztec3/utils/types/native_types.hpp @@ -17,8 +17,6 @@ namespace aztec3::utils::types { -// using plonk::stdlib::address; - struct NativeTypes { typedef bool boolean; @@ -29,7 +27,6 @@ struct NativeTypes { typedef uint256_t uint256; typedef barretenberg::fr fr; - typedef barretenberg::fr safe_fr; typedef proof_system::plonk::stdlib::address address; typedef barretenberg::fq fq; From 61420897b1dfe7f101d08a9ea813e10bf3961e07 Mon Sep 17 00:00:00 2001 From: David Banks <47112877+dbanks12@users.noreply.github.com> Date: Thu, 13 Apr 2023 11:34:56 -0400 Subject: [PATCH 161/166] fix use turbo (#240) --- circuits/cpp/bootstrap.sh | 4 ++-- circuits/cpp/cmake/barretenberg.cmake | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/circuits/cpp/bootstrap.sh b/circuits/cpp/bootstrap.sh index 7a9bcb72975..a9f7fcb4a86 100755 --- a/circuits/cpp/bootstrap.sh +++ b/circuits/cpp/bootstrap.sh @@ -68,7 +68,7 @@ echo "# When running cmake directly, remember to use: --build --preset $PRESET" echo "#################################" # Build native. -cmake --preset $PRESET -DCMAKE_BUILD_TYPE=RelWithAssert -USE_TURBO=true +cmake --preset $PRESET -DCMAKE_BUILD_TYPE=RelWithAssert -DUSE_TURBO=true cmake --build --preset $PRESET ${@/#/--target } # Install the webassembly toolchain. @@ -77,5 +77,5 @@ if ! [ -d "./barretenberg/cpp/src/wasi-sdk-$WASI_VERSION.0" ] ; then fi # Build WASM. -cmake --preset wasm -USE_TURBO=true +cmake --preset wasm -DUSE_TURBO=true cmake --build --preset wasm diff --git a/circuits/cpp/cmake/barretenberg.cmake b/circuits/cpp/cmake/barretenberg.cmake index 5878804ddca..96516bfe35b 100644 --- a/circuits/cpp/cmake/barretenberg.cmake +++ b/circuits/cpp/cmake/barretenberg.cmake @@ -33,7 +33,7 @@ ExternalProject_Add(Barretenberg BUILD_ALWAYS TRUE UPDATE_COMMAND "" INSTALL_COMMAND "" - CONFIGURE_COMMAND ${CMAKE_COMMAND} --preset ${CMAKE_BBERG_PRESET} -DSERIALIZE_CANARY=${SERIALIZE_CANARY} -DENABLE_ASAN=${ENABLE_ASAN} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + CONFIGURE_COMMAND ${CMAKE_COMMAND} --preset ${CMAKE_BBERG_PRESET} -DSERIALIZE_CANARY=${SERIALIZE_CANARY} -DENABLE_ASAN=${ENABLE_ASAN} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DUSE_TURBO=${USE_TURBO} BUILD_COMMAND ${CMAKE_COMMAND} --build --preset ${CMAKE_BBERG_PRESET} ${BBERG_TARGETS} # byproducts needed by ninja generator (not needed by make) BUILD_BYPRODUCTS ${BBERG_BUILD_DIR}/lib/libbarretenberg.a ${BBERG_BUILD_DIR}/lib/libenv.a) From a0c1aed57515a17d1f475440bfe0f2b3aa6cac67 Mon Sep 17 00:00:00 2001 From: David Banks <47112877+dbanks12@users.noreply.github.com> Date: Thu, 13 Apr 2023 12:22:27 -0400 Subject: [PATCH 162/166] ci: use turbo in dockerfiles (#243) --- circuits/cpp/dockerfiles/Dockerfile.arm64-linux-gcc | 2 +- circuits/cpp/dockerfiles/Dockerfile.wasm-linux-clang | 2 +- circuits/cpp/dockerfiles/Dockerfile.wasm-linux-clang-assert | 2 +- circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-clang | 2 +- circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-clang-assert | 2 +- circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-gcc | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/circuits/cpp/dockerfiles/Dockerfile.arm64-linux-gcc b/circuits/cpp/dockerfiles/Dockerfile.arm64-linux-gcc index 0b1c7a338d0..8ba6d984ada 100644 --- a/circuits/cpp/dockerfiles/Dockerfile.arm64-linux-gcc +++ b/circuits/cpp/dockerfiles/Dockerfile.arm64-linux-gcc @@ -2,6 +2,6 @@ FROM aztecprotocol/crosstool-ng-arm64:latest WORKDIR /usr/src/aztec3-circuits/cpp COPY . . -RUN cmake --toolchain ./cmake/toolchains/aarch64-linux.cmake --preset gcc && cmake --build --preset gcc +RUN cmake --toolchain ./cmake/toolchains/aarch64-linux.cmake --preset gcc -DUSE_TURBO=true && cmake --build --preset gcc RUN cd build && for test in ./bin/*_tests; do qemu-aarch64 $test; done ENTRYPOINT /bin/bash \ No newline at end of file diff --git a/circuits/cpp/dockerfiles/Dockerfile.wasm-linux-clang b/circuits/cpp/dockerfiles/Dockerfile.wasm-linux-clang index c6783effe00..00325e48d10 100644 --- a/circuits/cpp/dockerfiles/Dockerfile.wasm-linux-clang +++ b/circuits/cpp/dockerfiles/Dockerfile.wasm-linux-clang @@ -4,7 +4,7 @@ WORKDIR /usr/src/aztec3-circuits/cpp/barretenberg/cpp/src RUN curl -s -L https://github.com/CraneStation/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-linux.tar.gz | tar zxfv - WORKDIR /usr/src/aztec3-circuits/cpp COPY . . -RUN cmake --preset wasm && cmake --build --preset wasm +RUN cmake --preset wasm -DUSE_TURBO=true && cmake --build --preset wasm FROM alpine:3.17 COPY --from=builder /usr/src/aztec3-circuits/cpp/build-wasm/bin/aztec3-circuits.wasm /usr/src/aztec3-circuits/cpp/build-wasm/bin/aztec3-circuits.wasm diff --git a/circuits/cpp/dockerfiles/Dockerfile.wasm-linux-clang-assert b/circuits/cpp/dockerfiles/Dockerfile.wasm-linux-clang-assert index abce9c5f8e1..f0ea18ebe4e 100644 --- a/circuits/cpp/dockerfiles/Dockerfile.wasm-linux-clang-assert +++ b/circuits/cpp/dockerfiles/Dockerfile.wasm-linux-clang-assert @@ -5,7 +5,7 @@ RUN curl -s -L https://github.com/CraneStation/wasi-sdk/releases/download/wasi-s WORKDIR /usr/src/aztec3-circuits/cpp COPY . . -RUN cmake --preset wasm && cmake --build --preset wasm +RUN cmake --preset wasm -DUSE_TURBO=true && cmake --build --preset wasm FROM ubuntu:kinetic RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y xz-utils curl diff --git a/circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-clang b/circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-clang index 98667a53a03..b2a11c56efa 100644 --- a/circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-clang +++ b/circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-clang @@ -15,7 +15,7 @@ WORKDIR /usr/src/aztec3-circuits/cpp COPY . . # Build the entire project, as we want to check everything builds under clang -RUN cmake --preset default && cmake --build --preset default +RUN cmake --preset default -DUSE_TURBO=true && cmake --build --preset default FROM alpine:3.17 RUN apk update && apk add openmp diff --git a/circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-clang-assert b/circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-clang-assert index 41d13318d49..95b212e04a2 100644 --- a/circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-clang-assert +++ b/circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-clang-assert @@ -15,7 +15,7 @@ WORKDIR /usr/src/aztec3-circuits/cpp COPY . . # Build everything to ensure everything builds. All tests will be run from the result of this build. -RUN cmake --preset default -DCMAKE_BUILD_TYPE=RelWithAssert -DCI=ON && cmake --build --preset default +RUN cmake --preset default -DCMAKE_BUILD_TYPE=RelWithAssert -DCI=ON -DUSE_TURBO=true && cmake --build --preset default FROM alpine:3.17 RUN apk update && apk add curl openmp diff --git a/circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-gcc b/circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-gcc index a8d343b1381..1e5d89e2583 100644 --- a/circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-gcc +++ b/circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-gcc @@ -10,7 +10,7 @@ RUN apk update \ WORKDIR /usr/src/aztec3-circuits/cpp COPY . . # Build the entire project, as we want to check everything builds under gcc. -RUN cmake --preset gcc -DCI=ON && cmake --build --preset gcc +RUN cmake --preset gcc -DCI=ON -DUSE_TURBO=true && cmake --build --preset gcc FROM alpine:3.17 RUN apk update && apk add libstdc++ libgomp From d76b0f3e455b5b679d35e2c4047db27df17f4867 Mon Sep 17 00:00:00 2001 From: David Banks <47112877+dbanks12@users.noreply.github.com> Date: Thu, 13 Apr 2023 15:32:52 -0400 Subject: [PATCH 163/166] feat: Kernel fix & test improvements/refactoring (#239) * fix bug in native kernel - contract logic was being skipped * zero-initialize all abi and kernel structs. helper function to zero-init arrays of frs * better struct initialization in app circuits files * dont need to do as much in base utils since structs are sanely zero-initialized * use fill to initialize array of fields to zero * fix native private kernel, refactor private kernel tests, add real logic in test setup for computing function/contract tree roots/siblings * new hash functions --- circuits/cpp/cmake/module.cmake | 8 +- .../basic_contract_deployment.cpp | 10 +- .../basic_contract_deployment.hpp | 4 +- .../circuits/apps/test_apps/escrow/.test.cpp | 2 +- .../apps/test_apps/escrow/deposit.cpp | 10 +- .../apps/test_apps/escrow/deposit.hpp | 4 +- circuits/cpp/src/aztec3/circuits/hash.hpp | 107 +- .../aztec3/circuits/kernel/private/.test.cpp | 1242 +++++------------ .../private/native_private_kernel_circuit.cpp | 64 +- 9 files changed, 509 insertions(+), 942 deletions(-) diff --git a/circuits/cpp/cmake/module.cmake b/circuits/cpp/cmake/module.cmake index 788b1127e72..f654774b779 100644 --- a/circuits/cpp/cmake/module.cmake +++ b/circuits/cpp/cmake/module.cmake @@ -113,7 +113,13 @@ function(barretenberg_module MODULE_NAME) WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) else() # Currently haven't found a way to easily wrap the calls in wasmtime when run from ctest. - gtest_discover_tests(${MODULE_NAME}_tests WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) + # Needed to add `TEST_DISCOVERY_TIMEOUT` to work around: + # ``` + # Error running test executable. + # ... + # Result: Process terminated due to timeout + # ``` + gtest_discover_tests(${MODULE_NAME}_tests WORKING_DIRECTORY ${CMAKE_BINARY_DIR} PROPERTIES TEST_DISCOVERY_TIMEOUT 600) endif() endif() diff --git a/circuits/cpp/src/aztec3/circuits/apps/test_apps/basic_contract_deployment/basic_contract_deployment.cpp b/circuits/cpp/src/aztec3/circuits/apps/test_apps/basic_contract_deployment/basic_contract_deployment.cpp index 76844774252..05bfaf1ff60 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/test_apps/basic_contract_deployment/basic_contract_deployment.cpp +++ b/circuits/cpp/src/aztec3/circuits/apps/test_apps/basic_contract_deployment/basic_contract_deployment.cpp @@ -9,9 +9,7 @@ namespace aztec3::circuits::apps::test_apps::basic_contract_deployment { using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; OptionalPrivateCircuitPublicInputs constructor(FunctionExecutionContext& exec_ctx, - NT::fr const& _arg0, - NT::fr const& _arg1, - NT::fr const& _arg2) + std::array const& args) { /**************************************************************** * PREAMBLE @@ -24,9 +22,9 @@ OptionalPrivateCircuitPublicInputs constructor(FunctionExecutionContext& exe // Convert params into circuit types: auto& composer = exec_ctx.composer; - CT::fr arg0 = to_ct(composer, _arg0); - CT::fr arg1 = to_ct(composer, _arg1); - CT::fr arg2 = to_ct(composer, _arg2); + CT::fr arg0 = to_ct(composer, args[0]); + CT::fr arg1 = to_ct(composer, args[1]); + CT::fr arg2 = to_ct(composer, args[2]); auto& oracle = exec_ctx.oracle; const CT::address msg_sender = oracle.get_msg_sender(); diff --git a/circuits/cpp/src/aztec3/circuits/apps/test_apps/basic_contract_deployment/basic_contract_deployment.hpp b/circuits/cpp/src/aztec3/circuits/apps/test_apps/basic_contract_deployment/basic_contract_deployment.hpp index d606dac38ec..71851b822ac 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/test_apps/basic_contract_deployment/basic_contract_deployment.hpp +++ b/circuits/cpp/src/aztec3/circuits/apps/test_apps/basic_contract_deployment/basic_contract_deployment.hpp @@ -10,8 +10,6 @@ namespace aztec3::circuits::apps::test_apps::basic_contract_deployment { using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; OptionalPrivateCircuitPublicInputs constructor(FunctionExecutionContext& exec_ctx, - NT::fr const& _arg0, - NT::fr const& _arg1, - NT::fr const& _arg2); + std::array const& args); } // namespace aztec3::circuits::apps::test_apps::basic_contract_deployment \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp b/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp index 08d6d440089..04dd483d5a5 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp @@ -58,7 +58,7 @@ TEST_F(escrow_tests, test_deposit) auto asset_id = NT::fr(1); auto memo = NT::fr(999); - auto result = deposit(exec_ctx, amount, asset_id, memo); + auto result = deposit(exec_ctx, { amount, asset_id, memo }); info("result: ", result); info("computed witness: ", composer.computed_witness); diff --git a/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp b/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp index c2ed7322c84..4c7b0245202 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp +++ b/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/deposit.cpp @@ -10,9 +10,7 @@ namespace aztec3::circuits::apps::test_apps::escrow { using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; OptionalPrivateCircuitPublicInputs deposit(FunctionExecutionContext& exec_ctx, - NT::fr const& _amount, - NT::fr const& _asset_id, - NT::fr const& _memo) + std::array const& args) { /**************************************************************** * PREAMBLE @@ -25,9 +23,9 @@ OptionalPrivateCircuitPublicInputs deposit(FunctionExecutionContext& exec_ct // Convert params into circuit types: auto& composer = exec_ctx.composer; - CT::fr amount = to_ct(composer, _amount); - CT::fr asset_id = to_ct(composer, _asset_id); - CT::fr memo = to_ct(composer, _memo); + CT::fr amount = to_ct(composer, args[0]); + CT::fr asset_id = to_ct(composer, args[1]); + CT::fr memo = to_ct(composer, args[2]); auto& oracle = exec_ctx.oracle; const CT::address msg_sender = oracle.get_msg_sender(); diff --git a/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/deposit.hpp b/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/deposit.hpp index afb9391f8f2..6151d792ebf 100644 --- a/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/deposit.hpp +++ b/circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/deposit.hpp @@ -10,8 +10,6 @@ namespace aztec3::circuits::apps::test_apps::escrow { using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; OptionalPrivateCircuitPublicInputs deposit(FunctionExecutionContext& exec_ctx, - NT::fr const& _amount, - NT::fr const& _asset_id, - NT::fr const& _memo); + std::array const& args); } // namespace aztec3::circuits::apps::test_apps::escrow \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/hash.hpp b/circuits/cpp/src/aztec3/circuits/hash.hpp index 4a71fb1eec8..c5a722c6d8b 100644 --- a/circuits/cpp/src/aztec3/circuits/hash.hpp +++ b/circuits/cpp/src/aztec3/circuits/hash.hpp @@ -1,9 +1,14 @@ +#include #include +#include "aztec3/circuits/abis/function_leaf_preimage.hpp" +#include #include namespace aztec3::circuits { using abis::FunctionData; +using aztec3::circuits::abis::FunctionLeafPreimage; +using aztec3::circuits::abis::private_kernel::ContractLeafPreimage; template typename NCT::fr compute_args_hash(std::array args) { @@ -87,20 +92,108 @@ typename NCT::fr add_contract_address_to_nullifier(typename NCT::address contrac * @param siblingPath The nodes representing the merkle siblings of the leaf, its parent, * the next parent, etc up to the sibling below the root * @return The computed Merkle tree root. + * + * TODO need to use conditional assigns instead of `ifs` for circuit version. + * see membership.hpp:check_subtree_membership (left/right/conditional_assign, etc) */ template -typename NCT::fr root_from_sibling_path(typename NCT::fr leaf, - typename NCT::uint32 leafIndex, - std::array siblingPath) +typename NCT::fr root_from_sibling_path(typename NCT::fr const& leaf, + typename NCT::uint32 const& leafIndex, + std::array const& siblingPath) { - for (size_t i = 0; i < siblingPath.size(); i++) { + auto node = leaf; + for (size_t i = 0; i < N; i++) { if (leafIndex & (1 << i)) { - leaf = NCT::merkle_hash(siblingPath[i], leaf); + node = NCT::merkle_hash(siblingPath[i], node); } else { - leaf = NCT::merkle_hash(leaf, siblingPath[i]); + node = NCT::merkle_hash(node, siblingPath[i]); } } - return leaf; // root + return node; // root +} + +/** + * @brief Calculate the function tree root from the sibling path and leaf preimage. + * + * @tparam NCT (native or circuit) + * @param function_selector in leaf preimage + * @param is_private in leaf preimage + * @param vk_hash in leaf preimage + * @param acir_hash in leaf preimage + * @param function_leaf_index leaf index in the function tree + * @param function_leaf_sibling_path + * @return NCT::fr + */ +template +typename NCT::fr function_tree_root_from_siblings( + typename NCT::fr const& function_selector, + typename NCT::boolean const& is_private, + typename NCT::fr const& vk_hash, + typename NCT::fr const& acir_hash, + typename NCT::uint32 const& function_leaf_index, + std::array const& function_leaf_sibling_path) +{ + const auto function_leaf_preimage = FunctionLeafPreimage{ + .function_selector = function_selector, + .is_private = is_private, + .vk_hash = vk_hash, + .acir_hash = acir_hash, + }; + + const auto function_leaf = function_leaf_preimage.hash(); + + auto function_tree_root = + root_from_sibling_path(function_leaf, function_leaf_index, function_leaf_sibling_path); + return function_tree_root; +} + +/** + * @brief Calculate the contract tree root from the sibling path and leaf preimage. + * + * @tparam NCT (native or circuit) + * @param function_tree_root in leaf preimage + * @param storage_contract_address in leaf preimage + * @param portal_contract_address in leaf preimage + * @param contract_leaf_index leaf index in the function tree + * @param contract_leaf_sibling_path + * @return NCT::fr + */ +template +typename NCT::fr contract_tree_root_from_siblings( + typename NCT::fr const& function_tree_root, + typename NCT::address const& storage_contract_address, + typename NCT::address const& portal_contract_address, + typename NCT::uint32 const& contract_leaf_index, + std::array const& contract_leaf_sibling_path) +{ + const ContractLeafPreimage contract_leaf_preimage{ storage_contract_address, + portal_contract_address, + function_tree_root }; + + const auto contract_leaf = contract_leaf_preimage.hash(); + + const auto computed_contract_tree_root = + root_from_sibling_path(contract_leaf, contract_leaf_index, contract_leaf_sibling_path); + return computed_contract_tree_root; +} + +/** + * @brief Compute sibling path for an empty tree. + * + * @tparam NCT (native or circuit) + * @tparam TREE_HEIGHT + * @param zero_leaf the leaf value that corresponds to a zero preimage + * @return std::array + */ +template +std::array compute_empty_sibling_path(typename NCT::fr const& zero_leaf) +{ + std::array sibling_path = { zero_leaf }; + for (size_t i = 1; i < TREE_HEIGHT; i++) { + // hash previous sibling with itself to get node above + sibling_path[i] = NCT::merkle_hash(sibling_path[i - 1], sibling_path[i - 1]); + } + return sibling_path; } } // namespace aztec3::circuits \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/.test.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/.test.cpp index cdcedf5b6fe..1d092f77578 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/.test.cpp @@ -1,14 +1,11 @@ -// #include -// #include -// #include -// #include -// #include #include "index.hpp" #include "init.hpp" #include "c_bind.h" +#include "aztec3/constants.hpp" #include +#include #include #include @@ -26,36 +23,30 @@ #include #include #include -// #include -// #include -#include "aztec3/circuits/kernel/private/utils.hpp" - -#include -// #include +#include "aztec3/circuits/kernel/private/utils.hpp" #include #include #include +#include #include -// #include -// #include -// #include - namespace { -using aztec3::circuits::compute_constructor_hash; +using aztec3::circuits::compute_empty_sibling_path; using aztec3::circuits::abis::CallContext; using aztec3::circuits::abis::CallStackItem; using aztec3::circuits::abis::CallType; using aztec3::circuits::abis::ContractDeploymentData; using aztec3::circuits::abis::FunctionData; +using aztec3::circuits::abis::FunctionLeafPreimage; using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; using aztec3::circuits::abis::PrivateCircuitPublicInputs; using aztec3::circuits::abis::SignedTxRequest; using aztec3::circuits::abis::TxContext; using aztec3::circuits::abis::TxRequest; +using aztec3::circuits::abis::private_kernel::NewContractData; using aztec3::circuits::abis::private_kernel::AccumulatedData; using aztec3::circuits::abis::private_kernel::ConstantData; @@ -70,288 +61,253 @@ using aztec3::circuits::apps::test_apps::escrow::deposit; using DummyComposer = aztec3::utils::DummyComposer; -// using aztec3::circuits::mock::mock_circuit; using aztec3::circuits::mock::mock_kernel_circuit; +// A type representing any private circuit function +// (for now it works for deposit and constructor) +using private_function = std::function( + FunctionExecutionContext&, + std::array const&)>; + +// Some helper constants for trees +constexpr size_t MAX_FUNCTION_LEAVES = 2 << (aztec3::FUNCTION_TREE_HEIGHT - 1); +const NT::fr EMPTY_FUNCTION_LEAF = FunctionLeafPreimage{}.hash(); // hash of empty/0 preimage +const NT::fr EMPTY_CONTRACT_LEAF = NewContractData{}.hash(); // hash of empty/0 preimage +const auto& EMPTY_FUNCTION_SIBLINGS = compute_empty_sibling_path(EMPTY_FUNCTION_LEAF); +const auto& EMPTY_CONTRACT_SIBLINGS = compute_empty_sibling_path(EMPTY_CONTRACT_LEAF); + } // namespace namespace aztec3::circuits::kernel::private_kernel { -class private_kernel_tests : public ::testing::Test {}; - -TEST(private_kernel_tests, test_deposit) +/** + * @brief Print some debug info about a composer if in DEBUG_PRINTS mode + * + * @param composer + */ +void debugComposer(Composer const& composer) { - //*************************************************************************** - // Some private circuit proof (`deposit`, in this case) - //*************************************************************************** - - const NT::address escrow_contract_address = 12345; - // const NT::fr escrow_contract_leaf_index = 1; - const NT::fr escrow_portal_contract_address = 23456; - - const NT::fr msg_sender_private_key = 123456789; - const NT::address msg_sender = - NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); - const NT::address tx_origin = msg_sender; - - Composer deposit_composer = Composer("../barretenberg/cpp/srs_db/ignition"); - DB db; +#ifdef DEBUG_PRINTS + info("computed witness: ", composer.computed_witness); + // info("witness: ", private_kernel_composer.witness); + // info("constant variables: ", private_kernel_composer.constant_variables); + // info("variables: ", composer.variables); + info("failed?: ", composer.failed()); + info("err: ", composer.err()); + info("n: ", composer.get_num_gates()); +#else + (void)composer; // only used in debug mode +#endif +} - FunctionData function_data{ - .function_selector = 1, // TODO: deduce this from the contract, somehow. +/** + * @brief Generate a verification key for a private circuit. + * + * @details Use some dummy inputs just to get the VK for a private circuit + * + * @param is_constructor Whether this private call is a constructor call + * @param func The private circuit call to generate a VK for + * @param num_args Number of args to that private circuit call + * @return std::shared_ptr - the generated VK + */ +std::shared_ptr gen_func_vk(bool is_constructor, private_function const& func, size_t const num_args) +{ + // Some dummy inputs to get the circuit to compile and get a VK + FunctionData dummy_function_data{ .is_private = true, - .is_constructor = false, - }; - - CallContext call_context{ - .msg_sender = msg_sender, - .storage_contract_address = escrow_contract_address, - .portal_contract_address = 0, - .is_delegate_call = false, - .is_static_call = false, - .is_contract_deployment = false, - }; - - NativeOracle deposit_oracle = - NativeOracle(db, escrow_contract_address, function_data, call_context, msg_sender_private_key); - OracleWrapper deposit_oracle_wrapper = OracleWrapper(deposit_composer, deposit_oracle); - - FunctionExecutionContext deposit_ctx(deposit_composer, deposit_oracle_wrapper); - - auto amount = NT::fr(5); - auto asset_id = NT::fr(1); - auto memo = NT::fr(999); - - OptionalPrivateCircuitPublicInputs opt_deposit_public_inputs = deposit(deposit_ctx, amount, asset_id, memo); - PrivateCircuitPublicInputs deposit_public_inputs = opt_deposit_public_inputs.remove_optionality(); - - Prover deposit_prover = deposit_composer.create_prover(); - NT::Proof deposit_proof = deposit_prover.construct_proof(); - // info("\ndeposit_proof: ", deposit_proof.proof_data); - - std::shared_ptr deposit_vk = deposit_composer.compute_verification_key(); - - //*************************************************************************** - // We can create a TxRequest from some of the above data. Users must sign a TxRequest in order to give permission - // for a tx to take place - creating a SignedTxRequest. - //*************************************************************************** - - TxRequest deposit_tx_request = TxRequest{ - .from = tx_origin, - .to = escrow_contract_address, - .function_data = function_data, - .args = deposit_public_inputs.args, - .nonce = 0, - .tx_context = - TxContext{ - .is_fee_payment_tx = false, - .is_rebate_payment_tx = false, - .is_contract_deployment_tx = false, - .contract_deployment_data = ContractDeploymentData(), - }, - .chain_id = 1, - }; - - SignedTxRequest signed_deposit_tx_request = SignedTxRequest{ - .tx_request = deposit_tx_request, - - // .signature = TODO: need a method for signing a TxRequest. + .is_constructor = is_constructor, }; - //*************************************************************************** - // We mock a kernel circuit proof for the base case of kernel recursion (because even the first iteration of the - // kernel circuit expects to verify some previous kernel circuit). - //*************************************************************************** - - Composer mock_kernel_composer = Composer("../barretenberg/cpp/srs_db/ignition"); - - // TODO: we have a choice to make: - // Either the `end` state of the mock kernel's public inputs can be set equal to the public call we _want_ to - // verify in the first round of recursion, OR, we have some fiddly conditional logic in the circuit to ignore - // certain checks if we're handling the 'base case' of the recursion. - // I've chosen the former, for now. - const CallStackItem deposit_call_stack_item{ - .contract_address = deposit_tx_request.to, - - .function_data = deposit_tx_request.function_data, - - .public_inputs = deposit_public_inputs, + CallContext dummy_call_context{ + .is_contract_deployment = is_constructor, }; - std::array initial_kernel_private_call_stack{}; - initial_kernel_private_call_stack[0] = deposit_call_stack_item.hash(); - - // Some test data: - auto mock_kernel_public_inputs = PublicInputs{ - .end = - AccumulatedData{ - .private_call_stack = initial_kernel_private_call_stack, - }, - - // These will be constant throughout all recursions, so can be set to those of the first function call - the - // deposit tx. - .constants = - ConstantData{ - .old_tree_roots = - OldTreeRoots{ - .private_data_tree_root = deposit_public_inputs.historic_private_data_tree_root, - // .nullifier_tree_root = - // .contract_tree_root = - // .private_kernel_vk_tree_root = - }, - .tx_context = deposit_tx_request.tx_context, - }, - - .is_private = true, - // .is_public = false, - // .is_contract_deployment = false, - }; - - mock_kernel_circuit(mock_kernel_composer, mock_kernel_public_inputs); - - Prover mock_kernel_prover = mock_kernel_composer.create_prover(); - NT::Proof mock_kernel_proof = mock_kernel_prover.construct_proof(); - // info("\nmock_kernel_proof: ", mock_kernel_proof.proof_data); - - std::shared_ptr mock_kernel_vk = mock_kernel_composer.compute_verification_key(); - - //*************************************************************************** - // Now we can execute and prove the first kernel iteration, with all the data generated above: - // - app proof, public inputs, etc. - // - mock kernel proof, public inputs, etc. - //*************************************************************************** - - Composer private_kernel_composer = Composer("../barretenberg/cpp/srs_db/ignition"); - - PrivateInputs private_inputs = PrivateInputs{ - .signed_tx_request = signed_deposit_tx_request, - - .previous_kernel = - PreviousKernelData{ - .public_inputs = mock_kernel_public_inputs, - .proof = mock_kernel_proof, - .vk = mock_kernel_vk, - }, - - .private_call = - PrivateCallData{ - .call_stack_item = deposit_call_stack_item, - .private_call_stack_preimages = deposit_ctx.get_private_call_stack_items(), - - .proof = deposit_proof, - .vk = deposit_vk, - - // .function_leaf_membership_witness TODO - // .contract_leaf_membership_witness TODO - - .portal_contract_address = escrow_portal_contract_address, - - // TODO: MembershipWitness function_leaf_membership_witness; - // TODO: MembershipWitness contract_leaf_membership_witness; - }, - }; - - private_kernel_circuit(private_kernel_composer, private_inputs); + // Dummmy invokation of private call circuit, in order to derive its vk + Composer dummy_composer = Composer("../barretenberg/cpp/srs_db/ignition"); + { + DB dummy_db; + NativeOracle dummy_oracle = is_constructor + ? NativeOracle(dummy_db, 0, dummy_function_data, dummy_call_context, {}, 0) + : NativeOracle(dummy_db, 0, dummy_function_data, dummy_call_context, 0); - Prover final_kernel_prover = private_kernel_composer.create_prover(); - NT::Proof final_kernel_proof = final_kernel_prover.construct_proof(); + OracleWrapper dummy_oracle_wrapper = OracleWrapper(dummy_composer, dummy_oracle); - stdlib::types::Verifier final_kernel_verifier = private_kernel_composer.create_verifier(); - auto final_result = final_kernel_verifier.verify_proof(final_kernel_proof); - EXPECT_EQ(final_result, true); + FunctionExecutionContext dummy_ctx(dummy_composer, dummy_oracle_wrapper); - info("computed witness: ", private_kernel_composer.computed_witness); - // info("witness: ", private_kernel_composer.witness); - // info("constant variables: ", private_kernel_composer.constant_variables); - // info("variables: ", private_kernel_composer.variables); + std::array dummy_args; + // if args are value 0, deposit circuit errors when inserting utxo notes + dummy_args.fill(1); + // Make call to private call circuit itself to lay down constraints + func(dummy_ctx, dummy_args); + // FIXME remove arg + (void)num_args; + } - // TODO: this fails intermittently, with: - // bigfield multiply range check failed - info("failed?: ", private_kernel_composer.failed()); - info("err: ", private_kernel_composer.err()); - info("n: ", private_kernel_composer.get_num_gates()); + // Now we can derive the vk: + return dummy_composer.compute_verification_key(); } -TEST(private_kernel_tests, test_native_deposit) +/** + * @brief Perform a private circuit call and generate the inputs to private kernel + * + * @param is_constructor whether this private circuit call is a constructor + * @param func the private circuit call being validated by this kernel iteration + * @param args_vec the private call's args + * @return PrivateInputs - the inputs to the private call circuit + */ +PrivateInputs do_private_call_get_kernel_inputs(bool const is_constructor, + private_function const& func, + std::vector const& args_vec) { //*************************************************************************** - // Some private circuit proof (`deposit`, in this case) + // Initialize some inputs to private call and kernel circuits //*************************************************************************** - - const NT::address escrow_contract_address = 12345; - // const NT::fr escrow_contract_leaf_index = 1; - const NT::fr escrow_portal_contract_address = 23456; + // TODO randomize inputs + NT::address contract_address = is_constructor ? 0 : 12345; // updated later if in constructor + const NT::uint32 contract_leaf_index = 1; + const NT::uint32 function_leaf_index = 1; + const NT::fr portal_contract_address = 23456; + const NT::fr contract_address_salt = 34567; + const NT::fr acir_hash = 12341234; const NT::fr msg_sender_private_key = 123456789; const NT::address msg_sender = NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); const NT::address tx_origin = msg_sender; - /** - * NOTE: this is a bit cheeky. We want to test the _native_ kernel circuit implementation. But I don't want to write - * a corresponding _native_ version of every 'app'. So let's just compute the circuit version of the app, and then - * convert it to native types, so that it can be fed into the kernel circuit. - * - */ - Composer deposit_composer = Composer("../barretenberg/cpp/srs_db/ignition"); - DB db; - FunctionData function_data{ .function_selector = 1, // TODO: deduce this from the contract, somehow. .is_private = true, - .is_constructor = false, + .is_constructor = is_constructor, }; CallContext call_context{ .msg_sender = msg_sender, - .storage_contract_address = escrow_contract_address, - .portal_contract_address = 0, + .storage_contract_address = contract_address, + .portal_contract_address = portal_contract_address, .is_delegate_call = false, .is_static_call = false, - .is_contract_deployment = false, + .is_contract_deployment = is_constructor, }; - NativeOracle deposit_oracle = - NativeOracle(db, escrow_contract_address, function_data, call_context, msg_sender_private_key); - OracleWrapper deposit_oracle_wrapper = OracleWrapper(deposit_composer, deposit_oracle); + // sometimes need private call args as array + std::array args{}; + for (size_t i = 0; i < args_vec.size(); ++i) { + args[i] = args_vec[i]; + } + + //*************************************************************************** + // Initialize contract related information like private call VK (and its hash), + // function tree, contract tree, contract address for newly deployed contract, + // etc... + //*************************************************************************** + + // generate private circuit VK and its hash using circuit with dummy inputs + // it is needed below: + // for constructors - to generate the contract address, function leaf, etc + // for private calls - to generate the function leaf, etc + const std::shared_ptr private_circuit_vk = gen_func_vk(is_constructor, func, args_vec.size()); + const NT::fr private_circuit_vk_hash = + stdlib::recursion::verification_key::compress_native(private_circuit_vk, GeneratorIndex::VK); + + ContractDeploymentData contract_deployment_data{}; + NT::fr contract_tree_root = 0; // TODO set properly for constructor? + if (is_constructor) { + // TODO compute function tree root from leaves + // create leaf preimage for each function and hash all into tree + // push to array/vector + // use variation of `compute_root_partial_left_tree` to compute the root from leaves + // const auto& function_leaf_preimage = FunctionLeafPreimage{ + // .function_selector = function_data.function_selector, + // .is_private = function_data.is_private, + // .vk_hash = private_circuit_vk_hash, + // .acir_hash = acir_hash, + //}; + std::vector function_leaves(MAX_FUNCTION_LEAVES, EMPTY_FUNCTION_LEAF); + // const NT::fr& function_tree_root = plonk::stdlib::merkle_tree::compute_tree_root_native(function_leaves); + + // TODO use actual function tree root computed from leaves + // update cdd with actual info + contract_deployment_data = { + .constructor_vk_hash = private_circuit_vk_hash, + .function_tree_root = plonk::stdlib::merkle_tree::compute_tree_root_native(function_leaves), + .contract_address_salt = contract_address_salt, + .portal_contract_address = portal_contract_address, + }; - FunctionExecutionContext deposit_ctx(deposit_composer, deposit_oracle_wrapper); + // Get constructor hash for use when deriving contract address + auto constructor_hash = compute_constructor_hash(function_data, args, private_circuit_vk_hash); + + // Derive contract address so that it can be used inside the constructor itself + contract_address = compute_contract_address( + msg_sender, contract_address_salt, contract_deployment_data.function_tree_root, constructor_hash); + // update the contract address in the call context now that it is known + call_context.storage_contract_address = contract_address; + } else { + const NT::fr& function_tree_root = function_tree_root_from_siblings(function_data.function_selector, + function_data.is_private, + private_circuit_vk_hash, + acir_hash, + function_leaf_index, + EMPTY_FUNCTION_SIBLINGS); + + // update contract_tree_root with real value + contract_tree_root = contract_tree_root_from_siblings(function_tree_root, + contract_address, + portal_contract_address, + contract_leaf_index, + EMPTY_CONTRACT_SIBLINGS); + } - auto amount = NT::fr(5); - auto asset_id = NT::fr(1); - auto memo = NT::fr(999); + //*************************************************************************** + // Create a private circuit/call using composer, oracles, execution context + // Generate its proof and public inputs for submission with a TX request + //*************************************************************************** + Composer private_circuit_composer = Composer("../barretenberg/cpp/srs_db/ignition"); - OptionalPrivateCircuitPublicInputs opt_deposit_public_inputs = deposit(deposit_ctx, amount, asset_id, memo); - PrivateCircuitPublicInputs deposit_public_inputs = opt_deposit_public_inputs.remove_optionality(); + DB db; + NativeOracle oracle = + is_constructor + ? NativeOracle( + db, contract_address, function_data, call_context, contract_deployment_data, msg_sender_private_key) + : NativeOracle(db, contract_address, function_data, call_context, msg_sender_private_key); - Prover deposit_prover = deposit_composer.create_prover(); - NT::Proof deposit_proof = deposit_prover.construct_proof(); + OracleWrapper oracle_wrapper = OracleWrapper(private_circuit_composer, oracle); - std::shared_ptr deposit_vk = deposit_composer.compute_verification_key(); + FunctionExecutionContext ctx(private_circuit_composer, oracle_wrapper); + + OptionalPrivateCircuitPublicInputs opt_private_circuit_public_inputs = func(ctx, args); + PrivateCircuitPublicInputs private_circuit_public_inputs = + opt_private_circuit_public_inputs.remove_optionality(); + // TODO this should likely be handled as part of the DB/Oracle/Context infrastructure + private_circuit_public_inputs.historic_contract_tree_root = contract_tree_root; + + Prover private_circuit_prover = private_circuit_composer.create_prover(); + NT::Proof private_circuit_proof = private_circuit_prover.construct_proof(); + // info("\nproof: ", private_circuit_proof.proof_data); //*************************************************************************** // We can create a TxRequest from some of the above data. Users must sign a TxRequest in order to give permission // for a tx to take place - creating a SignedTxRequest. //*************************************************************************** - - TxRequest deposit_tx_request = TxRequest{ + TxRequest tx_request = TxRequest{ .from = tx_origin, - .to = escrow_contract_address, + .to = contract_address, .function_data = function_data, - .args = deposit_public_inputs.args, + .args = private_circuit_public_inputs.args, .nonce = 0, .tx_context = TxContext{ .is_fee_payment_tx = false, .is_rebate_payment_tx = false, - .is_contract_deployment_tx = false, - .contract_deployment_data = ContractDeploymentData(), + .is_contract_deployment_tx = is_constructor, + .contract_deployment_data = contract_deployment_data, }, .chain_id = 1, }; - SignedTxRequest signed_deposit_tx_request = SignedTxRequest{ - .tx_request = deposit_tx_request, + SignedTxRequest signed_tx_request = SignedTxRequest{ + .tx_request = tx_request, // .signature = TODO: need a method for signing a TxRequest. }; @@ -360,7 +316,6 @@ TEST(private_kernel_tests, test_native_deposit) // We mock a kernel circuit proof for the base case of kernel recursion (because even the first iteration of the // kernel circuit expects to verify some previous kernel circuit). //*************************************************************************** - Composer mock_kernel_composer = Composer("../barretenberg/cpp/srs_db/ignition"); // TODO: we have a choice to make: @@ -368,36 +323,33 @@ TEST(private_kernel_tests, test_native_deposit) // verify in the first round of recursion, OR, we have some fiddly conditional logic in the circuit to ignore // certain checks if we're handling the 'base case' of the recursion. // I've chosen the former, for now. - const CallStackItem deposit_call_stack_item{ - .contract_address = deposit_tx_request.to, - - .function_data = deposit_tx_request.function_data, - - .public_inputs = deposit_public_inputs, + const CallStackItem call_stack_item{ + .contract_address = tx_request.to, + .function_data = tx_request.function_data, + .public_inputs = private_circuit_public_inputs, }; std::array initial_kernel_private_call_stack{}; - initial_kernel_private_call_stack[0] = deposit_call_stack_item.hash(); + initial_kernel_private_call_stack[0] = call_stack_item.hash(); // Some test data: - PublicInputs mock_kernel_public_inputs = PublicInputs{ + auto mock_kernel_public_inputs = PublicInputs{ .end = AccumulatedData{ .private_call_stack = initial_kernel_private_call_stack, }, - // These will be constant throughout all recursions, so can be set to those of the first function call - the - // deposit tx. + // These will be constant throughout all recursions, so can be set to those of the first function call - the tx. .constants = ConstantData{ .old_tree_roots = OldTreeRoots{ - .private_data_tree_root = deposit_public_inputs.historic_private_data_tree_root, + .private_data_tree_root = private_circuit_public_inputs.historic_private_data_tree_root, // .nullifier_tree_root = - // .contract_tree_root = + .contract_tree_root = private_circuit_public_inputs.historic_contract_tree_root, // .private_kernel_vk_tree_root = }, - .tx_context = deposit_tx_request.tx_context, + .tx_context = tx_request.tx_context, }, .is_private = true, @@ -409,20 +361,15 @@ TEST(private_kernel_tests, test_native_deposit) Prover mock_kernel_prover = mock_kernel_composer.create_prover(); NT::Proof mock_kernel_proof = mock_kernel_prover.construct_proof(); + // info("\nmock_kernel_proof: ", mock_kernel_proof.proof_data); std::shared_ptr mock_kernel_vk = mock_kernel_composer.compute_verification_key(); //*************************************************************************** - // Now we can execute and prove the first kernel iteration, with all the data generated above: - // - app proof, public inputs, etc. - // - mock kernel proof, public inputs, etc. + // Now we can construct the full private inputs to the kernel circuit //*************************************************************************** - - // NOTE: WE DON'T USE A COMPOSER HERE, SINCE WE WANT TO TEST THE `native_private_kernel_circuit` - // Composer private_kernel_composer = Composer("../barretenberg/cpp/srs_db/ignition"); - - PrivateInputs private_inputs = PrivateInputs{ - .signed_tx_request = signed_deposit_tx_request, + PrivateInputs kernel_private_inputs = PrivateInputs{ + .signed_tx_request = signed_tx_request, .previous_kernel = PreviousKernelData{ @@ -433,690 +380,227 @@ TEST(private_kernel_tests, test_native_deposit) .private_call = PrivateCallData{ - .call_stack_item = deposit_call_stack_item, - .private_call_stack_preimages = deposit_ctx.get_private_call_stack_items(), + .call_stack_item = call_stack_item, + .private_call_stack_preimages = ctx.get_private_call_stack_items(), - .proof = deposit_proof, - .vk = deposit_vk, - // .vk_path TODO + .proof = private_circuit_proof, + .vk = private_circuit_vk, - // TODO: MembershipWitness function_leaf_membership_witness; - // TODO: MembershipWitness contract_leaf_membership_witness; + .function_leaf_membership_witness = { + .leaf_index = function_leaf_index, + .sibling_path = EMPTY_FUNCTION_SIBLINGS, + }, + .contract_leaf_membership_witness = { + .leaf_index = contract_leaf_index, + .sibling_path = EMPTY_CONTRACT_SIBLINGS, + }, - .portal_contract_address = escrow_portal_contract_address, + .portal_contract_address = portal_contract_address, + + .acir_hash = acir_hash, }, }; - DummyComposer composer = DummyComposer(); - PublicInputs public_inputs = native_private_kernel_circuit(composer, private_inputs); - - // Prover final_kernel_prover = private_kernel_composer.create_prover(); - // NT::Proof final_kernel_proof = final_kernel_prover.construct_proof(); - - // stdlib::types::Verifier final_kernel_verifier = private_kernel_composer.create_verifier(); - // auto final_result = final_kernel_verifier.verify_proof(final_kernel_proof); - // EXPECT_EQ(final_result, true); - - // info("computed witness: ", private_kernel_composer.computed_witness); - // info("witness: ", private_kernel_composer.witness); - // info("constant variables: ", private_kernel_composer.constant_variables); - // info("variables: ", private_kernel_composer.variables); - - // TODO: this fails intermittently, with: - // bigfield multiply range check failed - // info("failed?: ", private_kernel_composer.failed()); - // info("err: ", private_kernel_composer.err()); - // info("n: ", private_kernel_composer.get_num_gates()); + return kernel_private_inputs; } -TEST(private_kernel_tests, test_basic_contract_deployment) +/** + * @brief Validate that the deployed contract address is correct. + * + * @details Compare the public inputs new contract address + * with one manually computed from private inputs. + * @param private_inputs to be used in manual computation + * @param public_inputs that contain the expected new contract address + */ +void validate_deployed_contract_address(PrivateInputs const& private_inputs, PublicInputs const& public_inputs) { - //*************************************************************************** - // Some private circuit proof (`constructor`, in this case) - //*************************************************************************** - - // contract address for newly deployed contract will be derived - // below after constructor VK is computed - // const NT::fr new_contract_leaf_index = 1; - const NT::fr new_portal_contract_address = 23456; - const NT::fr contract_address_salt = 34567; - - const NT::fr msg_sender_private_key = 123456789; - const NT::address msg_sender = - NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); - const NT::address tx_origin = msg_sender; - - FunctionData function_data{ - .function_selector = 1, // TODO: deduce this from the contract, somehow. - .is_private = true, - .is_constructor = true, - }; - - CallContext call_context{ - .msg_sender = msg_sender, - .storage_contract_address = 0, // will be replaced with contract address once it is calculated - .portal_contract_address = 0, - .is_delegate_call = false, - .is_static_call = false, - .is_contract_deployment = true, - }; - - NT::fr arg0 = 5; - NT::fr arg1 = 1; - NT::fr arg2 = 999; - std::array args = { 0 }; - args[0] = arg0; - args[1] = arg1; - args[2] = arg2; - - Composer dummy_constructor_composer = Composer("../barretenberg/cpp/srs_db/ignition"); - { - // Dummmy invokation, in order to derive the vk of this circuit - - // We need to use _dummy_ contract_deployment_data first, because the _proper_ version of the - // contract_deployment_data will need to contain the constructor_vk_hash... but the constructor's vk can only be - // computed after the composer has composed the circuit! - ContractDeploymentData dummy_contract_deployment_data{ - .constructor_vk_hash = 0, // zeros are okay for dummy call - .function_tree_root = 0, - .contract_address_salt = 0, - .portal_contract_address = 0, - }; - - DB dummy_db; - NativeOracle dummy_constructor_oracle = NativeOracle(dummy_db, - 0, // contract address not known during VK computation - function_data, - call_context, - dummy_contract_deployment_data, - msg_sender_private_key); - OracleWrapper dummy_constructor_oracle_wrapper = - OracleWrapper(dummy_constructor_composer, dummy_constructor_oracle); - - FunctionExecutionContext dummy_constructor_ctx(dummy_constructor_composer, dummy_constructor_oracle_wrapper); - - constructor(dummy_constructor_ctx, arg0, arg1, arg2); - } - - // Now we can derive the vk: - std::shared_ptr constructor_vk = dummy_constructor_composer.compute_verification_key(); - auto constructor_vk_hash = - stdlib::recursion::verification_key::compress_native(constructor_vk, GeneratorIndex::VK); - - // Now, we can proceed with the proper (non-dummy) invokation of our constructor circuit: - - Composer constructor_composer = Composer("../barretenberg/cpp/srs_db/ignition"); - DB db; - - ContractDeploymentData contract_deployment_data{ - .constructor_vk_hash = constructor_vk_hash, - .function_tree_root = 0, // TODO actually get this? - .contract_address_salt = contract_address_salt, - .portal_contract_address = new_portal_contract_address, - }; - - // Get constructor hash for use when deriving contract address - auto constructor_hash = compute_constructor_hash(function_data, args, constructor_vk_hash); - - // Derive contract address so that it can be used inside the constructor itself - const NT::address new_contract_address = compute_contract_address( - msg_sender, contract_address_salt, contract_deployment_data.function_tree_root, constructor_hash); - // update the contract address in the call context now that it is known - call_context.storage_contract_address = new_contract_address; - - NativeOracle constructor_oracle = NativeOracle( - db, new_contract_address, function_data, call_context, contract_deployment_data, msg_sender_private_key); - OracleWrapper constructor_oracle_wrapper = OracleWrapper(constructor_composer, constructor_oracle); - - FunctionExecutionContext constructor_ctx(constructor_composer, constructor_oracle_wrapper); - - OptionalPrivateCircuitPublicInputs opt_constructor_public_inputs = - constructor(constructor_ctx, arg0, arg1, arg2); - - PrivateCircuitPublicInputs constructor_public_inputs = opt_constructor_public_inputs.remove_optionality(); - - Prover constructor_prover = constructor_composer.create_prover(); - NT::Proof constructor_proof = constructor_prover.construct_proof(); - // info("\nconstructor_proof: ", constructor_proof.proof_data); - - auto expected_constructor_hash = - NT::compress({ function_data.hash(), - NT::compress(constructor_public_inputs.args, CONSTRUCTOR_ARGS), - constructor_vk_hash }, - CONSTRUCTOR); - NT::fr expected_contract_address = NT::compress({ msg_sender, - contract_deployment_data.contract_address_salt, - contract_deployment_data.function_tree_root, - expected_constructor_hash }, - CONTRACT_ADDRESS); - - //*************************************************************************** - // We can create a TxRequest from some of the above data. Users must sign a TxRequest in order to give permission - // for a tx to take place - creating a SignedTxRequest. - //*************************************************************************** - - TxRequest constructor_tx_request = TxRequest{ - .from = tx_origin, - .to = new_contract_address, - .function_data = function_data, - .args = constructor_public_inputs.args, - .nonce = 0, - .tx_context = - TxContext{ - .is_fee_payment_tx = false, - .is_rebate_payment_tx = false, - .is_contract_deployment_tx = true, - .contract_deployment_data = contract_deployment_data, - }, - .chain_id = 1, - }; - - SignedTxRequest signed_constructor_tx_request = SignedTxRequest{ - .tx_request = constructor_tx_request, - - // .signature = TODO: need a method for signing a TxRequest. - }; - - //*************************************************************************** - // We mock a kernel circuit proof for the base case of kernel recursion (because even the first iteration of the - // kernel circuit expects to verify some previous kernel circuit). - //*************************************************************************** - - Composer mock_kernel_composer = Composer("../barretenberg/cpp/srs_db/ignition"); - // TODO: we have a choice to make: - // Either the `end` state of the mock kernel's public inputs can be set equal to the public call we _want_ to - // verify in the first round of recursion, OR, we have some fiddly conditional logic in the circuit to ignore - // certain checks if we're handling the 'base case' of the recursion. - // I've chosen the former, for now. - const CallStackItem constructor_call_stack_item{ - .contract_address = constructor_tx_request.to, - - .function_data = constructor_tx_request.function_data, - - .public_inputs = constructor_public_inputs, - }; - - std::array initial_kernel_private_call_stack{}; - initial_kernel_private_call_stack[0] = constructor_call_stack_item.hash(); + auto tx_request = private_inputs.signed_tx_request.tx_request; + auto cdd = private_inputs.signed_tx_request.tx_request.tx_context.contract_deployment_data; + + auto private_circuit_vk_hash = stdlib::recursion::verification_key::compress_native( + private_inputs.private_call.vk, GeneratorIndex::VK); + auto expected_constructor_hash = NT::compress({ private_inputs.private_call.call_stack_item.function_data.hash(), + NT::compress(tx_request.args, CONSTRUCTOR_ARGS), + private_circuit_vk_hash }, + CONSTRUCTOR); + NT::fr expected_contract_address = + NT::compress({ tx_request.from, cdd.contract_address_salt, cdd.function_tree_root, expected_constructor_hash }, + CONTRACT_ADDRESS); + EXPECT_EQ(public_inputs.end.new_contracts[0].contract_address.to_field(), expected_contract_address); +} - // Some test data: - auto mock_kernel_public_inputs = PublicInputs(); - mock_kernel_public_inputs.end.private_call_stack = initial_kernel_private_call_stack, - mock_kernel_public_inputs.constants.old_tree_roots.private_data_tree_root = - constructor_public_inputs.historic_private_data_tree_root; - mock_kernel_public_inputs.constants.tx_context = constructor_tx_request.tx_context; - mock_kernel_public_inputs.is_private = true; +/** + * @brief Some private circuit proof (`deposit`, in this case) + */ +TEST(private_kernel_tests, test_circuit_deposit) +{ + NT::fr const& amount = 5; + NT::fr const& asset_id = 1; + NT::fr const& memo = 999; - mock_kernel_circuit(mock_kernel_composer, mock_kernel_public_inputs); + auto const& private_inputs = do_private_call_get_kernel_inputs(false, deposit, { amount, asset_id, memo }); - Prover mock_kernel_prover = mock_kernel_composer.create_prover(); - NT::Proof mock_kernel_proof = mock_kernel_prover.construct_proof(); - // info("\nmock_kernel_proof: ", mock_kernel_proof.proof_data); + // Execute and prove the first kernel iteration + Composer private_kernel_composer("../barretenberg/cpp/srs_db/ignition"); + auto const& public_inputs = private_kernel_circuit(private_kernel_composer, private_inputs); - std::shared_ptr mock_kernel_vk = mock_kernel_composer.compute_verification_key(); + // Check contract address was correctly computed by the circuit + validate_deployed_contract_address(private_inputs, public_inputs); - //*************************************************************************** - // Now we can execute and prove the first kernel iteration, with all the data generated above: - // - app proof, public inputs, etc. - // - mock kernel proof, public inputs, etc. - //*************************************************************************** + // Create the final kernel proof and verify it natively. + auto final_kernel_prover = private_kernel_composer.create_prover(); + auto const& final_kernel_proof = final_kernel_prover.construct_proof(); - Composer private_kernel_composer = Composer("../barretenberg/cpp/srs_db/ignition"); + auto final_kernel_verifier = private_kernel_composer.create_verifier(); + auto const& final_result = final_kernel_verifier.verify_proof(final_kernel_proof); + EXPECT_EQ(final_result, true); - PrivateInputs private_inputs = PrivateInputs{ - .signed_tx_request = signed_constructor_tx_request, + debugComposer(private_kernel_composer); +} - .previous_kernel = - PreviousKernelData{ - .public_inputs = mock_kernel_public_inputs, - .proof = mock_kernel_proof, - .vk = mock_kernel_vk, - }, +/** + * @brief Some private circuit simulation (`deposit`, in this case) + */ +TEST(private_kernel_tests, test_native_deposit) +{ + NT::fr const& amount = 5; + NT::fr const& asset_id = 1; + NT::fr const& memo = 999; - .private_call = - PrivateCallData{ - .call_stack_item = constructor_call_stack_item, - .private_call_stack_preimages = constructor_ctx.get_private_call_stack_items(), + auto const& private_inputs = do_private_call_get_kernel_inputs(false, deposit, { amount, asset_id, memo }); + DummyComposer composer; + auto const& public_inputs = native_private_kernel_circuit(composer, private_inputs); - .proof = constructor_proof, - .vk = constructor_vk, + validate_deployed_contract_address(private_inputs, public_inputs); +} - // .function_leaf_membership_witness TODO - // .contract_leaf_membership_witness TODO +/** + * @brief Some private circuit proof (`constructor`, in this case) + */ +TEST(private_kernel_tests, test_basic_contract_deployment) +{ + NT::fr const& arg0 = 5; + NT::fr const& arg1 = 1; + NT::fr const& arg2 = 999; + std::vector args_vec = { arg0, arg1, arg2 }; - .portal_contract_address = new_portal_contract_address, - }, - }; + auto const& private_inputs = do_private_call_get_kernel_inputs(true, constructor, args_vec); - auto private_kernel_circuit_public_inputs = private_kernel_circuit(private_kernel_composer, private_inputs); + // Execute and prove the first kernel iteration + Composer private_kernel_composer("../barretenberg/cpp/srs_db/ignition"); + auto const& public_inputs = private_kernel_circuit(private_kernel_composer, private_inputs); // Check contract address was correctly computed by the circuit - EXPECT_EQ(private_kernel_circuit_public_inputs.end.new_contracts[0].contract_address.to_field(), - expected_contract_address); + validate_deployed_contract_address(private_inputs, public_inputs); // Create the final kernel proof and verify it natively. - stdlib::types::Prover final_kernel_prover = private_kernel_composer.create_prover(); - NT::Proof final_kernel_proof = final_kernel_prover.construct_proof(); + auto final_kernel_prover = private_kernel_composer.create_prover(); + auto const& final_kernel_proof = final_kernel_prover.construct_proof(); - stdlib::types::Verifier final_kernel_verifier = private_kernel_composer.create_verifier(); - auto final_result = final_kernel_verifier.verify_proof(final_kernel_proof); + auto final_kernel_verifier = private_kernel_composer.create_verifier(); + auto const& final_result = final_kernel_verifier.verify_proof(final_kernel_proof); EXPECT_EQ(final_result, true); - info("computed witness: ", private_kernel_composer.computed_witness); - // info("witness: ", private_kernel_composer.witness); - // info("constant variables: ", private_kernel_composer.constant_variables); - // info("variables: ", private_kernel_composer.variables); - - // TODO: this fails intermittently, with: - // bigfield multiply range check failed - info("failed?: ", private_kernel_composer.failed()); - info("err: ", private_kernel_composer.err()); - info("n: ", private_kernel_composer.num_gates); + debugComposer(private_kernel_composer); } +/** + * @brief Some private circuit simulation (`constructor`, in this case) + */ TEST(private_kernel_tests, test_native_basic_contract_deployment) { - //*************************************************************************** - // Some private circuit proof (`constructor`, in this case) - //*************************************************************************** - - // contract address for newly deployed contract will be derived - // below after constructor VK is computed - // const NT::fr new_contract_leaf_index = 1; - const NT::fr new_portal_contract_address = 23456; - const NT::fr contract_address_salt = 34567; - - const NT::fr msg_sender_private_key = 123456789; - const NT::address msg_sender = - NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); - const NT::address tx_origin = msg_sender; - - /** - * NOTE: this is a bit cheeky. We want to test the _native_ kernel circuit implementation. But I don't want to write - * a corresponding _native_ version of every 'app'. So let's just compute the circuit version of the app, and then - * convert it to native types, so that it can be fed into the kernel circuit. - * - */ - FunctionData function_data{ - .function_selector = 1, // TODO: deduce this from the contract, somehow. - .is_private = true, - .is_constructor = true, - }; - - CallContext call_context{ - .msg_sender = msg_sender, - .storage_contract_address = 0, // will be replaced with contract address once it is calculated - .portal_contract_address = 0, - .is_delegate_call = false, - .is_static_call = false, - .is_contract_deployment = true, - }; - - NT::fr arg0 = 5; - NT::fr arg1 = 1; - NT::fr arg2 = 999; - std::array args = { 0 }; - args[0] = arg0; - args[1] = arg1; - args[2] = arg2; - - Composer dummy_constructor_composer = Composer("../barretenberg/cpp/srs_db/ignition"); - { - // Dummmy invokation, in order to derive the vk of this circuit - - // We need to use _dummy_ contract_deployment_data first, because the _proper_ version of the - // contract_deployment_data will need to contain the constructor_vk_hash... but the constructor's vk can only be - // computed after the composer has composed the circuit! - ContractDeploymentData dummy_contract_deployment_data{ - .constructor_vk_hash = 0, // zeros are okay for dummy call - .function_tree_root = 0, - .contract_address_salt = 0, - .portal_contract_address = 0, - }; - - DB dummy_db; - NativeOracle dummy_constructor_oracle = NativeOracle(dummy_db, - 0, // contract address not known during VK computation - function_data, - call_context, - dummy_contract_deployment_data, - msg_sender_private_key); - OracleWrapper dummy_constructor_oracle_wrapper = - OracleWrapper(dummy_constructor_composer, dummy_constructor_oracle); - - FunctionExecutionContext dummy_constructor_ctx(dummy_constructor_composer, dummy_constructor_oracle_wrapper); - - constructor(dummy_constructor_ctx, arg0, arg1, arg2); - } - - // Now we can derive the vk: - std::shared_ptr constructor_vk = dummy_constructor_composer.compute_verification_key(); - auto constructor_vk_hash = - stdlib::recursion::verification_key::compress_native(constructor_vk, GeneratorIndex::VK); - - // Now, we can proceed with the proper (non-dummy) invokation of our constructor circuit: - - Composer constructor_composer = Composer("../barretenberg/cpp/srs_db/ignition"); - DB db; - - ContractDeploymentData contract_deployment_data{ - .constructor_vk_hash = constructor_vk_hash, - .function_tree_root = 0, // TODO actually get this? - .contract_address_salt = contract_address_salt, - .portal_contract_address = new_portal_contract_address, - }; - - // Get constructor hash for use when deriving contract address - auto constructor_hash = compute_constructor_hash(function_data, args, constructor_vk_hash); - - // Derive contract address so that it can be used inside the constructor itself - const NT::address new_contract_address = compute_contract_address( - msg_sender, contract_address_salt, contract_deployment_data.function_tree_root, constructor_hash); - - // update the contract address in the call context now that it is known - call_context.storage_contract_address = new_contract_address; - - NativeOracle constructor_oracle = NativeOracle( - db, new_contract_address, function_data, call_context, contract_deployment_data, msg_sender_private_key); - OracleWrapper constructor_oracle_wrapper = OracleWrapper(constructor_composer, constructor_oracle); - - FunctionExecutionContext constructor_ctx(constructor_composer, constructor_oracle_wrapper); + NT::fr const& arg0 = 5; + NT::fr const& arg1 = 1; + NT::fr const& arg2 = 999; + std::vector args_vec = { arg0, arg1, arg2 }; - OptionalPrivateCircuitPublicInputs opt_constructor_public_inputs = - constructor(constructor_ctx, arg0, arg1, arg2); + auto const& private_inputs = do_private_call_get_kernel_inputs(true, constructor, args_vec); + DummyComposer composer; + auto const& public_inputs = native_private_kernel_circuit(composer, private_inputs); - PrivateCircuitPublicInputs constructor_public_inputs = opt_constructor_public_inputs.remove_optionality(); - - Prover constructor_prover = constructor_composer.create_prover(); - NT::Proof constructor_proof = constructor_prover.construct_proof(); - - // auto constructor_hash_real = - // NT::compress({ function_data.hash(), - // NT::compress(constructor_public_inputs.args, CONSTRUCTOR_ARGS), - // constructor_vk_hash }, - // CONSTRUCTOR); - // auto contract_address_real = NT::compress({ msg_sender, - // contract_deployment_data.contract_address_salt, - // contract_deployment_data.function_tree_root, - // constructor_hash_real }, - // CONTRACT_ADDRESS); - - //*************************************************************************** - // We can create a TxRequest from some of the above data. Users must sign a TxRequest in order to give permission - // for a tx to take place - creating a SignedTxRequest. - //*************************************************************************** - - TxRequest constructor_tx_request = TxRequest{ - .from = tx_origin, - .to = new_contract_address, - .function_data = function_data, - .args = constructor_public_inputs.args, - .nonce = 0, - .tx_context = - TxContext{ - .is_fee_payment_tx = false, - .is_rebate_payment_tx = false, - .is_contract_deployment_tx = true, - .contract_deployment_data = contract_deployment_data, - }, - .chain_id = 1, - }; - - SignedTxRequest signed_constructor_tx_request = SignedTxRequest{ - .tx_request = constructor_tx_request, - - // .signature = TODO: need a method for signing a TxRequest. - }; - - //*************************************************************************** - // We mock a kernel circuit proof for the base case of kernel recursion (because even the first iteration of the - // kernel circuit expects to verify some previous kernel circuit). - //*************************************************************************** - - Composer mock_kernel_composer = Composer("../barretenberg/cpp/srs_db/ignition"); - - // TODO: we have a choice to make: - // Either the `end` state of the mock kernel's public inputs can be set equal to the public call we _want_ to - // verify in the first round of recursion, OR, we have some fiddly conditional logic in the circuit to ignore - // certain checks if we're handling the 'base case' of the recursion. - // I've chosen the former, for now. - const CallStackItem constructor_call_stack_item{ - .contract_address = constructor_tx_request.to, - - .function_data = constructor_tx_request.function_data, - - .public_inputs = constructor_public_inputs, - }; - - std::array initial_kernel_private_call_stack{}; - initial_kernel_private_call_stack[0] = constructor_call_stack_item.hash(); - - // Some test data: - auto mock_kernel_public_inputs = PublicInputs(); - mock_kernel_public_inputs.end.private_call_stack = initial_kernel_private_call_stack, - mock_kernel_public_inputs.constants.old_tree_roots.private_data_tree_root = - constructor_public_inputs.historic_private_data_tree_root; - mock_kernel_public_inputs.constants.tx_context = constructor_tx_request.tx_context; - mock_kernel_public_inputs.is_private = true; - - mock_kernel_circuit(mock_kernel_composer, mock_kernel_public_inputs); - - Prover mock_kernel_prover = mock_kernel_composer.create_prover(); - NT::Proof mock_kernel_proof = mock_kernel_prover.construct_proof(); - // info("\nmock_kernel_proof: ", mock_kernel_proof.proof_data); - - std::shared_ptr mock_kernel_vk = mock_kernel_composer.compute_verification_key(); - - //*************************************************************************** - // Now we can execute and prove the first kernel iteration, with all the data generated above: - // - app proof, public inputs, etc. - // - mock kernel proof, public inputs, etc. - //*************************************************************************** - - // NOTE: WE DON'T USE A COMPOSER HERE, SINCE WE WANT TO TEST THE `native_private_kernel_circuit` - // Composer private_kernel_composer = Composer("../barretenberg/cpp/srs_db/ignition"); - - PrivateInputs private_inputs = PrivateInputs{ - .signed_tx_request = signed_constructor_tx_request, - - .previous_kernel = - PreviousKernelData{ - .public_inputs = mock_kernel_public_inputs, - .proof = mock_kernel_proof, - .vk = mock_kernel_vk, - }, - - .private_call = - PrivateCallData{ - .call_stack_item = constructor_call_stack_item, - .private_call_stack_preimages = constructor_ctx.get_private_call_stack_items(), - - .proof = constructor_proof, - .vk = constructor_vk, - - // .function_leaf_membership_witness TODO - // .contract_leaf_membership_witness TODO - - .portal_contract_address = new_portal_contract_address, - }, - }; - DummyComposer composer = DummyComposer(); - PublicInputs private_kernel_circuit_public_inputs = native_private_kernel_circuit(composer, private_inputs); + validate_deployed_contract_address(private_inputs, public_inputs); } +/** + * @brief Some private circuit simulation checked against its results via cbinds + */ TEST(private_kernel_tests, test_create_proof_cbinds) { - //*************************************************************************** - // Some private NATIVE mocked proof (`constructor`, in this case) - // and the cbind to generate valid outputs - //*************************************************************************** - - const NT::address new_contract_address = 12345; - // const NT::fr new_contract_leaf_index = 1; - const NT::fr new_portal_contract_address = 23456; - - const NT::fr msg_sender_private_key = 123456789; - const NT::address msg_sender = - NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); - const NT::address tx_origin = msg_sender; + NT::fr const& arg0 = 5; + NT::fr const& arg1 = 1; + NT::fr const& arg2 = 999; + std::vector args_vec = { arg0, arg1, arg2 }; - Composer constructor_composer = Composer("../barretenberg/cpp/srs_db/ignition"); - DB db; + // first run actual simulation to get public inputs + auto const& private_inputs = do_private_call_get_kernel_inputs(true, constructor, args_vec); + DummyComposer composer; + auto const& public_inputs = native_private_kernel_circuit(composer, private_inputs); - FunctionData function_data{ - .function_selector = 1, // TODO: deduce this from the contract, somehow. - .is_private = true, - .is_constructor = true, - }; - - CallContext call_context{ - .msg_sender = msg_sender, - .storage_contract_address = new_contract_address, - .portal_contract_address = 0, - .is_delegate_call = false, - .is_static_call = false, - .is_contract_deployment = true, - }; - - NativeOracle constructor_oracle = - NativeOracle(db, new_contract_address, function_data, call_context, msg_sender_private_key); - OracleWrapper constructor_oracle_wrapper = OracleWrapper(constructor_composer, constructor_oracle); - - FunctionExecutionContext constructor_ctx(constructor_composer, constructor_oracle_wrapper); - - auto arg0 = NT::fr(5); - auto arg1 = NT::fr(1); - auto arg2 = NT::fr(999); - - OptionalPrivateCircuitPublicInputs opt_constructor_public_inputs = - constructor(constructor_ctx, arg0, arg1, arg2); - - ContractDeploymentData contract_deployment_data{ - .constructor_vk_hash = 0, // TODO actually get this? - .function_tree_root = 0, // TODO actually get this? - .contract_address_salt = 42, - .portal_contract_address = new_portal_contract_address, - }; - opt_constructor_public_inputs.contract_deployment_data = contract_deployment_data; - - PrivateCircuitPublicInputs constructor_public_inputs = opt_constructor_public_inputs.remove_optionality(); - - Prover constructor_prover = constructor_composer.create_prover(); - NT::Proof constructor_proof = constructor_prover.construct_proof(); - // info("\nconstructor_proof: ", constructor_proof.proof_data); - - std::shared_ptr constructor_vk = constructor_composer.compute_verification_key(); - - //*************************************************************************** - // We can create a TxRequest from some of the above data. Users must sign a TxRequest in order to give permission - // for a tx to take place - creating a SignedTxRequest. - //*************************************************************************** - - TxRequest constructor_tx_request = TxRequest{ - .from = tx_origin, - .to = new_contract_address, - .function_data = function_data, - .args = constructor_public_inputs.args, - .nonce = 0, - .tx_context = - TxContext{ - .is_fee_payment_tx = false, - .is_rebate_payment_tx = false, - .is_contract_deployment_tx = false, - .contract_deployment_data = contract_deployment_data, - }, - .chain_id = 1, - }; - - SignedTxRequest signed_constructor_tx_request = SignedTxRequest{ - .tx_request = constructor_tx_request, - - // .signature = TODO: need a method for signing a TxRequest. - }; + // serialize expected public inputs for later comparison + std::vector expected_public_inputs_vec; + write(expected_public_inputs_vec, public_inputs); //*************************************************************************** - // We mock a kernel circuit proof for the base case of kernel recursion (because even the first iteration of the - // kernel circuit expects to verify some previous kernel circuit). + // Now run the simulate/prove cbinds to make sure their outputs match //*************************************************************************** - - Composer mock_kernel_composer = Composer("../barretenberg/cpp/srs_db/ignition"); - - // TODO: we have a choice to make: - // Either the `end` state of the mock kernel's public inputs can be set equal to the public call we _want_ to - // verify in the first round of recursion, OR, we have some fiddly conditional logic in the circuit to ignore - // certain checks if we're handling the 'base case' of the recursion. - // I've chosen the former, for now. - const CallStackItem constructor_call_stack_item{ - .contract_address = constructor_tx_request.to, - - .function_data = constructor_tx_request.function_data, - - .public_inputs = constructor_public_inputs, - }; - - std::array initial_kernel_private_call_stack{}; - initial_kernel_private_call_stack[0] = constructor_call_stack_item.hash(); - // TODO might be able to get rid of proving key buffer uint8_t const* pk_buf; - size_t pk_size = private_kernel__init_proving_key(&pk_buf); - info("Proving key size: ", pk_size); + private_kernel__init_proving_key(&pk_buf); + // info("Proving key size: ", pk_size); // TODO might be able to get rid of verification key buffer - uint8_t const* vk_buf; - size_t vk_size = private_kernel__init_verification_key(pk_buf, &vk_buf); - info("Verification key size: ", vk_size); + // uint8_t const* vk_buf; + // size_t vk_size = private_kernel__init_verification_key(pk_buf, &vk_buf); + // info("Verification key size: ", vk_size); std::vector signed_constructor_tx_request_vec; - write(signed_constructor_tx_request_vec, signed_constructor_tx_request); - - PrivateCallData private_constructor_call = PrivateCallData{ - .call_stack_item = constructor_call_stack_item, - .private_call_stack_preimages = constructor_ctx.get_private_call_stack_items(), - - .proof = constructor_proof, - .vk = constructor_vk, + write(signed_constructor_tx_request_vec, private_inputs.signed_tx_request); - // .function_leaf_membership_witness TODO - // .contract_leaf_membership_witness TODO - - .portal_contract_address = new_portal_contract_address, - }; std::vector private_constructor_call_vec; - write(private_constructor_call_vec, private_constructor_call); + write(private_constructor_call_vec, private_inputs.private_call); - uint8_t const* proof_data; - uint8_t const* public_inputs; - info("Simulating to generate public inputs..."); + uint8_t const* proof_data_buf; + uint8_t const* public_inputs_buf; + // info("Simulating to generate public inputs..."); size_t public_inputs_size = private_kernel__sim(signed_constructor_tx_request_vec.data(), nullptr, // no previous kernel on first iteration private_constructor_call_vec.data(), true, // first iteration - &public_inputs); + &public_inputs_buf); - info("Proving"); + // TODO better equality check + // for (size_t i = 0; i < public_inputs_size; i++) + for (size_t i = 0; i < 10; i++) { + ASSERT_EQ(public_inputs_buf[i], expected_public_inputs_vec[i]); + } + (void)public_inputs_size; + // info("Proving"); size_t proof_data_size = private_kernel__prove(signed_constructor_tx_request_vec.data(), - nullptr, + nullptr, // no previous kernel on first iteration private_constructor_call_vec.data(), pk_buf, true, // first iteration - &proof_data); - info("Proof size: ", proof_data_size); - info("PublicInputs size: ", public_inputs_size); + &proof_data_buf); + (void)proof_data_size; + // info("Proof size: ", proof_data_size); + // info("PublicInputs size: ", public_inputs_size); free((void*)pk_buf); - free((void*)vk_buf); - free((void*)proof_data); - free((void*)public_inputs); + // free((void*)vk_buf); + free((void*)proof_data_buf); + free((void*)public_inputs_buf); } +/** + * @brief Test this dummy cbind + */ TEST(private_kernel_tests, test_dummy_previous_kernel_cbind) { uint8_t const* cbind_previous_kernel_buf; - size_t cbind_buf_size = private_kernel__dummy_previous_kernel(&cbind_previous_kernel_buf); + size_t const cbind_buf_size = private_kernel__dummy_previous_kernel(&cbind_previous_kernel_buf); - PreviousKernelData previous_kernel = utils::dummy_previous_kernel_with_vk_proof(); + auto const& previous_kernel = utils::dummy_previous_kernel_with_vk_proof(); std::vector expected_vec; write(expected_vec, previous_kernel); @@ -1125,12 +609,12 @@ TEST(private_kernel_tests, test_dummy_previous_kernel_cbind) // would be best if we could just check struct equality or check // equality of an entire memory region (same as other similar TODOs // in other test files) - if (cbind_buf_size > 10) { - // for (size_t 0; i < public_inputs_size; i++) { - for (size_t i = 0; i < 10; i++) { - ASSERT_EQ(cbind_previous_kernel_buf[i], expected_vec[i]); - } + // TODO better equality check + // for (size_t i = 0; i < cbind_buf_size; i++) { + for (size_t i = 0; i < 10; i++) { + ASSERT_EQ(cbind_previous_kernel_buf[i], expected_vec[i]); } + (void)cbind_buf_size; } } // namespace aztec3::circuits::kernel::private_kernel diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit.cpp index d9265ffeabc..781856bccc2 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit.cpp @@ -14,7 +14,6 @@ namespace aztec3::circuits::kernel::private_kernel { -using aztec3::circuits::abis::FunctionLeafPreimage; using aztec3::circuits::abis::private_kernel::ContractLeafPreimage; using aztec3::circuits::abis::private_kernel::NewContractData; using aztec3::circuits::abis::private_kernel::PrivateInputs; @@ -29,7 +28,8 @@ using DummyComposer = aztec3::utils::DummyComposer; using aztec3::circuits::compute_constructor_hash; using aztec3::circuits::compute_contract_address; -using aztec3::circuits::root_from_sibling_path; +using aztec3::circuits::contract_tree_root_from_siblings; +using aztec3::circuits::function_tree_root_from_siblings; // using plonk::stdlib::merkle_tree:: @@ -138,44 +138,34 @@ void contract_logic(DummyComposer& composer, PrivateInputs const& private_in * - Hash the contract_leaf with the contract_leaf's sibling_path to get the contract_tree_root */ - const auto function_leaf_preimage = FunctionLeafPreimage{ - .function_selector = private_inputs.private_call.call_stack_item.function_data.function_selector, - .is_private = true, - .vk_hash = private_call_vk_hash, - .acir_hash = private_inputs.private_call.acir_hash, - }; - - const auto function_leaf = function_leaf_preimage.hash(); - - const auto& function_leaf_index = private_inputs.private_call.function_leaf_membership_witness.leaf_index; - const auto& function_leaf_sibling_path = private_inputs.private_call.function_leaf_membership_witness.sibling_path; - - const auto& function_tree_root = - root_from_sibling_path(function_leaf, function_leaf_index, function_leaf_sibling_path); - - const ContractLeafPreimage contract_leaf_preimage{ - storage_contract_address, - portal_contract_address, - function_tree_root, - }; - - const auto contract_leaf = contract_leaf_preimage.hash(); - - auto& contract_leaf_index = private_inputs.private_call.contract_leaf_membership_witness.leaf_index; - auto& contract_leaf_sibling_path = private_inputs.private_call.contract_leaf_membership_witness.sibling_path; - - const auto& computed_contract_tree_root = - root_from_sibling_path(contract_leaf, contract_leaf_index, contract_leaf_sibling_path); - - auto& purported_contract_tree_root = + // ensure that historic/purported contract tree root matches the one in previous kernel + auto const& purported_contract_tree_root = private_inputs.private_call.call_stack_item.public_inputs.historic_contract_tree_root; - composer.do_assert(computed_contract_tree_root == purported_contract_tree_root, - "computed_contract_tree_root doesn't match purported_contract_tree_root"); - - auto& previous_kernel_contract_tree_root = + auto const& previous_kernel_contract_tree_root = private_inputs.previous_kernel.public_inputs.constants.old_tree_roots.contract_tree_root; composer.do_assert(purported_contract_tree_root == previous_kernel_contract_tree_root, "purported_contract_tree_root doesn't match previous_kernel_contract_tree_root"); + + // The logic below ensures that the contract exists in the contracts tree + if (!is_contract_deployment) { + auto const& computed_function_tree_root = function_tree_root_from_siblings( + private_inputs.private_call.call_stack_item.function_data.function_selector, + true, // is_private + private_call_vk_hash, + private_inputs.private_call.acir_hash, + private_inputs.private_call.function_leaf_membership_witness.leaf_index, + private_inputs.private_call.function_leaf_membership_witness.sibling_path); + + auto const& computed_contract_tree_root = contract_tree_root_from_siblings( + computed_function_tree_root, + storage_contract_address, + portal_contract_address, + private_inputs.private_call.contract_leaf_membership_witness.leaf_index, + private_inputs.private_call.contract_leaf_membership_witness.sibling_path); + + composer.do_assert(computed_contract_tree_root == purported_contract_tree_root, + "computed_contract_tree_root doesn't match purported_contract_tree_root"); + } } void update_end_values(DummyComposer& composer, @@ -351,6 +341,8 @@ PublicInputs native_private_kernel_circuit(DummyComposer& composer, PrivateI update_end_values(composer, private_inputs, public_inputs); + contract_logic(composer, private_inputs, public_inputs); + // We'll skip any verification in this native implementation, because for a Local Developer Testnet, there won't // _be_ a valid proof to verify!!! auto aggregation_object = verify_proofs(composer, // private_inputs, From f7c09debcff4c5b2595c613ba95a66c9de1e8d2f Mon Sep 17 00:00:00 2001 From: Maddiaa <47148561+cheethas@users.noreply.github.com> Date: Fri, 14 Apr 2023 12:15:03 -0700 Subject: [PATCH 164/166] fix: nullifier tests (#249) * fixes * fix: more possible regression tests * fix: remove logs * fix: remove more logs * clean: reuse test code * clean * rm done todo --------- Co-authored-by: cheethas --- .../src/aztec3/circuits/rollup/base/.test.cpp | 59 +++++++++++++++++++ .../base/native_base_rollup_circuit.cpp | 15 +++-- .../base/nullifier_tree_testing_harness.cpp | 22 +++++-- .../base/nullifier_tree_testing_harness.hpp | 2 + .../src/aztec3/circuits/rollup/base/utils.cpp | 1 - 5 files changed, 87 insertions(+), 12 deletions(-) diff --git a/circuits/cpp/src/aztec3/circuits/rollup/base/.test.cpp b/circuits/cpp/src/aztec3/circuits/rollup/base/.test.cpp index 52eda38267b..d0f967a5556 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/base/.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/base/.test.cpp @@ -507,6 +507,65 @@ TEST_F(base_rollup_tests, nullifier_tree_regression) ASSERT_EQ(outputs.end_nullifier_tree_snapshot, nullifier_tree_end_snapshot); } +void perform_standard_nullifier_test(std::array new_nullifiers) +{ + // Regression test caught when testing the typescript nullifier tree implementation + DummyComposer composer = DummyComposer(); + BaseRollupInputs empty_inputs = dummy_base_rollup_inputs_with_vk_proof(); + + std::vector initial_values(7, 0); + for (size_t i = 0; i < 7; i++) { + initial_values[i] = i + 1; + } + + std::tuple, AppendOnlyTreeSnapshot> inputs_and_snapshots = + utils::generate_nullifier_tree_testing_values(empty_inputs, new_nullifiers, initial_values); + BaseRollupInputs testing_inputs = std::get<0>(inputs_and_snapshots); + AppendOnlyTreeSnapshot nullifier_tree_start_snapshot = std::get<1>(inputs_and_snapshots); + AppendOnlyTreeSnapshot nullifier_tree_end_snapshot = std::get<2>(inputs_and_snapshots); + + /** + * RUN + */ + + // Run the circuit + BaseOrMergeRollupPublicInputs outputs = + aztec3::circuits::rollup::native_base_rollup::base_rollup_circuit(composer, testing_inputs); + + /** + * ASSERT + */ + // Start state + ASSERT_EQ(outputs.start_nullifier_tree_snapshot, nullifier_tree_start_snapshot); + + // End state + ASSERT_EQ(outputs.end_nullifier_tree_snapshot, nullifier_tree_end_snapshot); +} + +// Another regression test with values from a failing packages test +TEST_F(base_rollup_tests, nullifier_tree_regression_2) +{ + // Regression test caught when testing the typescript nullifier tree implementation + std::array new_nullifiers = { 0 }; + new_nullifiers[0] = uint256_t("2a7d956c1365d259646d2d85babe1abb793bb8789e98df7e2336a29a0c91fd01"); + new_nullifiers[1] = uint256_t("236bf2d113f9ffee89df1a7a04890c9ad3583c6773eb9cdec484184f66abd4c6"); + new_nullifiers[4] = uint256_t("2f5c8a1ee33c7104b244e22a3e481637cd501c9eae868cfab6b16e3b4ef3d635"); + new_nullifiers[5] = uint256_t("0c484a20780e31747cf9f4f6803986525ed98ef587f5155a1c50689c2cad10ae"); + + perform_standard_nullifier_test(new_nullifiers); +} + +TEST_F(base_rollup_tests, nullifier_tree_regression_3) +{ + std::array new_nullifiers = { 0 }; + new_nullifiers[0] = uint256_t("0740a17aa6437e71836d2adcdcb3f52879bb869cdd9c8fb8dc39a12846cd17f2"); + new_nullifiers[1] = uint256_t("282e0e2f38310a7c7c98b636830b66f3276294560e26ef2499da10892f00af8f"); + new_nullifiers[4] = uint256_t("0f117936e888bd3befb4435f4d65300d25609e95a3d1563f62ef7e58c294f578"); + new_nullifiers[5] = uint256_t("0fcb3908cb15ebf8bab276f5df17524d3b676c8655234e4350953c387fffcdd7"); + + perform_standard_nullifier_test(new_nullifiers); +} + // Note leaving this test here as there are no negative tests, even though it no longer passes TEST_F(base_rollup_tests, new_nullifier_tree_sparse_attack) { diff --git a/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp b/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp index 47c1aa671f7..6b69b24ae32 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp @@ -313,11 +313,15 @@ AppendOnlySnapshot check_nullifier_tree_non_membership_and_insert_to_tree(DummyC // check previous nullifier leaves // TODO: this is a hack, and insecure, we need to fix this bool matched = false; - for (size_t k = 0; k < nullifier_index; k++) { - if ((uint256_t(nullifier_insertion_subtree[k].nextValue) > uint256_t(nullifier) && - uint256_t(nullifier_insertion_subtree[k].value) < uint256_t(nullifier)) || - (nullifier_insertion_subtree[k].nextValue == 0 && - nullifier_insertion_subtree[k].nextIndex == 0)) { + + for (size_t k = 0; k < nullifier_index && !matched; k++) { + if (nullifier_insertion_subtree[k].value == 0) { + continue; + } + + if ((uint256_t(nullifier_insertion_subtree[k].value) < uint256_t(nullifier)) && + (uint256_t(nullifier_insertion_subtree[k].nextValue) > uint256_t(nullifier) || + nullifier_insertion_subtree[k].nextValue == 0)) { matched = true; // Update pointers @@ -329,6 +333,7 @@ AppendOnlySnapshot check_nullifier_tree_non_membership_and_insert_to_tree(DummyC nullifier_insertion_subtree[k].nextValue = nullifier; } } + // if not matched, our subtree will misformed - we must reject composer.do_assert(matched, "Nullifier subtree is malformed"); diff --git a/circuits/cpp/src/aztec3/circuits/rollup/base/nullifier_tree_testing_harness.cpp b/circuits/cpp/src/aztec3/circuits/rollup/base/nullifier_tree_testing_harness.cpp index 3c44dd7f92b..87806528439 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/base/nullifier_tree_testing_harness.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/base/nullifier_tree_testing_harness.cpp @@ -12,11 +12,13 @@ NullifierMemoryTreeTestingHarness::NullifierMemoryTreeTestingHarness(size_t dept {} // Check for a larger value in an array -bool check_has_lesser_value(std::vector const& values, fr const& value) +bool check_has_less_than(std::vector const& values, fr const& value) { + // Must perform comparisons on integers uint256_t value_as_uint = uint256_t(value); for (auto const& v : values) { + // info(v, " ", uint256_t(v) < value_as_uint); if (uint256_t(v) < value_as_uint) { return true; } @@ -108,6 +110,7 @@ NullifierMemoryTreeTestingHarness::circuit_prep_batch_insert(std::vector con sibling_paths.push_back(empty_sp); low_nullifier_indexes.push_back(empty_index); low_nullifiers.push_back(empty_leaf); + continue; } // If the low_nullifier node has been touched this sub tree insertion, we provide a dummy sibling path @@ -115,13 +118,12 @@ NullifierMemoryTreeTestingHarness::circuit_prep_batch_insert(std::vector con // inserted before it If it has not been touched, we provide a sibling path then update the nodes pointers auto prev_nodes = touched_nodes.find(current); - bool has_lesser_value = false; + bool has_less_than = false; if (prev_nodes != touched_nodes.end()) { - has_lesser_value = check_has_lesser_value(prev_nodes->second, new_value); + has_less_than = check_has_less_than(prev_nodes->second, new_value); } // If there is a lower value in the tree, we need to check the current low nullifiers for one that can be used - // if (current == 0 || has_lesser_value) { - if (has_lesser_value) { + if (has_less_than) { for (size_t j = 0; j < pending_insertion_tree.size(); ++j) { // Skip checking empty values @@ -171,7 +173,8 @@ NullifierMemoryTreeTestingHarness::circuit_prep_batch_insert(std::vector con .nextValue = new_value }; // Update the old leaf in the tree - update_element(current, new_leaf.hash()); + // update old value in tree + update_element_in_place(current, new_leaf); } } @@ -179,6 +182,13 @@ NullifierMemoryTreeTestingHarness::circuit_prep_batch_insert(std::vector con return std::make_tuple(low_nullifiers, sibling_paths, low_nullifier_indexes); } +void NullifierMemoryTreeTestingHarness::update_element_in_place(size_t index, nullifier_leaf leaf) +{ + // Find the leaf with the value closest and less than `value` + this->leaves_[index] = leaf; + update_element(index, leaf.hash()); +} + std::pair NullifierMemoryTreeTestingHarness::find_lower(fr const& value) { size_t current; diff --git a/circuits/cpp/src/aztec3/circuits/rollup/base/nullifier_tree_testing_harness.hpp b/circuits/cpp/src/aztec3/circuits/rollup/base/nullifier_tree_testing_harness.hpp index 4a8a8411b4c..3ded991dd36 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/base/nullifier_tree_testing_harness.hpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/base/nullifier_tree_testing_harness.hpp @@ -38,6 +38,8 @@ class NullifierMemoryTreeTestingHarness : public proof_system::plonk::stdlib::me // Current size of the tree fr size() { return leaves_.size(); } + void update_element_in_place(size_t index, nullifier_leaf leaf); + // Get all of the sibling paths and low nullifier values required to craft an non membership / inclusion proofs std::tuple, std::vector>, std::vector> circuit_prep_batch_insert(std::vector const& values); diff --git a/circuits/cpp/src/aztec3/circuits/rollup/base/utils.cpp b/circuits/cpp/src/aztec3/circuits/rollup/base/utils.cpp index d4a0da2689a..7187277ce47 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/base/utils.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/base/utils.cpp @@ -159,7 +159,6 @@ generate_nullifier_tree_testing_values(BaseRollupInputs rollupInputs, } insertion_values.push_back(insertion_val); reference_tree.append_value(insertion_val); - auto hashes = reference_tree.get_hashes(); } // Get the hash paths etc from the insertion values From ec1b5045d7427540054aa82e198d3d338ab743bb Mon Sep 17 00:00:00 2001 From: ludamad Date: Mon, 17 Apr 2023 15:22:53 -0400 Subject: [PATCH 165/166] chore: post merge fixup --- .circleci/config.yml | 109 ++++++++++- build_manifest.json | 215 ++++++---------------- circuits/.circleci/config.yml | 199 -------------------- circuits/.github/pull_request_template.md | 33 ---- circuits/.gitmodules | 7 - circuits/build_manifest.json | 26 --- circuits/build_manifest.sh | 14 -- 7 files changed, 154 insertions(+), 449 deletions(-) delete mode 100644 circuits/.circleci/config.yml delete mode 100644 circuits/.github/pull_request_template.md delete mode 100644 circuits/.gitmodules delete mode 100644 circuits/build_manifest.json delete mode 100644 circuits/build_manifest.sh diff --git a/.circleci/config.yml b/.circleci/config.yml index d8895d792d1..939d77a93c4 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -52,7 +52,7 @@ checkout: &checkout git fetch --depth 50 --filter=blob:none origin $CIRCLE_SHA1 git checkout FETCH_HEAD # Initialize submodules recursively - git submodule update --init --recursive circuits build-system + git submodule update --init --recursive # Called setup_env to setup a bunch of global variables used throughout the rest of the build process. # It takes the required CCI environment variables as inputs, and gives them normalised names for the rest of @@ -62,8 +62,26 @@ setup_env: &setup_env name: "Setup environment" command: ./build-system/scripts/setup_env "$CIRCLE_SHA1" "$CIRCLE_TAG" "$CIRCLE_JOB" "$CIRCLE_REPOSITORY_URL" "$CIRCLE_BRANCH" +# This step is used to save logs from various barretenberg test to the workspace so that they can be used later to parse benchmark values out of them +save_logs: &save_logs + persist_to_workspace: + root: /tmp/test-logs + paths: + - ./* + jobs: - wasm-linux-clang: + circuits-wasm-linux-clang: + docker: + - image: aztecprotocol/alpine-build-image + resource_class: small + steps: + - *checkout + - *setup_env + - run: + name: "Build" + command: cond_spot_run_build circuits-wasm-linux-clang 64 + + circuits-wasm-linux-clang-assert: docker: - image: aztecprotocol/alpine-build-image resource_class: small @@ -72,7 +90,65 @@ jobs: - *setup_env - run: name: "Build" - command: cond_spot_run_build aztec3-circuits-wasm-linux-clang 64 + command: cond_spot_run_build circuits-wasm-linux-clang-assert 64 + + circuits-x86_64-linux-clang: + docker: + - image: aztecprotocol/alpine-build-image + resource_class: small + steps: + - *checkout + - *setup_env + - run: + name: "Build" + command: cond_spot_run_build circuits-x86_64-linux-clang 64 + + circuits-x86_64-linux-clang-assert: + docker: + - image: aztecprotocol/alpine-build-image + resource_class: small + steps: + - *checkout + - *setup_env + - run: + name: "Build" + command: cond_spot_run_build circuits-x86_64-linux-clang-assert 64 + + circuits-wasm-tests: + docker: + - image: aztecprotocol/alpine-build-image + resource_class: small + steps: + - *checkout + - *setup_env + - run: + name: "Test" + command: cond_spot_run_tests circuits-wasm-linux-clang-assert 1 a3-tests USE_WASM_TIME + - *save_logs + + circuits-tests: + docker: + - image: aztecprotocol/alpine-build-image + resource_class: small + steps: + - *checkout + - *setup_env + - run: + name: "Test" + command: cond_spot_run_tests circuits-x86_64-linux-clang-assert 1 a3-tests + - *save_logs + + #circuits--tests: + # docker: + # - image: aztecprotocol/alpine-build-image + # resource_class: small + # steps: + # - *checkout + # - *setup_env + # - run: + # name: 'Test' + # command: cond_spot_run_tests circuits-x86_64-linux-clang-assert 1 _tests + # - *save_logs yarn-project-base: machine: @@ -113,7 +189,7 @@ jobs: name: "Build and test" command: build foundation - aztec-js: + aztec-js: machine: image: ubuntu-2004:202010-01 resource_class: large @@ -211,7 +287,7 @@ jobs: - run: name: "Build and test" command: build archiver - + aztec-rpc: machine: image: ubuntu-2004:202010-01 @@ -319,17 +395,31 @@ e2e_test: &e2e_test requires: - e2e-join <<: *defaults - +circuits-wasm-test: &circuits-wasm-test + requires: + - circuits-wasm-linux-clang-assert + <<: *defaults +circuits-test: &circuits-test + requires: + - circuits-x86_64-linux-clang-assert + <<: *defaults workflows: system: when: equal: [system, << pipeline.parameters.workflow >>] jobs: - - wasm-linux-clang: - <<: *defaults + - circuits-wasm-linux-clang: *defaults + - circuits-wasm-linux-clang-assert: *defaults + - circuits-x86_64-linux-clang: *defaults + - circuits-x86_64-linux-clang-assert: *defaults + - circuits-wasm-tests: + <<: *circuits-wasm-test + - circuits-tests: + <<: *circuits-test + #- aztec3-circuit--tests: *circuits-test - yarn-project-base: requires: - - wasm-linux-clang + - circuits-wasm-linux-clang <<: *defaults - ethereum-js: *yarn_project @@ -356,7 +446,6 @@ workflows: - noir-contracts - foundation <<: *defaults - - e2e-deploy-contract: *e2e_test - e2e-zk-token-contract: *e2e_test - e2e-block-building: *e2e_test diff --git a/build_manifest.json b/build_manifest.json index 1cb9712426a..07fc52ca7ef 100644 --- a/build_manifest.json +++ b/build_manifest.json @@ -1,46 +1,39 @@ { - "aztec3-circuits-wasm-linux-clang": { + "circuits-wasm-linux-clang": { "buildDir": "circuits/cpp", "dockerfile": "dockerfiles/Dockerfile.wasm-linux-clang", - "rebuildPatterns": [ - "^circuits/" - ], + "rebuildPatterns": ["^circuits/"], + "dependencies": [] + }, + "circuits-wasm-linux-clang-assert": { + "buildDir": "circuits/cpp", + "dockerfile": "dockerfiles/Dockerfile.wasm-linux-clang-assert", + "rebuildPatterns": ["^circuits/"], "dependencies": [] }, "circuits-x86_64-linux-clang": { - "buildDir": "circuits", + "buildDir": "circuits/cpp", "dockerfile": "dockerfiles/Dockerfile.x86_64-linux-clang", - "rebuildPatterns": [ - "^circuits/" - ], + "rebuildPatterns": ["^circuits/"], "dependencies": [] }, "circuits-x86_64-linux-clang-assert": { - "buildDir": "circuits", + "buildDir": "circuits/cpp", "dockerfile": "dockerfiles/Dockerfile.x86_64-linux-clang-assert", - "rebuildPatterns": [ - "^circuits/" - ], + "rebuildPatterns": ["^circuits/"], "dependencies": [] }, "circuits-x86_64-linux-gcc": { - "buildDir": "circuits", + "buildDir": "circuits/cpp", "dockerfile": "dockerfiles/Dockerfile.x86_64-linux-gcc", - "rebuildPatterns": [ - "^circuits/" - ], + "rebuildPatterns": ["^circuits/"], "dependencies": [] }, "l1-contracts": { "buildDir": "l1-contracts", "dockerfile": "Dockerfile", - "rebuildPatterns": [ - "^l1-contracts/" - ], - "dependencies": [ - "ethereum.js", - "foundation" - ] + "rebuildPatterns": ["^l1-contracts/"], + "dependencies": ["ethereum.js", "foundation"] }, "yarn-project-base": { "buildDir": "yarn-project", @@ -49,17 +42,13 @@ "^yarn-project/yarn-project-base/", "^yarn-project/yarn.lock" ], - "dependencies": [ - "aztec3-circuits-wasm-linux-clang" - ] + "dependencies": ["circuits-wasm-linux-clang"] }, "acir-simulator": { "buildDir": "yarn-project", "projectDir": "yarn-project/acir-simulator", "dockerfile": "acir-simulator/Dockerfile", - "rebuildPatterns": [ - "^yarn-project/acir-simulator/" - ], + "rebuildPatterns": ["^yarn-project/acir-simulator/"], "dependencies": [ "barretenberg.js", "circuits.js", @@ -72,34 +61,21 @@ "buildDir": "yarn-project", "projectDir": "yarn-project/archiver", "dockerfile": "archiver/Dockerfile", - "rebuildPatterns": [ - "^yarn-project/archiver/" - ], - "dependencies": [ - "ethereum.js", - "foundation", - "l1-contracts", - "types" - ] + "rebuildPatterns": ["^yarn-project/archiver/"], + "dependencies": ["ethereum.js", "foundation", "l1-contracts", "types"] }, "aztec-cli": { "buildDir": "yarn-project", "projectDir": "yarn-project/aztec-cli", "dockerfile": "aztec-cli/Dockerfile", - "rebuildPatterns": [ - "^yarn-project/aztec-cli/" - ], - "dependencies": [ - "foundation" - ] + "rebuildPatterns": ["^yarn-project/aztec-cli/"], + "dependencies": ["foundation"] }, "aztec-rpc": { "buildDir": "yarn-project", "projectDir": "yarn-project/aztec-rpc", "dockerfile": "aztec-rpc/Dockerfile", - "rebuildPatterns": [ - "^yarn-project/aztec-rpc/" - ], + "rebuildPatterns": ["^yarn-project/aztec-rpc/"], "dependencies": [ "acir-simulator", "aztec-node", @@ -115,48 +91,28 @@ "buildDir": "yarn-project", "projectDir": "yarn-project/aztec.js", "dockerfile": "aztec.js/Dockerfile", - "rebuildPatterns": [ - "^yarn-project/aztec.js/" - ], - "dependencies": [ - "aztec-rpc", - "circuits.js", - "foundation", - "noir-contracts" - ] + "rebuildPatterns": ["^yarn-project/aztec.js/"], + "dependencies": ["aztec-rpc", "circuits.js", "foundation", "noir-contracts"] }, "barretenberg.js": { "buildDir": "yarn-project", "projectDir": "yarn-project/barretenberg.js", "dockerfile": "barretenberg.js/Dockerfile", - "rebuildPatterns": [ - "^yarn-project/barretenberg.js/" - ], - "dependencies": [ - "foundation", - "yarn-project-base" - ] + "rebuildPatterns": ["^yarn-project/barretenberg.js/"], + "dependencies": ["foundation", "yarn-project-base"] }, "circuits.js": { "buildDir": "yarn-project", "projectDir": "yarn-project/circuits.js", "dockerfile": "circuits.js/Dockerfile", - "rebuildPatterns": [ - "^yarn-project/circuits.js/" - ], - "dependencies": [ - "barretenberg.js", - "foundation", - "yarn-project-base" - ] + "rebuildPatterns": ["^yarn-project/circuits.js/"], + "dependencies": ["barretenberg.js", "foundation", "yarn-project-base"] }, "end-to-end": { "buildDir": "yarn-project", "projectDir": "yarn-project/end-to-end", "dockerfile": "end-to-end/Dockerfile", - "rebuildPatterns": [ - "^yarn-project/end-to-end/" - ], + "rebuildPatterns": ["^yarn-project/end-to-end/"], "dependencies": [ "aztec-node", "aztec.js", @@ -170,114 +126,70 @@ "buildDir": "yarn-project", "projectDir": "yarn-project/ethereum.js", "dockerfile": "ethereum.js/Dockerfile", - "rebuildPatterns": [ - "^yarn-project/ethereum.js/" - ], - "dependencies": [ - "foundation" - ] + "rebuildPatterns": ["^yarn-project/ethereum.js/"], + "dependencies": ["foundation"] }, "foundation": { "buildDir": "yarn-project", "projectDir": "yarn-project/foundation", "dockerfile": "foundation/Dockerfile", - "rebuildPatterns": [ - "^yarn-project/foundation/" - ], + "rebuildPatterns": ["^yarn-project/foundation/"], "dependencies": [] }, "kernel-prover": { "buildDir": "yarn-project", "projectDir": "yarn-project/kernel-prover", "dockerfile": "kernel-prover/Dockerfile", - "rebuildPatterns": [ - "^yarn-project/kernel-prover/" - ], - "dependencies": [ - "acir-simulator", - "circuits.js", - "foundation" - ] + "rebuildPatterns": ["^yarn-project/kernel-prover/"], + "dependencies": ["acir-simulator", "circuits.js", "foundation"] }, "key-store": { "buildDir": "yarn-project", "projectDir": "yarn-project/key-store", "dockerfile": "key-store/Dockerfile", - "rebuildPatterns": [ - "^yarn-project/key-store/" - ], - "dependencies": [ - "foundation" - ] + "rebuildPatterns": ["^yarn-project/key-store/"], + "dependencies": ["foundation"] }, "l2-block": { "buildDir": "yarn-project", "projectDir": "yarn-project/l2-block", "dockerfile": "l2-block/Dockerfile", - "rebuildPatterns": [ - "^yarn-project/l2-block/" - ], - "dependencies": [ - "circuits.js", - "foundation", - "l1-contracts", - "tx" - ] + "rebuildPatterns": ["^yarn-project/l2-block/"], + "dependencies": ["circuits.js", "foundation", "l1-contracts", "tx"] }, "merkle-tree": { "buildDir": "yarn-project", "projectDir": "yarn-project/merkle-tree", "dockerfile": "merkle-tree/Dockerfile", - "rebuildPatterns": [ - "^yarn-project/merkle-tree/" - ], - "dependencies": [ - "barretenberg.js", - "foundation" - ] + "rebuildPatterns": ["^yarn-project/merkle-tree/"], + "dependencies": ["barretenberg.js", "foundation"] }, "noir-contracts": { "buildDir": "yarn-project", "projectDir": "yarn-project/noir-contracts", "dockerfile": "noir-contracts/Dockerfile", - "rebuildPatterns": [ - "^yarn-project/noir-contracts/" - ], - "dependencies": [ - "foundation" - ] + "rebuildPatterns": ["^yarn-project/noir-contracts/"], + "dependencies": ["foundation"] }, "p2p": { "buildDir": "yarn-project", "projectDir": "yarn-project/p2p", "dockerfile": "p2p/Dockerfile", - "rebuildPatterns": [ - "^yarn-project/p2p/" - ], - "dependencies": [ - "circuits.js", - "foundation", - "types" - ] + "rebuildPatterns": ["^yarn-project/p2p/"], + "dependencies": ["circuits.js", "foundation", "types"] }, "prover-client": { "buildDir": "yarn-project", "projectDir": "yarn-project/prover-client", "dockerfile": "prover-client/Dockerfile", - "rebuildPatterns": [ - "^yarn-project/prover-client/" - ], - "dependencies": [ - "foundation" - ] + "rebuildPatterns": ["^yarn-project/prover-client/"], + "dependencies": ["foundation"] }, "aztec-node": { "buildDir": "yarn-project", "projectDir": "yarn-project/aztec-node", "dockerfile": "aztec-node/Dockerfile", - "rebuildPatterns": [ - "^yarn-project/aztec-node/" - ], + "rebuildPatterns": ["^yarn-project/aztec-node/"], "dependencies": [ "archiver", "barretenberg.js", @@ -295,9 +207,7 @@ "buildDir": "yarn-project", "projectDir": "yarn-project/sequencer-client", "dockerfile": "sequencer-client/Dockerfile", - "rebuildPatterns": [ - "^yarn-project/sequencer-client/" - ], + "rebuildPatterns": ["^yarn-project/sequencer-client/"], "dependencies": [ "circuits.js", "ethereum.js", @@ -313,36 +223,21 @@ "buildDir": "yarn-project", "projectDir": "yarn-project/tx", "dockerfile": "tx/Dockerfile", - "rebuildPatterns": [ - "^yarn-project/tx/" - ], - "dependencies": [ - "barretenberg.js", - "circuits.js", - "foundation", - "types" - ] + "rebuildPatterns": ["^yarn-project/tx/"], + "dependencies": ["barretenberg.js", "circuits.js", "foundation", "types"] }, "types": { "buildDir": "yarn-project", "projectDir": "yarn-project/types", "dockerfile": "types/Dockerfile", - "rebuildPatterns": [ - "^yarn-project/types/" - ], - "dependencies": [ - "circuits.js", - "foundation", - "l1-contracts" - ] + "rebuildPatterns": ["^yarn-project/types/"], + "dependencies": ["circuits.js", "foundation", "l1-contracts"] }, "world-state": { "buildDir": "yarn-project", "projectDir": "yarn-project/world-state", "dockerfile": "world-state/Dockerfile", - "rebuildPatterns": [ - "^yarn-project/world-state/" - ], + "rebuildPatterns": ["^yarn-project/world-state/"], "dependencies": [ "barretenberg.js", "circuits.js", @@ -351,4 +246,4 @@ "types" ] } -} \ No newline at end of file +} diff --git a/circuits/.circleci/config.yml b/circuits/.circleci/config.yml deleted file mode 100644 index 28e83ba795c..00000000000 --- a/circuits/.circleci/config.yml +++ /dev/null @@ -1,199 +0,0 @@ -# This config consists of currently 1 workflow. -# - system: The main Aztec 3 circuits and C++ -# -# The default workflow is system. To trigger the other workflows, trigger a workflow from CCI -# setting a string variable called `workflow` to another name. -# -# This file uses YAML anchors and aliases to prevent repetition of blocks of config: -# https://support.atlassian.com/bitbucket-cloud/docs/yaml-anchors/ -# -# Two primary anchors are checkout and setup_env, called as the first step of almost all jobs: -# - checkout: A custom checkout step to reduce the amount of data downloaded to improve speed. -# - setup_env: Sets up the common environment used by all build steps. -# -# Two CCI executors are used: -# - docker (small): Used only to launch external EC2 instances for big workloads. It's the cheapest option. -# - machine (large): Used for building in CCI itself. 4cpus, 15GB has the optimal power/cost ratio. -# -# The docker executor uses a custom image build in `build_image`. It's specifically streamlined for fast download -# with just enough tools to execute the build system, and launch EC2 instances etc. -# -# There are some `join` steps that are just noops. They are just used to produce cleaner graph rendering in CCI. - -version: 2.1 - -# This build step checks out the code from the repository. It has a hardcoded readonly key to allow the checkout. -# Initially it just fetches the repo metadata for the current commit hash to a depth of 50 commits. -# We need historical commit hashes to calculate diffs between previous and current commits. -# It then checks out the fetched head to actually download the data. -checkout: &checkout - run: - name: 'Checkout code' - command: | - cd $HOME - mkdir -p .ssh - chmod 0700 .ssh - ssh-keyscan -t rsa github.com >> .ssh/known_hosts - - # IF YOU'RE CHANGING THIS, YOU ALSO WANT TO CHANGE: build-system/remote_build/remote_build - # Shallow checkout this commit. - mkdir -p project - cd project - git init - git remote add origin $CIRCLE_REPOSITORY_URL - # Only download metadata when fetching. - git fetch --depth 50 --filter=blob:none origin $CIRCLE_SHA1 - git checkout FETCH_HEAD - # Pull in build-system submodule. - git submodule update --init build-system - -# This build step checks out the code from the benchmark-archive repository. -# The key is saved in CircleCi environment in base64 format. -# Initially it just fetches the latest version. -benchmark_add_keys: &benchmark_add_keys - run: - name: 'Add keys for getting the benchmark archive' - command: | - cd $HOME - mkdir -p .ssh - chmod 0700 .ssh - ssh-keyscan -t rsa github.com >> .ssh/known_hosts - - # A read-write key for updating the repository. - echo "$GITHUB_BENCMARK_REPOSITORY_SSH_KEY" | base64 -d > .ssh/id_ed25519 - - # This allows github to discern wich key to use. - echo "Host github.com - Hostname github.com - IdentityFile=/root/.ssh/id_rsa - - Host github.com-logs - Hostname github.com - IdentityFile=/root/.ssh/id_ed25519" > .ssh/config - - chmod 0600 .ssh/id_ed25519 - ssh-add .ssh/id_ed25519 - -# Called setup_env to setup a bunch of global variables used throughout the rest of the build process. -# It takes the required CCI environment variables as inputs, and gives them normalised names for the rest of -# the build process. This enables easy running of the build system external to CCI, as used for powerful EC2 builds. -setup_env: &setup_env - run: - name: 'Setup environment' - command: ./build-system/scripts/setup_env "$CIRCLE_SHA1" "$CIRCLE_TAG" "$CIRCLE_JOB" "$CIRCLE_REPOSITORY_URL" "$CIRCLE_BRANCH" - -# This step is used to save logs from various barretenberg test to the workspace so that they can be used later to parse benchmark values out of them -save_logs: &save_logs - persist_to_workspace: - root: /tmp/test-logs - paths: - - ./* - -jobs: - wasm-linux-clang: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small - steps: - - *checkout - - *setup_env - - run: - name: 'Build' - command: cond_spot_run_build aztec3-circuits-wasm-linux-clang 64 - - wasm-linux-clang-assert: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small - steps: - - *checkout - - *setup_env - - run: - name: 'Build' - command: cond_spot_run_build aztec3-circuits-wasm-linux-clang-assert 64 - - x86_64-linux-clang: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small - steps: - - *checkout - - *setup_env - - run: - name: 'Build' - command: cond_spot_run_build aztec3-circuits-x86_64-linux-clang 64 - - x86_64-linux-clang-assert: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small - steps: - - *checkout - - *setup_env - - run: - name: 'Build' - command: cond_spot_run_build aztec3-circuits-x86_64-linux-clang-assert 64 - - aztec3-circuits-wasm-tests: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small - steps: - - *checkout - - *setup_env - - run: - name: 'Test' - command: cond_spot_run_tests aztec3-circuits-wasm-linux-clang-assert 1 a3-tests USE_WASM_TIME - - *save_logs - - aztec3-circuits-tests: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small - steps: - - *checkout - - *setup_env - - run: - name: 'Test' - command: cond_spot_run_tests aztec3-circuits-x86_64-linux-clang-assert 1 a3-tests - - *save_logs - - #aztec3-circuits--tests: - # docker: - # - image: aztecprotocol/alpine-build-image - # resource_class: small - # steps: - # - *checkout - # - *setup_env - # - run: - # name: 'Test' - # command: cond_spot_run_tests aztec3-circuits-x86_64-linux-clang-assert 1 _tests - # - *save_logs - -# Repeatable config for defining the workflow below. -tag_regex: &tag_regex /v[0-9]+(\.[0-9]+)*(-[a-zA-Z-]+\.[0-9]+)?/ -defaults: &defaults - context: - - build - filters: - tags: - only: *tag_regex -a3_wasm_test: &a3_wasm_test - requires: - - wasm-linux-clang-assert - <<: *defaults -a3_test: &a3_test - requires: - - x86_64-linux-clang-assert - <<: *defaults - -workflows: - system: - jobs: - - wasm-linux-clang: *defaults - - wasm-linux-clang-assert: *defaults - - x86_64-linux-clang: *defaults - - x86_64-linux-clang-assert: *defaults - - aztec3-circuits-wasm-tests: *a3_wasm_test - - aztec3-circuits-tests: *a3_test - #- aztec3-circuit--tests: *a3_test diff --git a/circuits/.github/pull_request_template.md b/circuits/.github/pull_request_template.md deleted file mode 100644 index b3ed4e76e3e..00000000000 --- a/circuits/.github/pull_request_template.md +++ /dev/null @@ -1,33 +0,0 @@ -# Description - -Please provide a paragraph or two giving a summary of the change, including relevant motivation and context. - -# Checklist: - -- [ ] I have reviewed my diff in github, line by line. -- [ ] Every change is related to the PR description. -- [ ] I have [linked](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue) this pull request to the issue(s) that it resolves. -- [ ] There are no unexpected formatting changes, superfluous debug logs, or commented-out code. -- [ ] There are no circuit changes, OR specifications in `/specs` have been updated. -- [ ] There are no circuit changes, OR a cryptographer has been assigned for review. -- [ ] I've updated any terraform that needs updating (e.g. environment variables) for deployment. -- [ ] The branch has been rebased against the head of its merge target. -- [ ] I'm happy for the PR to be merged at the reviewer's next convenience. -- [ ] New functions, classes, etc. have been documented according to the doxygen comment format. Classes and structs must have `@brief` describing the intended functionality. -- [ ] If existing code has been modified, such documentation has been added or updated. - -> **Note** -> If you are updating the submodule, please make sure you do it in its own _special_ PR and avoid making changes to the submodule as a part of other PRs. -> To update a submodule, you can run the following commands: -> ```console -> $ git submodule update --recursive -> ``` -> Alternatively, you can select a particular commit in `barretenberg/aztec3` that you wish to point to: -> ```console -> $ cd barretenberg -> $ git pull origin aztec3 # This will point to the latest commit in `barretenberg/aztec3` -> $ git checkout # Use this if you wish to point to a particular commit. -> $ cd .. -> $ git add . && git commit -m -> $ git push -> ``` diff --git a/circuits/.gitmodules b/circuits/.gitmodules deleted file mode 100644 index cfe7b14e1c1..00000000000 --- a/circuits/.gitmodules +++ /dev/null @@ -1,7 +0,0 @@ -[submodule "barretenberg"] - path = cpp/barretenberg - url = git@github.com:AztecProtocol/barretenberg.git - branch = aztec3 -[submodule "aztec-build-system"] - path = build-system - url = git@github.com:AztecProtocol/build-system.git diff --git a/circuits/build_manifest.json b/circuits/build_manifest.json deleted file mode 100644 index 41be4339731..00000000000 --- a/circuits/build_manifest.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "aztec3-circuits-wasm-linux-clang": { - "buildDir": "cpp", - "dockerfile": "dockerfiles/Dockerfile.wasm-linux-clang", - "rebuildPatterns": ["^cpp/"], - "dependencies": [] - }, - "aztec3-circuits-wasm-linux-clang-assert": { - "buildDir": "cpp", - "dockerfile": "dockerfiles/Dockerfile.wasm-linux-clang-assert", - "rebuildPatterns": ["^cpp/"], - "dependencies": [] - }, - "aztec3-circuits-x86_64-linux-clang": { - "buildDir": "cpp", - "dockerfile": "dockerfiles/Dockerfile.x86_64-linux-clang", - "rebuildPatterns": ["^cpp/"], - "dependencies": [] - }, - "aztec3-circuits-x86_64-linux-clang-assert": { - "buildDir": "cpp", - "dockerfile": "dockerfiles/Dockerfile.x86_64-linux-clang-assert", - "rebuildPatterns": ["^cpp/"], - "dependencies": [] - } - } \ No newline at end of file diff --git a/circuits/build_manifest.sh b/circuits/build_manifest.sh deleted file mode 100644 index 27c20aef9c8..00000000000 --- a/circuits/build_manifest.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash -# Source this file to define the PROJECTS variable. -# PROJECT elements have structure PROJECT:WORKING_DIR:DOCKERFILE:REPO. -# -# TODO: Generate this from build_manifest.json - -# Commenting out a few projects, as the main use case is now to build the images needed to run end-to-end tests. -# If wanting to just see if docker images actually build, you can temporarily uncomment required projects. -PROJECTS=( - aztec3-circuits-wasm:cpp:./dockerfiles/Dockerfile.wasm-linux-clang:aztec3-circuits-wasm-linux-clang - aztec3-circuits-wasm-assert:cpp:./dockerfiles/Dockerfile.wasm-linux-clang-assert:aztec3-circuits-wasm-linux-clang-assert - aztec3-circuits-x86_64-clang:cpp:./dockerfiles/Dockerfile.x86_64-linux-clang:aztec3-circuits-x86_64-linux-clang - aztec3-circuits-x86_64-clang-assert:cpp:./dockerfiles/Dockerfile.x86_64-linux-clang-assert:aztec3-circuits-x86_64-linux-clang-assert -) \ No newline at end of file From aaa702fda807882a4f8390ad159ee487c5499c05 Mon Sep 17 00:00:00 2001 From: ludamad Date: Mon, 17 Apr 2023 15:45:38 -0400 Subject: [PATCH 166/166] chore: force build --- .gitmodules | 8 +- bootstrap.sh | 30 +-- build_manifest.sh | 2 +- circuits/LICENSE | 201 ------------------ circuits/PROJECT | 1 - circuits/README.md | 142 +++++++------ circuits/VERSION | 1 - circuits/bootstrap_docker.sh | 1 + circuits/build-system | 1 - circuits/cpp/CMakeLists.txt | 2 +- .../dockerfiles/Dockerfile.arm64-linux-gcc | 2 +- .../dockerfiles/Dockerfile.wasm-linux-clang | 10 +- .../Dockerfile.wasm-linux-clang-assert | 8 +- .../dockerfiles/Dockerfile.x86_64-linux-clang | 4 +- .../Dockerfile.x86_64-linux-clang-assert | 6 +- .../dockerfiles/Dockerfile.x86_64-linux-gcc | 4 +- circuits/cpp/scripts/run_tests | 10 +- .../cpp/src/aztec3/circuits/abis/c_bind.cpp | 2 - .../aztec3/circuits/rollup/merge/utils.cpp | 1 + scripts/tmux-splits | 2 +- yarn-project/circuits.js/README.md | 3 +- yarn-project/yarn-project-base/Dockerfile | 9 +- 22 files changed, 113 insertions(+), 337 deletions(-) delete mode 100644 circuits/LICENSE delete mode 100644 circuits/PROJECT delete mode 100644 circuits/VERSION delete mode 160000 circuits/build-system diff --git a/.gitmodules b/.gitmodules index 241af58f6f0..49f18b7f55c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,12 +1,12 @@ [submodule "build-system"] path = build-system url = git@github.com:AztecProtocol/build-system.git -[submodule "circuits"] - path = circuits - url = git@github.com:AztecProtocol/aztec3-circuits.git [submodule "l1-contracts"] path = l1-contracts url = git@github.com:AztecProtocol/aztec3-l1-contracts.git [submodule "barretenberg"] - path = barretenberg + path = circuits/cpp/barretenberg url = git@github.com:AztecProtocol/barretenberg.git +[submodule "legacy-nested-build-system"] + path = circuits/build-system + url = git@github.com:AztecProtocol/build-system.git \ No newline at end of file diff --git a/bootstrap.sh b/bootstrap.sh index e4eb6b01ce3..ba245880ae9 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -47,37 +47,9 @@ nvm install # Until we push .yarn/cache, we still need to install. cd yarn-project yarn install --immutable +# We do not need to build individual packages, yarn build will build the root tsconfig.json yarn build cd .. -PROJECTS=( - "yarn-project/foundation:yarn build" - "yarn-project/ethereum.js:yarn build" - "yarn-project/l1-contracts:yarn build" - "yarn-project/types:yarn build" - "yarn-project/merkle-tree:yarn build" - "yarn-project/archiver:yarn build" - "yarn-project/world-state:yarn build" - "yarn-project/p2p:yarn build" - "yarn-project/sequencer-client:yarn build" - "yarn-project/aztec-node:yarn build" - "yarn-project/key-store:yarn build" - "yarn-project/acir-simulator:yarn build" - "yarn-project/kernel-prover:yarn build" - "yarn-project/aztec-rpc:yarn build" - "yarn-project/aztec.js:yarn build" - "yarn-project/noir-contracts:yarn build" -) - -for E in "${PROJECTS[@]}"; do - ARR=(${E//:/ }) - DIR=${ARR[0]} - COMMAND=${ARR[@]:1} - echo "Bootstrapping $DIR: $COMMAND" - pushd $DIR > /dev/null - $COMMAND - popd > /dev/null -done - echo echo "Success! You could now run e.g.: ./scripts/tmux-splits e2e_deploy_contract" diff --git a/build_manifest.sh b/build_manifest.sh index be49f674bc3..c40d19cb5b9 100755 --- a/build_manifest.sh +++ b/build_manifest.sh @@ -13,7 +13,7 @@ # commit them, so that the most important build path remains fast and simple. PROJECTS=( - circuits:circuits/cpp:./dockerfiles/Dockerfile.wasm-linux-clang:aztec3-circuits-wasm-linux-clang + circuits:circuits/cpp:./dockerfiles/Dockerfile.wasm-linux-clang:circuits-wasm-linux-clang yarn-project-base:yarn-project # barretenberg.js:yarn-project end-to-end:yarn-project diff --git a/circuits/LICENSE b/circuits/LICENSE deleted file mode 100644 index 261eeb9e9f8..00000000000 --- a/circuits/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/circuits/PROJECT b/circuits/PROJECT deleted file mode 100644 index 8767aaf2272..00000000000 --- a/circuits/PROJECT +++ /dev/null @@ -1 +0,0 @@ -aztec3-circuits \ No newline at end of file diff --git a/circuits/README.md b/circuits/README.md index 4543cc57a76..bb2577d9d75 100644 --- a/circuits/README.md +++ b/circuits/README.md @@ -4,39 +4,41 @@ ## Repository Overview -The [`aztec3-circuits`](https://github.com/AztecProtocol/aztec3-circuits) repository contains circuits and related C++ code (`cpp/`) for Aztec3 along with Typescript wrappers (`ts/`). +The [`aztec3-circpuits`](https://github.com/AztecProtocol/aztec3-packages) circuits folder contains circuits and related C++ code (`cpp/`) for Aztec3 along with Typescript wrappers (`ts/`). ### Resources -* [Circuits project board](https://github.com/orgs/AztecProtocol/projects/22/views/2) -* [[DO NOT EDIT] Diagram with pseudocode for circuits](https://miro.com/app/board/uXjVPlafJWM=/) - * This diagram's contents are likely more up-to-date than code and than the other links below -* Kernel circuits - * [Slides - Dive into Kernel Circuits](https://drive.google.com/file/d/1BaspihHDUgny6MHAKMtTkWKvfah7PYtv/view?usp=share_link) - * [Recording of presentation](https://drive.google.com/file/d/1Uh-vLdc1_rsMUHL_c4HZ93jrjpuDsqD3/view?usp=share_link) - * [Kernel circuit mentioned in M1.1 Contract Deployment document](https://hackmd.io/ouVCnacHQRq2o1oRc5ksNA#Kernel-Circuit-functionality) - * [More info on the kernel circuit for Contract Creation](https://hackmd.io/@aztec-network/rkyRaXqPj#Kernel-Circuit-Logic) - * _Note:_ [Base rollup circuits in Aztec Connect](https://github.com/AztecProtocol/aztec-connect-cpp/tree/defi-bridge-project/src/rollup/proofs/rollup) are relevant to kernel circuits -* Rollup circuits - * [Rollup circuit mentioned in M1.1 Contract Deployment document](https://hackmd.io/ouVCnacHQRq2o1oRc5ksNA#Rollup-Circuit-functionality) - * [More info on the rollup circuit for Contract Creation](https://hackmd.io/@aztec-network/rkyRaXqPj#Rollup-Circuit-Logic) - * [Rollup circuits in Aztec Connect](https://github.com/AztecProtocol/aztec-connect-cpp/tree/defi-bridge-project/src/rollup/proofs) - * [[DO NOT EDIT] Diagram with different options for merkle insertions in rollup circuits](https://miro.com/app/board/uXjVMfITC3c=/) -* [Outdated specs](https://github.com/AztecProtocol/aztec2-internal/blob/3.0/markdown/specs/aztec3/src/SUMMARY.md) -* [Explanation of Indexed Merkle Tree (for nullifiers)](https://hackmd.io/AjR1uGh8SzSc7k3Gcu02mQ) +- [Circuits project board](https://github.com/orgs/AztecProtocol/projects/22/views/2) +- [[DO NOT EDIT] Diagram with pseudocode for circuits](https://miro.com/app/board/uXjVPlafJWM=/) + - This diagram's contents are likely more up-to-date than code and than the other links below +- Kernel circuits + - [Slides - Dive into Kernel Circuits](https://drive.google.com/file/d/1BaspihHDUgny6MHAKMtTkWKvfah7PYtv/view?usp=share_link) + - [Recording of presentation](https://drive.google.com/file/d/1Uh-vLdc1_rsMUHL_c4HZ93jrjpuDsqD3/view?usp=share_link) + - [Kernel circuit mentioned in M1.1 Contract Deployment document](https://hackmd.io/ouVCnacHQRq2o1oRc5ksNA#Kernel-Circuit-functionality) + - [More info on the kernel circuit for Contract Creation](https://hackmd.io/@aztec-network/rkyRaXqPj#Kernel-Circuit-Logic) + - _Note:_ [Base rollup circuits in Aztec Connect](https://github.com/AztecProtocol/aztec-connect-cpp/tree/defi-bridge-project/src/rollup/proofs/rollup) are relevant to kernel circuits +- Rollup circuits + - [Rollup circuit mentioned in M1.1 Contract Deployment document](https://hackmd.io/ouVCnacHQRq2o1oRc5ksNA#Rollup-Circuit-functionality) + - [More info on the rollup circuit for Contract Creation](https://hackmd.io/@aztec-network/rkyRaXqPj#Rollup-Circuit-Logic) + - [Rollup circuits in Aztec Connect](https://github.com/AztecProtocol/aztec-connect-cpp/tree/defi-bridge-project/src/rollup/proofs) + - [[DO NOT EDIT] Diagram with different options for merkle insertions in rollup circuits](https://miro.com/app/board/uXjVMfITC3c=/) +- [Outdated specs](https://github.com/AztecProtocol/aztec2-internal/blob/3.0/markdown/specs/aztec3/src/SUMMARY.md) +- [Explanation of Indexed Merkle Tree (for nullifiers)](https://hackmd.io/AjR1uGh8SzSc7k3Gcu02mQ) ### Getting Started with C++ Clone the repo and build the C++: + ``` -git clone git@github.com:AztecProtocol/aztec3-circuits.git -cd aztec3-circuits +git clone git@github.com:AztecProtocol/aztec3-packages.git +cd circuits git submodule update --init --recursive cd cpp ./bootstrap.sh ``` Here is an example of rapidly rebuilding and running all tests in `src/aztec3/circuits/abis/tests`: + ``` cmake --preset clang15 cmake --build --preset clang15 --target aztec3_circuits_abis_tests @@ -44,6 +46,7 @@ cmake --build --preset clang15 --target aztec3_circuits_abis_tests ``` You can also limit it to run only specific test cases using a gtest filter: + ``` (cd build && ./bin/aztec3_circuits_abis_tests --gtest_filter=*hash_tx_request*) ``` @@ -51,38 +54,44 @@ You can also limit it to run only specific test cases using a gtest filter: --- Here's a list of the tests currently available (conveniently combined with the command to build, then execute them, for easy copy-pasta): - - aztec3_circuits_abis_tests - - `cmake --build --preset clang15 --target aztec3_circuits_abis_tests && (cd build && ./bin/aztec3_circuits_abis_tests --gtest_filter=*)` - - aztec3_circuits_apps_tests - - `cmake --build --preset clang15 --target aztec3_circuits_apps_tests && (cd build && ./bin/aztec3_circuits_apps_tests --gtest_filter=*)` +- aztec3_circuits_abis_tests + + - `cmake --build --preset clang15 --target aztec3_circuits_abis_tests && (cd build && ./bin/aztec3_circuits_abis_tests --gtest_filter=*)` + +- aztec3_circuits_apps_tests + + - `cmake --build --preset clang15 --target aztec3_circuits_apps_tests && (cd build && ./bin/aztec3_circuits_apps_tests --gtest_filter=*)` + +- aztec3_circuits_kernel_tests - - aztec3_circuits_kernel_tests - - `cmake --build --preset clang15 --target aztec3_circuits_kernel_tests && (cd build && ./bin/aztec3_circuits_kernel_tests --gtest_filter=*)` + - `cmake --build --preset clang15 --target aztec3_circuits_kernel_tests && (cd build && ./bin/aztec3_circuits_kernel_tests --gtest_filter=*)` - - aztec3_circuits_recursion_tests - - `cmake --build --preset clang15 --target aztec3_circuits_recursion_tests && (cd build && ./bin/aztec3_circuits_recursion_tests --gtest_filter=*)` +- aztec3_circuits_recursion_tests - - aztec3_circuits_rollup_tests - - `cmake --build --preset clang15 --target aztec3_circuits_rollup_tests && (cd build && ./bin/aztec3_circuits_rollup_tests --gtest_filter=*)` + - `cmake --build --preset clang15 --target aztec3_circuits_recursion_tests && (cd build && ./bin/aztec3_circuits_recursion_tests --gtest_filter=*)` + +- aztec3_circuits_rollup_tests + - `cmake --build --preset clang15 --target aztec3_circuits_rollup_tests && (cd build && ./bin/aztec3_circuits_rollup_tests --gtest_filter=*)` --- ### C++ Repository Layout + This repository submodules [`barretenberg`](https://github.com/AztecProtocol/barretenberg) as a C++ library containing proving systems and utilities at `cpp/barretenberg/`. The core Aztec 3 C++ code lives in `cpp/src/aztec3/`, and is split into the following subdirectories/files: -* `constants.hpp`: top-level constants relevant to Aztec 3 -* `circuits`: circuits and their types and interfaces - * `apps`: infrastructure and early prototypes for application circuits ([more here](https://github.com/AztecProtocol/aztec3-circuits/tree/master/cpp/src/aztec3/circuits/apps)) - * `abis`: types, interfaces, and cbinds for representing/constructing outputs of application circuits that will be fed into kernel circuits ([more here](https://github.com/AztecProtocol/aztec3-circuits/tree/master/cpp/src/aztec3/circuits/abis)) - * `kernel`: kernel circuits, their interfaces, and their tests - * `rollup`: rollup circuits, their interfaces, and thier tests - * `recursion`: types and examples for aggregation of recursive proof objects - * `mock`: mock circuits -* `oracle`: used to fetch external information (like private data notes) and inject them as inputs into the circuit "Composer" during execution of circuit logic ([more here](https://github.com/AztecProtocol/aztec3-circuits/tree/master/cpp/src/aztec3/oracle)) -* `dbs`: database infrastructure (_e.g._ PrivateStateDb) +- `constants.hpp`: top-level constants relevant to Aztec 3 +- `circuits`: circuits and their types and interfaces + - `apps`: infrastructure and early prototypes for application circuits ([more here](https://github.com/AztecProtocol/aztec3-packages/tree/master/circuits/cpp/src/aztec3/circuits/apps)) + - `abis`: types, interfaces, and cbinds for representing/constructing outputs of application circuits that will be fed into kernel circuits ([more here](https://github.com/AztecProtocol/aztec3-packages/tree/master/circuits/cpp/src/aztec3/circuits/abis)) + - `kernel`: kernel circuits, their interfaces, and their tests + - `rollup`: rollup circuits, their interfaces, and thier tests + - `recursion`: types and examples for aggregation of recursive proof objects + - `mock`: mock circuits +- `oracle`: used to fetch external information (like private data notes) and inject them as inputs into the circuit "Composer" during execution of circuit logic ([more here](https://github.com/AztecProtocol/aztec3-packages/tree/master/circuits/cpp/src/aztec3/oracle)) +- `dbs`: database infrastructure (_e.g._ PrivateStateDb) ### Typescript @@ -92,7 +101,7 @@ All typescript code was moved from here into `aztec3-packages/yarn-project/circu The private kernel circuit validates that a particular private function was correctly executed by the user. Therefore, the private kernel circuit is going to be run on the user's device. A private function execution can involve calls to other private functions from the same contract or private functions from other contracts. Each call to another private function needs to be proven that the execution was correct. Therefore, each nested call to another private function will have its own circuit execution proof, and that proof must then be validated by the private kernel circuit. The proof generated by the private kernel circuit will be submitted to the transaction pool, from where rollup providers will include those private kernel proofs in their L2 blocks. -The private kernel circuit in Aztec 3 is implemented in [`circuit/kernel/private`](https://github.com/AztecProtocol/aztec3-circuits/tree/master/cpp/src/aztec3/circuits/kernel/private) directory. The input and output interface of the private kernel circuit is written in [`circuits/abis/private_kernel`](https://github.com/AztecProtocol/aztec3-circuits/tree/master/cpp/src/aztec3/circuits/abis/private_kernel). +The private kernel circuit in Aztec 3 is implemented in [`circuit/kernel/private`](https://github.com/AztecProtocol/aztec3-packages/tree/master/circuits/cpp/src/aztec3/circuits/kernel/private) directory. The input and output interface of the private kernel circuit is written in [`circuits/abis/private_kernel`](https://github.com/AztecProtocol/aztec3-packages/tree/master/circuits/cpp/src/aztec3/circuits/abis/private_kernel). See pseudocode in [this diagram](https://miro.com/app/board/uXjVPlafJWM=/) and the slides [here](https://drive.google.com/file/d/1BaspihHDUgny6MHAKMtTkWKvfah7PYtv/view?usp=share_link) for a deeper dive into the private kernel circuit. @@ -102,10 +111,11 @@ See pseudocode in [this diagram](https://miro.com/app/board/uXjVPlafJWM=/) and t The rollup providers (or sequencers - nomenclature is yet to be decided) pull up transactions from the pool to be rolled up. Each of these transactions is essentially a proof generated by the private kernel circuit including its public inputs. To accumulate several such transactions in a single L2 block, the rollup provider needs to aggregate the private kernel proofs. The base rollup circuit is meant to aggregate these private kernel proofs. In simple words, the rollup circuit validates that the private kernel circuit was correctly executed. -In our design, we allow the rollup providers to only aggregate _two_ private kernel proofs at once. This would mean that if a rollup provider wishes to roll-up 1024 transactions in one L2 block, for example, he would need $\frac{1024}{2} = 512$ invocations of the base rollup circuit. This hard-limit on the number of private kernel proofs that one can aggregate is enable generating rollup proofs on commodity hardware, effectively reducing the entry-barrier for common users to become rollup providers. +In our design, we allow the rollup providers to only aggregate _two_ private kernel proofs at once. This would mean that if a rollup provider wishes to roll-up 1024 transactions in one L2 block, for example, he would need $\frac{1024}{2} = 512$ invocations of the base rollup circuit. This hard-limit on the number of private kernel proofs that one can aggregate is enable generating rollup proofs on commodity hardware, effectively reducing the entry-barrier for common users to become rollup providers. :::info At a very high-level, the rollup circuits need to perform the following checks: + 1. Aggregate the inner proofs (most expensive part taking up appx 75% circuit size) 2. Merkle membership checks (second most expensive part taking up appx 15% circuit size) 3. Public input hashing using SHA-256 (third most expensive part, appx 10%, can blow up if you need to hash tons of public inputs) @@ -114,7 +124,7 @@ We have a limit on the first point: you can aggregate a maximum of two proofs pe ::: :::warning -**Note**: For the first milestone, we do not include public function execution in our circuit design. +**Note**: For the first milestone, we do not include public function execution in our circuit design. ::: See pseudocode in [this diagram](https://miro.com/app/board/uXjVPlafJWM=/) for a deep dive into the Base Rollup Circuit's functionality. @@ -128,46 +138,44 @@ Furthermore, we can use the same merge rollup circuit to verify two merge rollup See pseudocode in [this diagram](https://miro.com/app/board/uXjVPlafJWM=/) for a deep dive into the Merge Rollup Circuit's functionality. :::warning -**Note**: We might not need the merge rollup circuit for the offsite but its anyway going to be very similar to the base rollup circuit. +**Note**: We might not need the merge rollup circuit for the offsite but its anyway going to be very similar to the base rollup circuit. ::: ### Root Rollup Circuit -The root rollup circuit is the final circuit execution layer before the proof is sent to L1 for on-chain verification. The root rollup circuit verifies that the final merge rollup circuit was correctly executed. The proof from the root rollup circuit is verified by the rollup contract on Ethereum. So effectively, verifying that one proof on-chain gives a final green flag to whatever number of transactions that were included in that particular L2 block. +The root rollup circuit is the final circuit execution layer before the proof is sent to L1 for on-chain verification. The root rollup circuit verifies that the final merge rollup circuit was correctly executed. The proof from the root rollup circuit is verified by the rollup contract on Ethereum. So effectively, verifying that one proof on-chain gives a final green flag to whatever number of transactions that were included in that particular L2 block. It is interesting to note that the root rollup circuit takes _one_ proof and outputs _one_ proof. The reason we do this is to switch the types of the proof: i.e. ultra-plonk/honk to standard-plonk. This is because standard-plonk proofs are cheaper to verify on-chain (in terms of gas costs). - See pseudocode in [this diagram](https://miro.com/app/board/uXjVPlafJWM=/) for a deep dive into the Root Rollup Circuit's functionality. - ## Circuit Logic - ### Private Kernel Circuit Logic The private kernel circuit is recursive in that it will perform validation of a single function call, and then recursively verify its previous iteration along with the next function call. Below is a list of the private kernel circuit's high-level responsibilities: + 1. For the first iteration: - * **[M1.1]** Validate the signature of a signed tx object - * Validate the function in that tx object matches the one currently being processed + - **[M1.1]** Validate the signature of a signed tx object + - Validate the function in that tx object matches the one currently being processed 2. For all subsequent iterations: - * Pop an item off of the kernel's dynamic callstack - * Validate that this function matches the one currently being processed -1. Verify a 'previous' kernel circuit (mock for first iteration, always mocked for **[M1.1]**) -3. Verify the proof of execution for the function (or constructor **[M1.1]**) currently being processed -4. **[M1.1]** If this is a contract deployment, check the contract deployment logic - * _[After M1.1]_ Includes checks for private circuit execution logic -5. **[M1.1]** Generate `contract_address` and its nullifier (inserted in later circuit) -6. **[M1.1]** Generate `new_contract_data` which is the contract tree leaf preimage -7. Copy the current function's callstack into kernel's dynamic callstack -8. Validate the function data against `function_tree_root` - * Includes a membership check of the function leaf -9. Validate the contract data against `contract_tree_root` - * Includes a membership check of the contract leaf -10. Perform membership checks for commitments accessed by this function -11. Collect new commitments, nullifiers, contracts, and messages to L1 -12. Add recursion byproducts to `aggregation_object` -13. TODO: L1 messages -14. Section in progress... \ No newline at end of file + - Pop an item off of the kernel's dynamic callstack + - Validate that this function matches the one currently being processed +3. Verify a 'previous' kernel circuit (mock for first iteration, always mocked for **[M1.1]**) +4. Verify the proof of execution for the function (or constructor **[M1.1]**) currently being processed +5. **[M1.1]** If this is a contract deployment, check the contract deployment logic + - _[After M1.1]_ Includes checks for private circuit execution logic +6. **[M1.1]** Generate `contract_address` and its nullifier (inserted in later circuit) +7. **[M1.1]** Generate `new_contract_data` which is the contract tree leaf preimage +8. Copy the current function's callstack into kernel's dynamic callstack +9. Validate the function data against `function_tree_root` + - Includes a membership check of the function leaf +10. Validate the contract data against `contract_tree_root` + - Includes a membership check of the contract leaf +11. Perform membership checks for commitments accessed by this function +12. Collect new commitments, nullifiers, contracts, and messages to L1 +13. Add recursion byproducts to `aggregation_object` +14. TODO: L1 messages +15. Section in progress... diff --git a/circuits/VERSION b/circuits/VERSION deleted file mode 100644 index aa338688915..00000000000 --- a/circuits/VERSION +++ /dev/null @@ -1 +0,0 @@ -v0.1 \ No newline at end of file diff --git a/circuits/bootstrap_docker.sh b/circuits/bootstrap_docker.sh index c59b9a61528..12569fb7452 100755 --- a/circuits/bootstrap_docker.sh +++ b/circuits/bootstrap_docker.sh @@ -10,6 +10,7 @@ set -e TARGET_PROJECT=$1 +# TODO(AD) fix script after moving towards less repos REPO=aztec3-circuits COMMIT_HASH=$(git rev-parse HEAD) diff --git a/circuits/build-system b/circuits/build-system deleted file mode 160000 index c85b185d917..00000000000 --- a/circuits/build-system +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c85b185d917df423586897fd036275400b7159d9 diff --git a/circuits/cpp/CMakeLists.txt b/circuits/cpp/CMakeLists.txt index 832a811a9f7..9120c4126ea 100644 --- a/circuits/cpp/CMakeLists.txt +++ b/circuits/cpp/CMakeLists.txt @@ -1,4 +1,4 @@ -# aztec3-circuits +# aztec3 circuits package # copyright 2019 Spilsbury Holdings Ltd cmake_minimum_required(VERSION 3.24) diff --git a/circuits/cpp/dockerfiles/Dockerfile.arm64-linux-gcc b/circuits/cpp/dockerfiles/Dockerfile.arm64-linux-gcc index 8ba6d984ada..98a77fe5d04 100644 --- a/circuits/cpp/dockerfiles/Dockerfile.arm64-linux-gcc +++ b/circuits/cpp/dockerfiles/Dockerfile.arm64-linux-gcc @@ -1,6 +1,6 @@ # Unused & not maintained. This probably won't work without changes. FROM aztecprotocol/crosstool-ng-arm64:latest -WORKDIR /usr/src/aztec3-circuits/cpp +WORKDIR /usr/src/circuits/cpp COPY . . RUN cmake --toolchain ./cmake/toolchains/aarch64-linux.cmake --preset gcc -DUSE_TURBO=true && cmake --build --preset gcc RUN cd build && for test in ./bin/*_tests; do qemu-aarch64 $test; done diff --git a/circuits/cpp/dockerfiles/Dockerfile.wasm-linux-clang b/circuits/cpp/dockerfiles/Dockerfile.wasm-linux-clang index 00325e48d10..1594ca329e0 100644 --- a/circuits/cpp/dockerfiles/Dockerfile.wasm-linux-clang +++ b/circuits/cpp/dockerfiles/Dockerfile.wasm-linux-clang @@ -1,12 +1,12 @@ FROM ubuntu:kinetic AS builder RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y build-essential wget git libssl-dev cmake ninja-build curl binaryen -WORKDIR /usr/src/aztec3-circuits/cpp/barretenberg/cpp/src +WORKDIR /usr/src/circuits/cpp/barretenberg/cpp/src RUN curl -s -L https://github.com/CraneStation/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-linux.tar.gz | tar zxfv - -WORKDIR /usr/src/aztec3-circuits/cpp +WORKDIR /usr/src/circuits/cpp COPY . . RUN cmake --preset wasm -DUSE_TURBO=true && cmake --build --preset wasm FROM alpine:3.17 -COPY --from=builder /usr/src/aztec3-circuits/cpp/build-wasm/bin/aztec3-circuits.wasm /usr/src/aztec3-circuits/cpp/build-wasm/bin/aztec3-circuits.wasm -COPY --from=builder /usr/src/aztec3-circuits/cpp/barretenberg/cpp/build-wasm/bin/primitives.wasm /usr/src/aztec3-circuits/cpp/barretenberg/cpp/build-wasm/bin/primitives.wasm -COPY --from=builder /usr/src/aztec3-circuits/cpp/barretenberg/cpp/srs_db /usr/src/aztec3-circuits/cpp/barretenberg/cpp/srs_db +COPY --from=builder /usr/src/circuits/cpp/build-wasm/bin/aztec3-circuits.wasm /usr/src/circuits/cpp/build-wasm/bin/aztec3-circuits.wasm +COPY --from=builder /usr/src/circuits/cpp/barretenberg/cpp/build-wasm/bin/primitives.wasm /usr/src/circuits/cpp/barretenberg/cpp/build-wasm/bin/primitives.wasm +COPY --from=builder /usr/src/circuits/cpp/barretenberg/cpp/srs_db /usr/src/circuits/cpp/barretenberg/cpp/srs_db diff --git a/circuits/cpp/dockerfiles/Dockerfile.wasm-linux-clang-assert b/circuits/cpp/dockerfiles/Dockerfile.wasm-linux-clang-assert index f0ea18ebe4e..461ead4c3f1 100644 --- a/circuits/cpp/dockerfiles/Dockerfile.wasm-linux-clang-assert +++ b/circuits/cpp/dockerfiles/Dockerfile.wasm-linux-clang-assert @@ -1,8 +1,8 @@ FROM ubuntu:kinetic AS builder RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y build-essential git libssl-dev cmake ninja-build curl binaryen -WORKDIR /usr/src/aztec3-circuits/cpp/barretenberg/cpp/src +WORKDIR /usr/src/circuits/cpp/barretenberg/cpp/src RUN curl -s -L https://github.com/CraneStation/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-linux.tar.gz | tar zxfv - -WORKDIR /usr/src/aztec3-circuits/cpp +WORKDIR /usr/src/circuits/cpp COPY . . RUN cmake --preset wasm -DUSE_TURBO=true && cmake --build --preset wasm @@ -10,5 +10,5 @@ RUN cmake --preset wasm -DUSE_TURBO=true && cmake --build --preset wasm FROM ubuntu:kinetic RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y xz-utils curl RUN curl https://wasmtime.dev/install.sh -sSf | bash /dev/stdin --version v3.0.1 -COPY --from=builder /usr/src/aztec3-circuits/cpp/barretenberg/cpp/srs_db /usr/src/aztec3-circuits/cpp/barretenberg/cpp/srs_db -COPY --from=builder /usr/src/aztec3-circuits/cpp/build-wasm/bin/*_tests /usr/src/aztec3-circuits/cpp/build-wasm/bin/ +COPY --from=builder /usr/src/circuits/cpp/barretenberg/cpp/srs_db /usr/src/circuits/cpp/barretenberg/cpp/srs_db +COPY --from=builder /usr/src/circuits/cpp/build-wasm/bin/*_tests /usr/src/circuits/cpp/build-wasm/bin/ diff --git a/circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-clang b/circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-clang index b2a11c56efa..f06a0e3d7cd 100644 --- a/circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-clang +++ b/circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-clang @@ -11,7 +11,7 @@ RUN apk update \ curl \ perl -WORKDIR /usr/src/aztec3-circuits/cpp +WORKDIR /usr/src/circuits/cpp COPY . . # Build the entire project, as we want to check everything builds under clang @@ -19,4 +19,4 @@ RUN cmake --preset default -DUSE_TURBO=true && cmake --build --preset default FROM alpine:3.17 RUN apk update && apk add openmp -COPY --from=builder /usr/src/aztec3-circuits/cpp/barretenberg/cpp/srs_db /usr/src/aztec3-circuits/cpp/barretenberg/cpp/srs_db \ No newline at end of file +COPY --from=builder /usr/src/circuits/cpp/barretenberg/cpp/srs_db /usr/src/circuits/cpp/barretenberg/cpp/srs_db \ No newline at end of file diff --git a/circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-clang-assert b/circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-clang-assert index 95b212e04a2..346a4f7a215 100644 --- a/circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-clang-assert +++ b/circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-clang-assert @@ -11,7 +11,7 @@ RUN apk update \ curl \ perl -WORKDIR /usr/src/aztec3-circuits/cpp +WORKDIR /usr/src/circuits/cpp COPY . . # Build everything to ensure everything builds. All tests will be run from the result of this build. @@ -19,5 +19,5 @@ RUN cmake --preset default -DCMAKE_BUILD_TYPE=RelWithAssert -DCI=ON -DUSE_TURBO= FROM alpine:3.17 RUN apk update && apk add curl openmp -COPY --from=builder /usr/src/aztec3-circuits/cpp/barretenberg/cpp/srs_db /usr/src/aztec3-circuits/cpp/barretenberg/cpp/srs_db -COPY --from=builder /usr/src/aztec3-circuits/cpp/build/bin/*_tests /usr/src/aztec3-circuits/cpp/build/bin/ \ No newline at end of file +COPY --from=builder /usr/src/circuits/cpp/barretenberg/cpp/srs_db /usr/src/circuits/cpp/barretenberg/cpp/srs_db +COPY --from=builder /usr/src/circuits/cpp/build/bin/*_tests /usr/src/circuits/cpp/build/bin/ \ No newline at end of file diff --git a/circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-gcc b/circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-gcc index 1e5d89e2583..27034f08ec4 100644 --- a/circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-gcc +++ b/circuits/cpp/dockerfiles/Dockerfile.x86_64-linux-gcc @@ -7,11 +7,11 @@ RUN apk update \ ninja \ git \ curl -WORKDIR /usr/src/aztec3-circuits/cpp +WORKDIR /usr/src/circuits/cpp COPY . . # Build the entire project, as we want to check everything builds under gcc. RUN cmake --preset gcc -DCI=ON -DUSE_TURBO=true && cmake --build --preset gcc FROM alpine:3.17 RUN apk update && apk add libstdc++ libgomp -COPY --from=builder /usr/src/aztec3-circuits/cpp/barretenberg/cpp/srs_db /usr/src/aztec3-circuits/cpp/barretenberg/cpp/srs_db +COPY --from=builder /usr/src/circuits/cpp/barretenberg/cpp/srs_db /usr/src/circuits/cpp/barretenberg/cpp/srs_db diff --git a/circuits/cpp/scripts/run_tests b/circuits/cpp/scripts/run_tests index c44c802e308..0af2338f4ba 100755 --- a/circuits/cpp/scripts/run_tests +++ b/circuits/cpp/scripts/run_tests @@ -12,7 +12,7 @@ fi $(aws ecr get-login --region us-east-2 --no-include-email) 2> /dev/null -IMAGE_URI=278380418400.dkr.ecr.us-east-2.amazonaws.com/aztec3-circuits-x86_64-linux-clang-assert:cache-$COMMIT_HASH +IMAGE_URI=278380418400.dkr.ecr.us-east-2.amazonaws.com/circuits-x86_64-linux-clang-assert:cache-$COMMIT_HASH docker pull $IMAGE_URI @@ -22,16 +22,16 @@ fi if [ -z "$WASM_MODE" ]; then TEST_CMD="./bin/\$BIN $@" - BUILD_DIR=/usr/src/aztec3-circuits/cpp/build + BUILD_DIR=/usr/src/circuits/cpp/build else TEST_CMD="wasmtime --dir .. bin/\$BIN $@" - BUILD_DIR=/usr/src/aztec3-circuits/cpp/build-wasm + BUILD_DIR=/usr/src/circuits/cpp/build-wasm fi docker run --rm -t $IMAGE_URI /bin/sh -c "\ set -e; \ - cd /usr/src/aztec3-circuits/cpp/barretenberg/cpp/srs_db; \ - ln -sf /usr/src/aztec3-circuits/cpp/barretenberg/cpp/srs_db /usr/src/aztec3-circuits/cpp/srs_db; \ + cd /usr/src/circuits/cpp/barretenberg/cpp/srs_db; \ + ln -sf /usr/src/circuits/cpp/barretenberg/cpp/srs_db /usr/src/circuits/cpp/srs_db; \ ./download_ignition.sh $NUM_TRANSCRIPTS; \ cd $BUILD_DIR; \ for BIN in $TESTS; do $TEST_CMD; done" diff --git a/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp b/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp index 9beffd9bfb1..b897b0ac743 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp +++ b/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp @@ -105,8 +105,6 @@ compute_partial_left_tree(uint8_t const* leaves_buf, uint8_t num_leaves, NT::fr } // namespace -#define WASM_EXPORT __attribute__((visibility("default"))) - // Note: We don't have a simple way of calling the barretenberg c-bind. // Mimick bbmalloc behaviour. static void* bbmalloc(size_t size) diff --git a/circuits/cpp/src/aztec3/circuits/rollup/merge/utils.cpp b/circuits/cpp/src/aztec3/circuits/rollup/merge/utils.cpp index 62a5bbc5483..35b214cc394 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/merge/utils.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/merge/utils.cpp @@ -3,6 +3,7 @@ #include "aztec3/circuits/abis/rollup/merge/merge_rollup_inputs.hpp" #include "aztec3/circuits/abis/rollup/base/base_or_merge_rollup_public_inputs.hpp" #include "aztec3/constants.hpp" +#include "aztec3/utils/dummy_composer.hpp" #include "barretenberg/plonk/proof_system/verification_key/verification_key.hpp" #include "index.hpp" #include "init.hpp" diff --git a/scripts/tmux-splits b/scripts/tmux-splits index 9c93aa61927..296cdb36632 100755 --- a/scripts/tmux-splits +++ b/scripts/tmux-splits @@ -10,7 +10,7 @@ cd $(git rev-parse --show-toplevel) if tmux has-session -t $SESSION_NAME > /dev/null 2>&1; then tmux attach -t $SESSION_NAME else - tmux new-session -s $SESSION_NAME -d + tmux new-session -s $SESSION_NAME -d \ split-window \; \ select-layout even-vertical \; \ # Give a chance for terminals to start (avoids double command echo). diff --git a/yarn-project/circuits.js/README.md b/yarn-project/circuits.js/README.md index 15c3f5eb258..3340b3e16df 100644 --- a/yarn-project/circuits.js/README.md +++ b/yarn-project/circuits.js/README.md @@ -1,6 +1,7 @@ # Circuits.js -Javascript bindings for aztec3-circuits WASM. +Javascript bindings for the aztec3 circuits WASM. +High-level bindings to the raw C API to our core circuit logic. ## To run: diff --git a/yarn-project/yarn-project-base/Dockerfile b/yarn-project/yarn-project-base/Dockerfile index 2ed7214a24b..97760b5a588 100644 --- a/yarn-project/yarn-project-base/Dockerfile +++ b/yarn-project/yarn-project-base/Dockerfile @@ -1,5 +1,5 @@ # FROM 278380418400.dkr.ecr.eu-west-2.amazonaws.com/circuits-x86_64-linux-clang -FROM 278380418400.dkr.ecr.eu-west-2.amazonaws.com/aztec3-circuits-wasm-linux-clang +FROM 278380418400.dkr.ecr.eu-west-2.amazonaws.com/circuits-wasm-linux-clang # FROM 278380418400.dkr.ecr.eu-west-2.amazonaws.com/l1-contracts FROM node:18-alpine @@ -8,10 +8,9 @@ RUN apk update && apk add --no-cache build-base git python3 curl bash jq # COPY --from=1 /usr/src/circuits/build/bin /usr/src/circuits/build-wasm/bin # COPY --from=2 /usr/src/l1-contracts /usr/src/l1-contracts -# TODO: submodule circuits as aztec3-circuits so we don't have two names for the same thing. -COPY --from=0 /usr/src/aztec3-circuits/cpp/build-wasm/bin/aztec3-circuits.wasm /usr/src/circuits/cpp/build-wasm/bin/aztec3-circuits.wasm -COPY --from=0 /usr/src/aztec3-circuits/cpp/barretenberg/cpp/build-wasm/bin/primitives.wasm /usr/src/circuits/cpp/barretenberg/cpp/build-wasm/bin/primitives.wasm -COPY --from=0 /usr/src/aztec3-circuits/cpp/barretenberg/cpp/srs_db/download_ignition.sh /usr/src/circuits/cpp/barretenberg/cpp/srs_db/download_ignition.sh +COPY --from=0 /usr/src/circuits/cpp/build-wasm/bin/aztec3-circuits.wasm /usr/src/circuits/cpp/build-wasm/bin/aztec3-circuits.wasm +COPY --from=0 /usr/src/circuits/cpp/barretenberg/cpp/build-wasm/bin/primitives.wasm /usr/src/circuits/cpp/barretenberg/cpp/build-wasm/bin/primitives.wasm +COPY --from=0 /usr/src/circuits/cpp/barretenberg/cpp/srs_db/download_ignition.sh /usr/src/circuits/cpp/barretenberg/cpp/srs_db/download_ignition.sh WORKDIR /usr/src/circuits/cpp/barretenberg/cpp/srs_db RUN ./download_ignition.sh 1
- -
- {{> header}} - - - - {{#if search_enabled}} - - {{/if}} - - - - -
-
- -
- - {{{ content }}} -
- - -
-
- - - -