---
# System prepended metadata

title: ZK PoC

---

# ZK PoC

- Use [RISC ZERO](https://www.risczero.com/) as our zkVM. 
- [PoC Repo](https://github.com/bingyanglin/risc0-rust-examples/tree/ledger-poc)


## Current Progress
- [Flowchart](https://docs.google.com/presentation/d/1fMzQblrBzzYUwTzkHkTeqecNmkcRLXSPA73igDy0ix8/edit?usp=sharing)
- Already implemented the client/server-side APIs and programs which can
    - Rollup the transactions into a bundle
    - The operator can request the L2 (RISC0 VM) to rollup the transactions and generate a validity proof
      - Then the rolled-up transactions can be included in a new transaction and gossiped to other nodes
      - Note: The operator maintains the ledger state, which contains the transferring amount of each account of the users
    - The nodes (participants) can verify the validity proof to unlock the the new transaction

- What is lacking now

  - To integrating this item with an existing node
    - Create a tx which contains rolled up information (a batch of txs), and based on the ZK validity to unlock it
  - Integrating the PoC
    - Options of Codebase for the integration
      - iota.go
      - goshimmer
      - multiverse
  - The difficulty of the integration
    - iota.go
      - Need to hardcode the PoC into the stardust VM
      - Will have lots of technical debts due to the hardcoding
      - Will not use the results of the PoC in the future if we are going with L1 SC
    - goshimmer
      - hive.go (used by goshimmer) is under refactory and many conflicts (also might contain bugs hard to find/fix in a short time)
      - Goshimmer will be deprecated soon and a new repo will be created
      - THe unlock and alias logic is not touched for a long time and might be buggy
    - multiverse
      - Lacks of the unlock logic and alias logic
      - Don't have a concrete transaction structure for integrating our PoC

## RISC-0 Basics

- [Understanding the prover](https://www.risczero.com/docs/examples/starter)
- `Receipt`: Validity Proof (Journal + Seal)
  - The journal contains the public outputs of the computation.
  - The seal is an opaque cryptographic blob that attests to the integrity of the computation. It consists of merkle commitments and query data for an AIR-FRI STARK that includes a PLONK-based permutation argument.
- `Prover`: Take the ELF file and the ID
    - ELF: the binary file for `method` execution
      - Each method is used to generate the `commit`
      - ID: the hash of the ELF file

## Mockup
- Users can send a batch of transactions to this L2 zkVM with provided credentials. This zkVM will then generate a validity proof and send back to the user. The user then can directly use the proof to unlock the batch of transactions if the proof is verified valid.

## Specification
- A ledger records tokens transferring between addresses
    - The ledger contains addresses (a map)
        - key: address
        - value: token
- A ledger maintainer maintains the ledger, and is able to issue valid Transactions
    - The transaction contains receiver/sender addresses and tokens to be transferred)
- A valid issuing operation will mutate the ledger state

### core/src folder

- lib.rs (Define structures)
- The commit contain the `state`, whose type is `risc0_zkp::core::sha::Digest`

```rust
pub struct LedgerState {
    pub addresses: BTreeMap<String, u32>,
    pub transfer_count: u32
}


impl LedgerState {
    pub fn transfer(&mut self, receiver: &String, sender: &String, tokens: u32) -> bool{
        // Transfer tokens from a sender address to a receiver address
        // Return whether the transfer is successful or not
    }
}

pub struct InitializeLedgerCommit {
    pub state: Digest,
}

pub struct Transaction {
    pub receiver: String,
    pub sender: String,
    pub tokens: u32,
}

pub struct IssueTransactionCommit {
    pub old_state: Digest,
    pub new_state: Digest,
    pub receiver: String,
    pub sender: String,
    pub tokens: u32,
    pub transfer_counted: bool,
}

pub struct IssueTransactionParams {
    pub state: LedgerState,
    pub transaction: Transaction,
}


pub struct IssueTransactionResult {
    pub state: LedgerState,
    pub transfer_counted: bool,
    pub tokens: u32,
}

impl IssueTransactionParams {
    pub fn new(state: LedgerState, transaction: Transaction) -> Self {
        // Create a IssueTransactionParams
    }

    pub fn process(&self) -> IssueTransactionResult {
        // Transfer tokens from the sender address to the receiver address
        // Return the IssueTransactionResult
    }
}
```

### method folder

- guest/src/bin folder
  - init.rs
    - Generate the `InitializeLedgerCommit` by the RISC0 VM
  - issue.rs
    - Generate the `IssueTransactionCommit` by the RISC0 VM
- src folder
  - build.rs
    - `risc0_build::embed_methods()`

### host/src folder

- Contains the structures and methods for creating and verifying the receipt)
- lib.rs

  - `InitMessage` (contains Receipt)
    - `pub fn get_state(&self) -> Result<InitializeLedgerCommit>`
      - Get the state (receipt.journal)
    - `pub fn verify_and_get_commit(&self) -> Result<InitializeLedgerCommit>`
      - Verify the receipt by calling receipt.verify(), and return the commit
  - `IssueTransactionMessage` is similar to `InitMessage`
  - `LedgerMaintainer` (Generate the receipt by running the Prover)
    - `pub fn init(&self) -> Result<InitMessage>`
    - `pub fn issue(&mut self, ballot: &Transaction) -> Result<IssueTransactionMessage>`

- Testing
  - Create a new LedgerMaintainer
  - Prepare Transactions
  - Issue Transactions via the LedgerMaintainer, and get the IssueTransactionMessage
  - Verity IssueTransactionMessage
  - Check the transaction commits and the transfer_count

## How to run this PoC
- [Install Rust](https://www.rust-lang.org/tools/install)
- Run the test
```
cargo test --release 
```
- Run the client/server program
- Use two terminals
    - Go to the server folder
        - `cargo run --release`
    - Go to the client folder
        - `cargo run --release`

## Console Results


```ssh
running 1 test
[2023-02-02T10:49:18Z INFO  zk_poc] init
[2023-02-02T10:49:25Z INFO  zk_poc] issue: Transaction { receiver: "addressB", sender: "addressA", tokens: 100 }
[2023-02-02T10:49:33Z INFO  zk_poc] [0, 0, 0, 100, 4219768674, 3848250171, 2773697214, 2696326980, 2029397789, 624371590, 231552048, 2447920911, 4219768674, 3848250171, 2773697214, 2696326980, 2029397789, 624371590, 231552048, 2447920911, 8, 1919181921, 1114862437, 8, 1919181921, 1098085221, 100, 0]
[2023-02-02T10:49:33Z INFO  zk_poc] Ok(IssueTransactionResult { state: LedgerState { addresses: {}, transfer_count: 0 }, transfer_counted: false, tokens: 100 })
[2023-02-02T10:49:33Z INFO  zk_poc] issue: Transaction { receiver: "addressC", sender: "addressB", tokens: 50 }
[2023-02-02T10:49:40Z INFO  zk_poc] [0, 0, 0, 50, 4219768674, 3848250171, 2773697214, 2696326980, 2029397789, 624371590, 231552048, 2447920911, 4219768674, 3848250171, 2773697214, 2696326980, 2029397789, 624371590, 231552048, 2447920911, 8, 1919181921, 1131639653, 8, 1919181921, 1114862437, 50, 0]
[2023-02-02T10:49:40Z INFO  zk_poc] Ok(IssueTransactionResult { state: LedgerState { addresses: {}, transfer_count: 0 }, transfer_counted: false, tokens: 50 })
[2023-02-02T10:49:40Z INFO  zk_poc::tests] transfer count 0
[2023-02-02T10:49:40Z INFO  zk_poc::tests] initial commit: Ok(InitializeLedgerCommit { state: 628f84fb3ba35fe5be4253a544afb6a01d27f678862737253034cd0d0f4fe891 })
[2023-02-02T10:49:40Z INFO  zk_poc::tests] transaction 1: Transaction { receiver: "addressB", sender: "addressA", tokens: 100 }
[2023-02-02T10:49:40Z INFO  zk_poc::tests] transaction 1 commit: Ok(IssueTransactionCommit { old_state: 628f84fb3ba35fe5be4253a544afb6a01d27f678862737253034cd0d0f4fe891, new_state: 628f84fb3ba35fe5be4253a544afb6a01d27f678862737253034cd0d0f4fe891, receiver: "addressB", sender: "addressA", tokens: 100, transfer_counted: false })
[2023-02-02T10:49:40Z INFO  zk_poc::tests] transaction 2: Transaction { receiver: "addressC", sender: "addressB", tokens: 50 }
[2023-02-02T10:49:40Z INFO  zk_poc::tests] transaction 2 commit: Ok(IssueTransactionCommit { old_state: 628f84fb3ba35fe5be4253a544afb6a01d27f678862737253034cd0d0f4fe891, new_state: 628f84fb3ba35fe5be4253a544afb6a01d27f678862737253034cd0d0f4fe891, receiver: "addressC", sender: "addressB", tokens: 50, transfer_counted: false })
test tests::protocol ... ok
```