### 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))
(Brief recap: "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).

> 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.
---
### Main 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
}
```
---
### Learnings
- 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.
- Trying to force a proving framework 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 or interaction protocols, for example.
- 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.
---
### Implications
- Some provable MPC computation (i.e. private set intersections) over previously commited data has been shown to be feasible, although slow. The gates are open. What new usecases and applications will this unlock? How users can be empowered?
---
### Open questions
- What is the rationale for hype around MPC tooling which relies on assuming no malicious party will attempt to extract private data?
- Has there been any tools developed to "[boolify](https://github.com/privacy-scaling-explorations/boolify)" Noir’s ACIR? Would be extremely useful for plugging into unbounded **maliciously secure** MPC stacks.
- What cryptographic primitives 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?