Skip to content

Commit

Permalink
Unify zkvm acronym (Sovereign-Labs#936)
Browse files Browse the repository at this point in the history
* Start renaming

* [no ci] start renaming

* Update README for sov-modules-api
  • Loading branch information
citizen-stig authored Oct 3, 2023
1 parent 7c31500 commit 0f4f694
Show file tree
Hide file tree
Showing 17 changed files with 70 additions and 65 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ must implement. In the Sovereign SDK, we define a rollup as the combination of t
1. A [State Transition Function](./rollup-interface/specs/interfaces/stf.md) ("STF") which defines the "business logic" of the rollup
1. A [Data Availability Layer](./rollup-interface/specs/interfaces/da.md) ("DA layer") which determines the set of transactions that are fed
to the state transition function
1. A Zero Knowledge proving system (aka "Zero Knowledge Virtual Machine" or "ZKVM"), which takes the compiled rollup code and
1. A Zero Knowledge proving system (aka "Zero Knowledge Virtual Machine" or "zkVM"), which takes the compiled rollup code and
produces succinct proofs that the logic has been executed correctly.

One of the primary goals of the Sovereign SDK is to enable a clean separation of concerns between these three components.
Expand Down Expand Up @@ -104,7 +104,7 @@ If you want to add support for a new data availability layer, the easiest way to

Adapters contain the logic integrating 3rd party codebases into the Sovereign SDK. Over time, we expect Sovereign SDK
to have adapters for almost all Data Availability Layers and LLVM-compatible proof systems. Currently, we
maintain adapters for [`Risc0`](https://www.risczero.com) (a ZKVM) and [`Celestia`](https://www.celestia.org) a (DA layer).
maintain adapters for [`Risc0`](https://www.risczero.com) (a zkVM) and [`Celestia`](https://www.celestia.org) a (DA layer).
The Avail project also maintains an adapter for their DA layer, which can be found [here](https://github.com/availproject/avail-sovereign-da-adapter).
[Chainway](https://chainway.xyz/) team also maintains an open-source Bitcoin DA adapter for their Sovereign Rollup on Bitcoin, which can be found [here](https://github.com/chainwayxyz/bitcoin-da).

Expand Down
2 changes: 1 addition & 1 deletion examples/const-rollup-config/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

In Sovereign, many state transition functions require consensus critical configuration. For example, rollups on Celestia
need to configure a namespace which they check for data. This consensus critical configuration needs to be available
to packages at compile time, so that it is baked into the binary which is fed to the ZKVM. Otherwise, a malicious
to packages at compile time, so that it is baked into the binary which is fed to the zkVM. Otherwise, a malicious
prover might be able to overwrite this configuration at runtime and create valid-looking proofs that were run
over the wrong namespace.

Expand Down
4 changes: 2 additions & 2 deletions examples/demo-rollup/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ This is a demo full node running a simple Sovereign SDK rollup on [Celestia](htt

## What is This?

This demo shows how to integrate a State Transition Function (STF) with a Data Availability (DA) layer and a ZKVM to create a full
This demo shows how to integrate a State Transition Function (STF) with a Data Availability (DA) layer and a zkVM to create a full
zk-rollup. The code in this repository corresponds to running a full-node of the rollup, which executes
every transaction. If you want to see the logic for _proof generation_, check out the [demo-prover](../demo-prover/)
package instead.
Expand Down Expand Up @@ -333,7 +333,7 @@ The above setup runs Celestia node locally to avoid any external network depende

## How to Customize This Example

Any time you change out the state transition function, ZKVM, or DA layer of your rollup, you'll
Any time you change out the state transition function, zkVM, or DA layer of your rollup, you'll
need to tweak this full-node code. At the very least, you'll need to modify the dependencies. In most cases,
your full node will also need to be aware of the STF's initialization logic, and how it exposes RPC.

Expand Down
2 changes: 1 addition & 1 deletion examples/demo-rollup/src/rollup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ pub fn configure_prover<Vm: ZkvmHost, Da: DaService>(
pub enum DemoProverConfig {
/// Run the rollup verification logic inside the current process
Simulate,
/// Run the rollup verifier in a zkvm executor
/// Run the rollup verifier in a zkVM executor
Execute,
/// Run the rollup verifier and create a SNARK of execution
Prove,
Expand Down
2 changes: 1 addition & 1 deletion examples/demo-simple-stf/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ In this tutorial, we’ll build an STF which checks if the input data (called a

The [State Transition Function
interface](../../rollup-interface/specs/interfaces/stf.md) serves as the core component of our rollup, where the business logic will reside.
Implementations of this trait can be integrated with any ZKVM and DA Layer resulting in a fully functional rollup. To begin, we will create a structure called `CheckHashPreimageStf`, and implement the `StateTransitionFunction` trait for it. You can find the complete code in the `lib.rs` file, but we will go over the most important parts here:
Implementations of this trait can be integrated with any zkVM and DA Layer resulting in a fully functional rollup. To begin, we will create a structure called `CheckHashPreimageStf`, and implement the `StateTransitionFunction` trait for it. You can find the complete code in the `lib.rs` file, but we will go over the most important parts here:

```rust, ignore
pub struct CheckHashPreimageStf {}
Expand Down
6 changes: 3 additions & 3 deletions examples/demo-stf/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ interface](../../rollup-interface/specs/interfaces/stf.md) ("STF") , which speci
a related trait called `State Transition Runner` ("STR") which tells a full node how to instantiate your abstract STF on a concrete machine.

Strictly speaking, it's sufficient for a rollup to only implement the first interface. If you've done that, it's possible to integrate
with ZKVMs and DA Layers - but you'll have to customize your full node implementation a bit to deal with your particular rollup's
with zkVMs and DA Layers - but you'll have to customize your full node implementation a bit to deal with your particular rollup's
configuration. By implementing the STR trait, we make it much easier for the full-node implementation to understand how to interact
with the rollup generically - so we can keep our modifications to the node as minimal as possible. In this demo, we'll implement both traits.

Expand Down Expand Up @@ -168,7 +168,7 @@ to import your custom STF! But, when you're building an STF it's useful to stick
That way, you can minimize the changeset for your custom node implementation, which reduces the risk of bugs.

To help you integrate with full node implementations, we provide standard tools for initializing an app (`StateTransitionRunner`). In this section, we'll briefly show how to use them. Again it is not strictly
required - just by implementing STF, you get the capability to integrate with DA layers and ZKVMs. But, using these structures
required - just by implementing STF, you get the capability to integrate with DA layers and zkVMs. But, using these structures
makes you more compatible with full node implementations out of the box.

### Using State Transition Runner
Expand All @@ -184,4 +184,4 @@ The State Transition Runner struct contains logic related to initialization and

Whew, that was a lot of information. To recap, implementing your own state transition function is as simple as plugging
a Runtime, a Transaction Verifier, and some Transaction Hooks into the pre-built app template. Once you've done that,
you can integrate with any DA layer and ZKVM to create a Sovereign Rollup.
you can integrate with any DA layer and zkVM to create a Sovereign Rollup.
8 changes: 4 additions & 4 deletions full-node/sov-stf-runner/src/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,17 @@ where
prover: Option<Prover<V, Da, Vm>>,
}

/// Represents the possible modes of execution for a zkvm program
/// Represents the possible modes of execution for a zkVM program
pub enum ProofGenConfig<ST, Da: DaService, Vm: ZkvmHost>
where
ST: StateTransitionFunction<Vm::Guest, Da::Spec>,
{
/// The simulator runs the rollup verifier logic without even emulating the zkvm
/// The simulator runs the rollup verifier logic without even emulating the zkVM
Simulate(StateTransitionVerifier<ST, Da::Verifier, Vm::Guest>),
/// The executor runs the rollup verification logic in the zkvm, but does not actually
/// The executor runs the rollup verification logic in the zkVM, but does not actually
/// produce a zk proof
Execute,
/// The prover runs the rollup verification logic in the zkvm and produces a zk proof
/// The prover runs the rollup verification logic in the zkVM and produces a zk proof
Prover,
}

Expand Down
48 changes: 27 additions & 21 deletions module-system/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,25 +241,28 @@ which re-executes the transactions in a (more expensive) zk environment to creat
workflow looks roughly like this:

```rust
// First, execute transactions natively to generate a witness for the zkvm
let native_rollup_instance = my_state_transition::<DefaultContext>::new(config);
let witness = Default::default()
native_rollup_instance.begin_slot(witness);
for batch in batches.cloned() {
native_rollup_instance.apply_batch(batch);
use sov_modules_api::DefaultContext;
fn main() {
// First, execute transactions natively to generate a witness for the zkVM
let native_rollup_instance = my_state_transition::<DefaultContext>::new(config);
let witness = Default::default();
native_rollup_instance.begin_slot(witness);
for batch in batches.cloned() {
native_rollup_instance.apply_batch(batch);
}
let (_new_state_root, populated_witness) = native_rollup_instance.end_batch();

// Then, re-execute the state transitions in the zkVM using the witness
let proof = MyZkvm::prove(|| {
let zk_rollup_instance = my_state_transition::<ZkDefaultContext>::new(config);
zk_rollup_instance.begin_slot(populated_witness);
for batch in batches {
zk_rollup_instance.apply(batch);
}
let (new_state_root, _) = zk_rollup_instance.end_batch();
MyZkvm::commit(new_state_root)
});
}
let (_new_state_root, populated_witness) = native_rollup_instance.end_batch();

// Then, re-execute the state transitions in the zkvm using the witness
let proof = MyZkvm::prove(|| {
let zk_rollup_instance = my_state_transition::<ZkDefaultContext>::new(config);
zk_rollup_instance.begin_slot(populated_witness);
for batch in batches {
zk_rollup_instance.apply(batch);
}
let (new_state_root, _) = zk_rollup_instance.end_batch();
MyZkvm::commit(new_state_root)
})
```

This distinction between native _execution_ and zero-knowledge _re-execution_ is deeply baked into the Module System. We take the
Expand All @@ -272,16 +275,19 @@ The most important trait we use to enable this abstraction is the `Spec` trait.

```rust
pub trait Spec {
type Address;
type Storage;
type PrivateKey;
type PublicKey;
type Hasher;
type Signature;
type Witness;
}
```

As you can see, a `Spec` for a rollup specifies the concrete types that will be used for many kinds of cryptographic operations.
That way, you can define your business logic in terms of _abstract_ cryptography, and then instantiate it with cryptography which
is efficient in your particular choice of ZKVM.
That way, you can define your business logic in terms of _abstract_ cryptography, and then instantiate it with cryptography, which
is efficient in your particular choice of zkVM.

In addition to the `Spec` trait, the Module System provides a simple `Context` trait which is defined like this:

Expand Down Expand Up @@ -318,7 +324,7 @@ Similarly, since each of the banks helper functions is automatically generic ove
can abstract away the distinctions between `zk` and `native` execution. For example, when a rollup is running in native mode
its `Storage` type will almost certainly be [`ProverStorage`](./sov-state/src/prover_storage.rs), which holds its data in a
Merkle tree backed by RocksDB. But if you're running in zk mode the `Storage` type will instead be [`ZkStorage`](./sov-state/src/zk_storage.rs), which reads
its data from a set of "hints" provided by the prover. Because all of the rollups modules are generic, none of them need to worry
its data from a set of "hints" provided by the prover. Because all the rollups modules are generic, none of them need to worry
about this distinction.

For more information on `Context` and `Spec`, and to see some example implementations, check out the [`sov_modules_api`](./sov-modules-api/) docs.
2 changes: 1 addition & 1 deletion module-system/sov-modules-api/src/default_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ pub struct ZkDefaultContext {
impl Spec for ZkDefaultContext {
type Address = Address;
type Storage = ZkStorage<DefaultStorageSpec>;
type PublicKey = DefaultPublicKey;
#[cfg(feature = "native")]
type PrivateKey = DefaultPrivateKey;
type PublicKey = DefaultPublicKey;
type Hasher = sha2::Sha256;
type Signature = DefaultSignature;
type Witness = ArrayWitness;
Expand Down
10 changes: 5 additions & 5 deletions module-system/sov-modules-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ pub trait PrivateKey:
/// over a Context, rollup developers can easily optimize their code for different environments
/// by simply swapping out the Context (and by extension, the Spec).
///
/// For example, a rollup running in a STARK-based zkvm like Risc0 might pick Sha256 or Poseidon as its preferred hasher,
/// For example, a rollup running in a STARK-based zkVM like Risc0 might pick Sha256 or Poseidon as its preferred hasher,
/// while a rollup running in an elliptic-curve based SNARK such as `Placeholder` from the =nil; foundation might
/// prefer a Pedersen hash. By using a generic Context and Spec, a rollup developer can trivially customize their
/// code for either (or both!) of these environments without touching their module implementations.
Expand All @@ -221,17 +221,17 @@ pub trait Spec {
/// Authenticated state storage used by the rollup. Typically some variant of a merkle-patricia trie.
type Storage: Storage + Send + Sync;

/// The public key used for digital signatures
#[cfg(feature = "native")]
type PrivateKey: PrivateKey<PublicKey = Self::PublicKey, Signature = Self::Signature>;

/// The public key used for digital signatures
#[cfg(feature = "native")]
type PublicKey: PublicKey + ::schemars::JsonSchema + FromStr<Err = anyhow::Error>;

#[cfg(not(feature = "native"))]
type PublicKey: PublicKey;

/// The public key used for digital signatures
#[cfg(feature = "native")]
type PrivateKey: PrivateKey<PublicKey = Self::PublicKey, Signature = Self::Signature>;

/// The hasher preferred by the rollup, such as Sha256 or Poseidon.
type Hasher: Digest<OutputSize = U32>;

Expand Down
6 changes: 3 additions & 3 deletions module-system/sov-state/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

This crate provides abstractions specifically designed for storing and retrieving data from a permanent storage, tailored to be used within the Module System.

## High level explanation
## High-level explanation

At a high level, the crate offers two main abstractions that module developers can utilize to access data:

Expand Down Expand Up @@ -37,13 +37,13 @@ Module developers can interact with the `WorkingSet`, `StateValue`, and `StateMa

The above API is used in the following way:

```Rust
```rust
state.value.set(&some_value, working_set);
let maybe_value = state.value.get(working_set);

```

## Low level explanation
## Low-level explanation

It's important to note that an understanding of this section is not necessarily required for efficient usage of the `sov-state`.

Expand Down
6 changes: 3 additions & 3 deletions rollup-interface/specs/interfaces/stf.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ adaptive gas pricing depending on prover throughput.
- **Arguments**

| Name | Type | Description |
| ------------------ | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| witness | WITNESS | The witness to be used to process this slot. In prover mode, the witness argument is an empty struct which is populated with "hints" for the ZKVM during execution. In ZK mode, the argument is the pre-populated set of hints. |
| ------------------ | ------------------ |------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| witness | WITNESS | The witness to be used to process this slot. In prover mode, the witness argument is an empty struct which is populated with "hints" for the zkVM during execution. In ZK mode, the argument is the pre-populated set of hints. |
| slot_header | BLOCK_HEADER | The header of the block on the DA layer |
| validity_condition | VALIDITY_CONDITION | Data for any extra checks which must be made by light clients before accepting the state transition from this slot. For example, if the DA layer uses a verkle tree which is too expensive to open in-circuit, this might contain a merkle root of the observed slot data - which light clients would need to check "out-of-band". |
| blobs | BLOB_TRANSACTIONS | An iterator over the blobs included in this slot |
Expand Down Expand Up @@ -115,7 +115,7 @@ state of a particular instance of the state transition function.

### Witness

A custom type for each state transition function containing the hints that are passed to the ZKVM.
A custom type for each state transition function containing the hints that are passed to the zkVM.

## Optional Methods

Expand Down
25 changes: 12 additions & 13 deletions rollup-interface/specs/interfaces/zkvm.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# ZKVM
# zkVM

The sovereign SDK is designed to support any zkVM capable of running Rust code.
However, VMs must be capable of supporting a standard set of APIs.
Expand All @@ -7,7 +7,7 @@ However, VMs must be capable of supporting a standard set of APIs.

This specification does *not* define any standards relating to performance: proof size, prover work,
verification time, latency. This omission should not be understood to imply
that the SDK will work equally well for all choice of proof system. However, since, the SDK will *function* correctly when
that the SDK will work equally well for all choice of proof system. However, the SDK will *function* correctly when
defined in any sound proof system, we don't define any specific requirements.
We strongly suggest that users consider a performant VM such as Risc0.

Expand Down Expand Up @@ -59,17 +59,16 @@ when proof verification fails.

Expressed in Rust, zkVM would be a `trait` that looked something like the following:


```rust
pub trait ZkVM {
type CodeCommitment: PartialEq + Clone;
type Proof: Encode + Decode<Error = DeserializationError>;
type Error;

fn log<T: Encode>(item: T);
fn verify<T: Decode>(
proof: Self::Proof,
code_commitment: &Self::CodeCommitment,
) -> Result<T, Self::Error>;
pub trait Zkvm {
type CodeCommitment: PartialEq + Clone;
type Proof: Encode + Decode<Error=DeserializationError>;
type Error;

fn log<T: Encode>(item: T);
fn verify<T: Decode>(
proof: Self::Proof,
code_commitment: &Self::CodeCommitment,
) -> Result<T, Self::Error>;
}
```
Loading

0 comments on commit 0f4f694

Please sign in to comment.