---
# System prepended metadata

title: Report NRG Milestone 3 (vN+1)

---

### Intro

This report marks the third milestone of a Noir Research Grant proposal, exploring the intersection between Noir, gaming, private shared state, and multiparty computation. (Previous entries: [2](https://hackmd.io/@FATSOLUTIONS/rkva88njkl), [1](https://hackmd.io/@FATSOLUTIONS/rJvWjq0uJx), [0](https://github.com/orgs/noir-lang/discussions/6359))

"Terry Escape" is a proof of concept multiplayer adversarial game where participants take turns trying to eliminate other players' agents from the board, by either deploying booby traps or infiltrating neighboring sites. But there is a catch, players only know the position of their own pieces plus what they can infer from turn interactions powered by MPC wizardry.

---

### Delivered artifact
A web frontend with clickable interface and its ZK components, for a multiplayer game with shared board but private pieces and client side proof generation. The various proofs for different stages of the protocol are generated and verified using NoirJS and its UltraHonk backend (all happening inside the browser context), which in turn update the graphical components with new information, sending and receiving protocol messages between players' machines.

An orchestrating server was also developed with the intention to reduce complexity, only having the task to relay public messages around in an orderly manner. It does not learn private information on the way.

The sources can be found [here](https://github.com/fatlabsxyz/terry-escape).

![image](https://hackmd.io/_uploads/HJYETvCDlx.png)


> View of a player, early on a gameplay, after players have already interacted on MPC rounds to update respective states and verified proofs correctness, as informed on the game log. This player is about to deploy a trap on nearby room.
##### [Demo Video](https://www.youtube.com/watch?v=UzEIVdN9-AQ)

---

### Roadbumps
The most relevant obstacles during development were:
- **Dependency on libraries in early development stages**
Developing core circuit logic while depending on libraries with low test coverage, proved to be a significant and recurrent slowdown. In particular, assuming core arithmetic operations (gt, add, shr, div, mod, etc.) of [noir-bignum](https://github.com/noir-lang/noir-bignum) work as expected, while in reality behaved erratically in certain scenarios, sometimes silently, due to multiple disjoint bugs. Some bugs where distilled and reported, some isolated, and others got fixed as part of bigger library refactors.

  Frequent breaking changes in upstream libraries introduced additional integration overhead, which is expected when building on actively evolving tooling.


- **Ultrahonk recursive verification**
While porting the MPC protocol proofs from a shell environment to the web context, multiple errors arose in circuits whose inputs included other circuit proofs. In the original scheme, these allowed to reduce game state updates to a single proof per player per turn.

  After some code archaeology to find the cause (web honk recursion [was not implemented](https://github.com/AztecProtocol/aztec-packages/blob/next/barretenberg/ts/src/barretenberg/backend.ts#L168-L198) and [marked as closed](https://github.com/noir-lang/noir/issues/5661)), the decision was made to rewrite all the circuits and make additional inputs crosschecks between the proofs, in order to preserve soundness.

  Finding about this, while late on the development process, was a major setback.
  
- **Silent oracles as private output**
To avoid duplication of circuit logic in another language (and attracting fresh bugs), private values were originally extracted by directly `println`-ing them to standard output, and parsing them after `nargo`'s CLI circuit execution.
This output became unavailable when porting to web context, so oracles with no return value were used instead. Such type of solutions were [discussed](https://github.com/noir-lang/noir/issues/688) [before](https://github.com/noir-lang/noir/issues/4532).

  An example snippet from the initial agent deploy circuit:
  ```rust
  #[oracle(oracle_board)]
  unconstrained fn oracle_board(board: [Field; Size]) -> () {}
  unconstrained fn output_board(board: [Field; Size]) -> () {
      oracle_board(board);
  }

  fn main(..., board_salt: Field) -> pub Field {
    ...
    let mut board = ...;
    ...
    let board_digest = hash([board_salt, hash(board)]);
    let _ = unsafe { output_board(board); };
    board_digest
  }
  ```
  
  And the corresponding snippet, from web proof generation:
  ```js
  ...
  const oracle_handler = async (name: string, _inputs: any) => {
    if (name == "oracle_board") { computed_board = _inputs[0]; }
    return [];
  };
  const { witness, returnValue } = await circuit.noir.execute(inputs, oracle_handler);
  ...
  ```

---

### Learnings
- Taking time to writedown the purpose and general motivation of the each circuit to be used, before jumping to development, helped a lot. Even when requiments changed. Having only a vague idea of how modules will latter interact, is a recipe for trouble.
- Mocking the proof generation -- by only executing the circuit to obtain outputs, but temporarily skipping the actual witness generation -- proved to be a signicant speedup to the testing feedback loop. Once the protocol flow was tested, witness computation was reintroduced to test complete integrations. Here is the relevant snippet from the code:
  ```ts
  const { witness, returnValue } = await circuit.noir.execute(inputs, oracle_handler);
  ...
  const publicAbi = {...circuit.abi, parameters: circuit.abi.parameters.filter(p => p.visibility == 'public') }
  let publicInputs = [...abiEncode(publicAbi, inputs).values()];
  publicInputs = publicInputs.concat([returnValue].flat(3).map(v => "0x"+BigInt(v as string).toString(16).padStart(64,'0')));
  let payload : ProofData = { proof: new Uint8Array(), publicInputs }
  
  if (!options.mockProof) {
    payload = await circuit.backend.generateProof(witness);
    ...
  }
  ...
  return { payload, ..., returnValue };
  ```
- Better to fail fast and reconsider tooling (from protocol, to circuits, to user interface) than to compromise with specifics features that might not yet be actually available. (Some written above as "roadbumps": libraries with bugs, missing recursive proving, and lacking language idioms).
For example, would be advisable to try executing, proving and verifying a trace of the first circuit on the final web enviroment, before advancing with other circuits. And verifiying the cryptographic libraries keep working correctly when imported in the target frontend and tested with real user data.
- Although feasible - general, verifiable and secure private shared state may require more research before becoming practical in time sensitive applications. Either by faster provers, lighter MPC protocols, or likely both. (Benchmarks for this project reached ~2 min/turn, ~500K bb gates. More details per circuit on the table in [report 2](https://hackmd.io/@FATSOLUTIONS/rkva88njkl).)
- Trying to force a proving framework (i.e. Noir tooling) into specific MPC primitives might have been an unwise move. Tooling selection derived from the problem requirements would most likely lead to better results. Be it other proving frameworks (e.g. [STARKs](https://eprint.iacr.org/2024/278)) or interaction protocols (e.g. [Laconic OT](https://eprint.iacr.org/2024/264)), to reduce proving times and messaging rounds respectively.
- noir gud
---

### Implications / Future development
- With this project, some provable MPC computation (i.e. private set intersections) over previously commited data has been shown to be feasible, although slow (for now?). The gates are open.
- What new usecases and applications will this unlock? How users can be empowered? How much work will be needed to implement secret agreements (on-chain contracts, with private shared state) owned by multiple parties, each with its own pieces of information, but collaboratively modifiable using MPC?
Nowadays, this seems to be a couple years in the future. But applications and ideas can be incubated today, exploring and understanding potential benefits to be unlocked, which in turn allows prioritizing future explorations. So, private programmable agreements on secret user data on global trust layer. Sounds fun. Your turn anon ...


---

### Open questions / Future research
This project has ended, but there are still many open paths that may be worth exploring. Including, but not limited to:

- What cryptographic primitives (signature aggregation, homomorphic encryption, etc.) are now unlocked by the existence of [noir_bigcurve](https://github.com/noir-lang/noir_bigcurve), what performance can be acheived, and how dev-friendly is that library? And importantly, how this performance compares to the same operations on other proving frameworks.
- Are application developers paying attention to the trust assumptions required by the MPC frameworks they rely on? Some tooling requires trusting that potentially malicious parties will simply not act in an attempt to learn private data, being only secure against a **semi-honest minority** (assumed to always follow the protocol, without ever sending maliciously crafted fake messages).
- Has there been any tools developed to "[boolify](https://github.com/privacy-scaling-explorations/boolify)" Noir’s ACIR? (That is, reducing the arithmetic circuit to low-level boolean operations only.) Would be useful for plugging into [existing](https://github.com/emp-toolkit/emp-agmpc) MPC stacks that are secure againts a **malicious dishonest majority**.
- Private shared state makes it possible to build privacy-first apps where multiple people interact without revealing their individual data. Beyond games, this could mean sealed-bid auctions where bids are only revealed at settlement, or private trading protocols where order flow stays encrypted but rules are enforced. Think funding rounds where investors prove commitments without exposing size or identity, or whitelisted mints where users prove eligibility without doxxing themselves. Terry Escape was a small sketch of this idea but with faster proving and better tooling, it’s easy to imagine this unlocking a broader class of coordination tools, not just for crypto, but for any system where coordination and privacy need to coexist.