# 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
```