added post
55835c29
1 file(s) · +138 −0
| 1 | + | --- |
|
| 2 | + | title: "How SP1 Precompiles Revolutionized zkVM Performance" |
|
| 3 | + | publishDate: "27 Oct 2024" |
|
| 4 | + | description: "Learn about Succinct, SP1, and how the innovation of Precompiles changed the zkVM space" |
|
| 5 | + | tags: ["zk", "succinct", "precompiles", "zkVM"] |
|
| 6 | + | ogImage: "https://dweb.mypinata.cloud/files/bafybeicrnbi7yt5wcnaiielxhvb5fb7mocl7k2ub43e3nqwlnfev4zekkm?img-format=webp" |
|
| 7 | + | --- |
|
| 8 | + | ||
| 9 | + | import { Image } from "astro:assets"; |
|
| 10 | + | ||
| 11 | + | <Image |
|
| 12 | + | src="https://dweb.mypinata.cloud/files/bafybeicrnbi7yt5wcnaiielxhvb5fb7mocl7k2ub43e3nqwlnfev4zekkm?img-format=webp" |
|
| 13 | + | alt="header image" |
|
| 14 | + | height={1080} |
|
| 15 | + | width={1920} |
|
| 16 | + | aspectRatio={9 / 16} |
|
| 17 | + | /> |
|
| 18 | + | ||
| 19 | + | In the last few years the terms "zk" or "zero knowledge proofs" have been buzzing and for good reasons. It's a relatively new piece of tech in cryptography that allows someone to prove something without revealing the information itself, which has massive implications for not only the blockchain space but for privacy and trusted code. While zk's are powerful, they also come at a cost. The majority of real-world use zero knowledge proofs are computationally expensive and inefficient, and in order to truly scale and make a difference, the cost needs to come down. This is where [Succinct](https://succinct.xyz/) comes in, a company that specializes in zkVM technology and makes it accessible to developers. Not only has Succinct built [SP1](https://blog.succinct.xyz/sp1-is-live/), an zkVM that allows you to write zero knowledge proofs in Rust, but they have also revolutionized efficiency with Precompiles. |
|
| 20 | + | ||
| 21 | + | ## What are Precompiles? |
|
| 22 | + | ||
| 23 | + | When it comes to writing zero knowledge proofs, there are generally many cryptographic operations and methods that become repetitive, especially when being used for blockchains. These include arithmetics like elliptic curves or hashes which are accessed in Rust through crates. While building SP1, Succinct realized that there could be improvements made if the execution of these programs happened through the RISC-V instruction used to make proofs. This created a balance between the ease of writing proofs in Rust but still having some of the benefits of custom circuits. The result was a series of patched crates of popular libraries that dramatically changed the speed and efficiency of zero knowledge proof calculation. |
|
| 24 | + | ||
| 25 | + | Instead of just taking my word for it, I'll show you how to spin up a quick SP1 project and we'll build proofs both with and without the precompile patches! |
|
| 26 | + | ||
| 27 | + | ## Proving the Performance |
|
| 28 | + | ||
| 29 | + | The best way to really experience these speed differences is to try SP1 out for yourself, so let's start with what you'll need to follow along. |
|
| 30 | + | ||
| 31 | + | - Install Rust - SP1 allows developers to write normal Rust to build zero knowledge proofs, so make sure to have it installed on your machine (preferably the nightly version). |
|
| 32 | + | - Install SP1 - After you have Rust installed the SP1 installation is quite straight forward. Just follow the instructions [here](https://docs.succinct.xyz/getting-started/install.html). |
|
| 33 | + | - Starter Repo - Finally you will want to clone the start repo that has everything built out. Run the following command and move into the project directory: `git clone https://github.com/stevedylandev/precompiles-demo && cd precompiles-demo` |
|
| 34 | + | ||
| 35 | + | Once you've gotten everything setup, let's do a quick walkthrough of the project structure. |
|
| 36 | + | ||
| 37 | + | ``` |
|
| 38 | + | . |
|
| 39 | + | ├── Cargo.lock |
|
| 40 | + | ├── Cargo.toml |
|
| 41 | + | ├── LICENSE-MIT |
|
| 42 | + | ├── README.md |
|
| 43 | + | ├── elf |
|
| 44 | + | │ └── riscv32im-succinct-zkvm-elf |
|
| 45 | + | ├── lib |
|
| 46 | + | │ ├── Cargo.toml |
|
| 47 | + | │ └── src |
|
| 48 | + | │ └── lib.rs |
|
| 49 | + | ├── program |
|
| 50 | + | │ ├── Cargo.toml |
|
| 51 | + | │ └── src |
|
| 52 | + | │ └── main.rs |
|
| 53 | + | ├── rust-toolchain |
|
| 54 | + | └── script |
|
| 55 | + | ├── Cargo.toml |
|
| 56 | + | ├── build.rs |
|
| 57 | + | └── src |
|
| 58 | + | └── bin |
|
| 59 | + | ``` |
|
| 60 | + | ||
| 61 | + | - `program` - In this folder we have the proof that we want to write in Rust. For our example we'll take an input and run it through a keccak256 hash. |
|
| 62 | + | - `script` - Here you will find a `bin` script that handles command arguments for either executing the program or generating the proof. It's recommended to use execute as the primary dev method since proving can be computationally expensive or take longer. |
|
| 63 | + | - `lib` - This directory has some helper structs that we'll use in the program for deserializing data. |
|
| 64 | + | - `elf` - The `elf` directory holds a special ELF (Executable and Linkable Format) file that is used to make our program and script programs talk to each other. |
|
| 65 | + | ||
| 66 | + | ||
| 67 | + | Now let's start testing. Run `cd program` to move into the program directory, and then run: |
|
| 68 | + | ||
| 69 | + | ``` |
|
| 70 | + | cargo prove build |
|
| 71 | + | ``` |
|
| 72 | + | ||
| 73 | + | This will build our program using SP1 and prepare it for the next step, execution. Once the build is finished run the following command: |
|
| 74 | + | ||
| 75 | + | ``` |
|
| 76 | + | cd ../script && cargo run --release -- --execute |
|
| 77 | + | ``` |
|
| 78 | + | ||
| 79 | + | This will start the bin command and will take a little time to run. Once complete you should see an output like this one: |
|
| 80 | + | ||
| 81 | + | ``` |
|
| 82 | + | 2024-10-27T04:45:04.296078Z INFO vk verification: true |
|
| 83 | + | n: Hello World from SP1! |
|
| 84 | + | 2024-10-27T04:45:04.388224Z INFO execute: close time.busy=6.23ms time.idle=14.2µs |
|
| 85 | + | Program executed successfully. |
|
| 86 | + | Input: Hello World from SP1! |
|
| 87 | + | Hash: 0x5de0efbc889e22250feb078959ad9aa6fb6c1301b94b3a8e6a10d49e47c074f2 |
|
| 88 | + | Number of cycles: 30635 |
|
| 89 | + | ``` |
|
| 90 | + | ||
| 91 | + | The once piece you'll want to note particularly is the cycle count. This is how many cycles were run on the circuits to produce the proof, and act as a measurement of computational efficiency. |
|
| 92 | + | ||
| 93 | + | With our base test out of the way with `30635` cycles, let's use our patched keccak library from SP1 to see the difference. We've already got the library listed in the `Cargo.toml` file inside the `program` directory: |
|
| 94 | + | ||
| 95 | + | ```toml |
|
| 96 | + | [package] |
|
| 97 | + | version = "0.1.0" |
|
| 98 | + | name = "keccak-program" |
|
| 99 | + | edition = "2021" |
|
| 100 | + | ||
| 101 | + | [dependencies] |
|
| 102 | + | tiny-keccak = { version = "2.0.2", features = ["keccak"] } |
|
| 103 | + | alloy-sol-types = { workspace = true } |
|
| 104 | + | sp1-zkvm = "3.0.0-rc4" |
|
| 105 | + | precompiles-demo = { path = "../lib" } |
|
| 106 | + | patched-tiny-keccak = { git = "https://github.com/sp1-patches/tiny-keccak", branch = "patch-v2.0.2", package = "tiny-keccak", features = [ |
|
| 107 | + | "keccak", |
|
| 108 | + | ] } |
|
| 109 | + | hex = "0.4.3" |
|
| 110 | + | ``` |
|
| 111 | + | ||
| 112 | + | To use it, we just need to update the top of the `program/src/main.rs` file to use `patched_tiny_keccak` instead of `tiny_keccak`. |
|
| 113 | + | ||
| 114 | + | ```rust |
|
| 115 | + | #![no_main] |
|
| 116 | + | sp1_zkvm::entrypoint!(main); |
|
| 117 | + | ||
| 118 | + | use alloy_sol_types::{private::FixedBytes, SolType}; |
|
| 119 | + | use precompiles_demo::PublicValuesStruct; |
|
| 120 | + | //use tiny_keccak::{Hasher, Keccak}; |
|
| 121 | + | use patched_tiny_keccak::{Hasher, Keccak}; |
|
| 122 | + | ``` |
|
| 123 | + | ||
| 124 | + | With the standard `tiny-keccak` library commented out and the patched one being put in in's place, let's navigate back to the `script` directory and run the same execute command. You should get some results like this: |
|
| 125 | + | ||
| 126 | + | ``` |
|
| 127 | + | n: Hello World from SP1! |
|
| 128 | + | Program executed successfully. |
|
| 129 | + | Input: Hello World from SP1! |
|
| 130 | + | Hash: 0x5de0efbc889e22250feb078959ad9aa6fb6c1301b94b3a8e6a10d49e47c074f2 |
|
| 131 | + | Number of cycles: 14259 |
|
| 132 | + | ``` |
|
| 133 | + | ||
| 134 | + | Just like that, our number of cycles has dropped by half! While this example is pretty elementary, in a much larger application with more computationally expensive programs the results seen are more efficient in magnitudes rather than just a 2x increase in performance. |
|
| 135 | + | ||
| 136 | + | ## Wrapping Up |
|
| 137 | + | ||
| 138 | + | While there has been many advances in zk technology, there is still much work to do for larger adoption. Writing zero knowledge proofs shouldn't take enormous amounts of time in low-level languages like assembly, and that's exactly why Succinct is making it easier with SP1. Even today there are dozens of teams using SP1 in production to help scale blockchains, rollups, bridges, and more. It's not hard to imagine a future where zkVMs are used in sectors beyond Web3, as there are many needs in our modern infrastructure for verifiable code, and Succinct will be there paving the way. |