diff --git a/Cargo.lock b/Cargo.lock index 7c8951e52f..ebe5987a20 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7575,6 +7575,7 @@ dependencies = [ "anyhow", "bincode", "borsh", + "risc0-zkvm", "serde", "sov-rollup-interface", ] @@ -7809,6 +7810,7 @@ dependencies = [ "hex", "proptest", "proptest-derive", + "risc0-zkvm", "serde", "serde_json", "sha2", diff --git a/bin/citrea/provers/risc0/guest-bitcoin/Cargo.lock b/bin/citrea/provers/risc0/guest-bitcoin/Cargo.lock index 20b4ed2889..f5e22964c3 100644 --- a/bin/citrea/provers/risc0/guest-bitcoin/Cargo.lock +++ b/bin/citrea/provers/risc0/guest-bitcoin/Cargo.lock @@ -2912,6 +2912,7 @@ dependencies = [ "digest 0.10.7", "hex", "proptest", + "risc0-zkvm", "serde", "sha2", "thiserror", diff --git a/bin/citrea/provers/risc0/guest-mock/Cargo.lock b/bin/citrea/provers/risc0/guest-mock/Cargo.lock index 2ebad997f8..c303a57262 100644 --- a/bin/citrea/provers/risc0/guest-mock/Cargo.lock +++ b/bin/citrea/provers/risc0/guest-mock/Cargo.lock @@ -2679,6 +2679,7 @@ dependencies = [ "digest 0.10.7", "hex", "proptest", + "risc0-zkvm", "serde", "sha2", "thiserror", diff --git a/bin/citrea/src/rollup/bitcoin.rs b/bin/citrea/src/rollup/bitcoin.rs index a2b362a3c6..044b915f00 100644 --- a/bin/citrea/src/rollup/bitcoin.rs +++ b/bin/citrea/src/rollup/bitcoin.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use std::sync::Arc; use async_trait::async_trait; @@ -18,6 +19,7 @@ use sov_modules_stf_blueprint::StfBlueprint; use sov_prover_storage_manager::ProverStorageManager; use sov_rollup_interface::da::DaVerifier; use sov_rollup_interface::services::da::SenderWithNotifier; +use sov_rollup_interface::spec::SpecId; use sov_rollup_interface::zk::{Zkvm, ZkvmHost}; use sov_state::{DefaultStorageSpec, Storage, ZkStorage}; use sov_stf_runner::{FullNodeConfig, ProverConfig}; @@ -90,8 +92,10 @@ impl RollupBlueprint for BitcoinRollup { } #[instrument(level = "trace", skip(self), ret)] - fn get_code_commitment(&self) -> ::CodeCommitment { - Digest::new(citrea_risc0::BITCOIN_DA_ID) + fn get_code_commitments_by_spec(&self) -> HashMap::CodeCommitment> { + let mut map = HashMap::new(); + map.insert(SpecId::Genesis, Digest::new(citrea_risc0::BITCOIN_DA_ID)); + map } #[instrument(level = "trace", skip_all, err)] diff --git a/bin/citrea/src/rollup/mock.rs b/bin/citrea/src/rollup/mock.rs index b2da311337..a0b9da83f5 100644 --- a/bin/citrea/src/rollup/mock.rs +++ b/bin/citrea/src/rollup/mock.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use std::sync::Arc; use async_trait::async_trait; @@ -13,6 +14,7 @@ use sov_modules_api::{Address, Spec}; use sov_modules_rollup_blueprint::RollupBlueprint; use sov_modules_stf_blueprint::StfBlueprint; use sov_prover_storage_manager::ProverStorageManager; +use sov_rollup_interface::spec::SpecId; use sov_rollup_interface::zk::{Zkvm, ZkvmHost}; use sov_state::{DefaultStorageSpec, Storage, ZkStorage}; use sov_stf_runner::{FullNodeConfig, ProverConfig}; @@ -81,8 +83,10 @@ impl RollupBlueprint for MockDemoRollup { Ok(rpc_methods) } - fn get_code_commitment(&self) -> ::CodeCommitment { - Digest::new(citrea_risc0::MOCK_DA_ID) + fn get_code_commitments_by_spec(&self) -> HashMap::CodeCommitment> { + let mut map = HashMap::new(); + map.insert(SpecId::Genesis, Digest::new(citrea_risc0::MOCK_DA_ID)); + map } async fn create_da_service( diff --git a/bin/citrea/src/rollup/mod.rs b/bin/citrea/src/rollup/mod.rs index 117fd0e726..36a0292ea1 100644 --- a/bin/citrea/src/rollup/mod.rs +++ b/bin/citrea/src/rollup/mod.rs @@ -176,7 +176,7 @@ pub trait CitreaRollupBlueprint: RollupBlueprint { }, }; - let code_commitment = self.get_code_commitment(); + let code_commitments_by_spec = self.get_code_commitments_by_spec(); let current_l2_height = ledger_db .get_head_soft_confirmation() @@ -196,7 +196,7 @@ pub trait CitreaRollupBlueprint: RollupBlueprint { native_stf, storage_manager, init_variant, - code_commitment, + code_commitments_by_spec, rollup_config.sync_blocks_count, fork_manager, soft_confirmation_tx, @@ -280,7 +280,7 @@ pub trait CitreaRollupBlueprint: RollupBlueprint { }, }; - let code_commitment = self.get_code_commitment(); + let code_commitments_by_spec = self.get_code_commitments_by_spec(); let current_l2_height = ledger_db .get_head_soft_confirmation() @@ -302,7 +302,7 @@ pub trait CitreaRollupBlueprint: RollupBlueprint { init_variant, Some(prover_service), Some(prover_config), - code_commitment, + code_commitments_by_spec, rollup_config.sync_blocks_count, fork_manager, soft_confirmation_tx, diff --git a/crates/fullnode/src/runner.rs b/crates/fullnode/src/runner.rs index 160c7698b7..e2abaf50cd 100644 --- a/crates/fullnode/src/runner.rs +++ b/crates/fullnode/src/runner.rs @@ -1,4 +1,4 @@ -use std::collections::VecDeque; +use std::collections::{HashMap, VecDeque}; use std::marker::PhantomData; use std::net::SocketAddr; use std::sync::Arc; @@ -27,6 +27,7 @@ use sov_rollup_interface::da::{ }; use sov_rollup_interface::rpc::SoftConfirmationStatus; use sov_rollup_interface::services::da::{DaService, SlotData}; +use sov_rollup_interface::spec::SpecId; pub use sov_rollup_interface::stf::BatchReceipt; use sov_rollup_interface::stf::{SoftConfirmationReceipt, StateTransitionFunction}; use sov_rollup_interface::storage::HierarchicalStorageManager; @@ -65,7 +66,7 @@ where prover_da_pub_key: Vec, phantom: std::marker::PhantomData, include_tx_body: bool, - code_commitment: Vm::CodeCommitment, + code_commitments_by_spec: HashMap, accept_public_input_as_proven: bool, l1_block_cache: Arc>>, sync_blocks_count: u64, @@ -103,7 +104,7 @@ where stf: Stf, mut storage_manager: Sm, init_variant: InitVariant, - code_commitment: Vm::CodeCommitment, + code_commitments_by_spec: HashMap, sync_blocks_count: u64, fork_manager: ForkManager, soft_confirmation_tx: broadcast::Sender, @@ -151,7 +152,7 @@ where prover_da_pub_key: public_keys.prover_da_pub_key, phantom: std::marker::PhantomData, include_tx_body: runner_config.include_tx_body, - code_commitment, + code_commitments_by_spec, accept_public_input_as_proven: runner_config .accept_public_input_as_proven .unwrap_or(false), @@ -230,47 +231,39 @@ where l1_block.header().height() ); tracing::debug!("ZK proof: {:?}", proof); - let state_transition = match proof.clone() { - Proof::Full(proof) => { - let code_commitment = self.code_commitment.clone(); - tracing::warn!( - "using code commitment: {:?}", - serde_json::to_string(&code_commitment).unwrap() - ); + let (state_transition, receipt) = + Vm::extract_output::<::Spec, Stf::StateRoot>(&proof) + .expect("Proof should be deserializable"); + if state_transition.sequencer_da_public_key != self.sequencer_da_pub_key + || state_transition.sequencer_public_key != self.sequencer_pub_key + { + return Err(anyhow!( + "Proof verification: Sequencer public key or sequencer da public key mismatch. Skipping proof." + ).into()); + } - if let Ok(proof_data) = Vm::verify_and_extract_output::< - ::Spec, - Stf::StateRoot, - >(&proof, &code_commitment) - { - if proof_data.sequencer_da_public_key != self.sequencer_da_pub_key - || proof_data.sequencer_public_key != self.sequencer_pub_key - { - return Err(anyhow!( - "Proof verification: Sequencer public key or sequencer da public key mismatch. Skipping proof." - ).into()); - } - proof_data - } else { - return Err(anyhow!( - "Proof verification: SNARK verification failed. Skipping to next proof.." - ) - .into()); - } + match proof { + Proof::Full(_) => { + let receipt = receipt.expect("Receipt must exist with full proof"); + let code_commitment = self + .code_commitments_by_spec + .get(&state_transition.final_spec_id) + .expect("Proof public input must contain valid spec id"); + receipt + .verify(code_commitment.clone()) + .map_err(|err| anyhow!("Proof verification: SNARK verification failed: {}. Skipping to next proof...", err))?; } Proof::PublicInput(_) => { if !self.accept_public_input_as_proven { return Err(anyhow!( - "Found public input in da block number: {:?}, Skipping to next proof..", + "Found public input in da block number: {}, Skipping to next proof..", l1_block.header().height(), ) .into()); } - // public input is accepted only in tests, so ok to expect - Vm::extract_output(&proof).expect("Proof should be deserializable") } - }; + } let stored_state_transition = StoredStateTransition { initial_state_root: state_transition.initial_state_root.as_ref().to_vec(), diff --git a/crates/fullnode/tests/runner_initialization_tests.rs b/crates/fullnode/tests/runner_initialization_tests.rs index a4fd7edbf1..e4402ad570 100644 --- a/crates/fullnode/tests/runner_initialization_tests.rs +++ b/crates/fullnode/tests/runner_initialization_tests.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use std::sync::Arc; use citrea_fullnode::CitreaFullnode; @@ -115,6 +116,9 @@ fn initialize_runner( let fork_manager = ForkManager::new(forks, 0); + let mut code_commitments_by_spec = HashMap::new(); + code_commitments_by_spec.insert(SpecId::Genesis, MockCodeCommitment([1u8; 32])); + CitreaFullnode::new( rollup_config.runner.unwrap(), rollup_config.public_keys, @@ -124,7 +128,7 @@ fn initialize_runner( stf, storage_manager, init_variant, - MockCodeCommitment([1u8; 32]), + code_commitments_by_spec, 10, fork_manager, broadcast::channel(1).0, diff --git a/crates/prover/src/runner.rs b/crates/prover/src/runner.rs index 5ae94e83e6..fdd1a8fc4e 100644 --- a/crates/prover/src/runner.rs +++ b/crates/prover/src/runner.rs @@ -1,5 +1,5 @@ use core::panic; -use std::collections::VecDeque; +use std::collections::{HashMap, VecDeque}; use std::marker::PhantomData; use std::net::SocketAddr; use std::sync::Arc; @@ -26,6 +26,7 @@ use sov_modules_stf_blueprint::StfBlueprintTrait; use sov_rollup_interface::da::{BlockHeaderTrait, DaData, DaSpec, SequencerCommitment}; use sov_rollup_interface::rpc::SoftConfirmationStatus; use sov_rollup_interface::services::da::DaService; +use sov_rollup_interface::spec::SpecId; use sov_rollup_interface::stf::{SoftConfirmationReceipt, StateTransitionFunction}; use sov_rollup_interface::zk::{Proof, StateTransitionData, ZkvmHost}; use sov_stf_runner::{ @@ -71,7 +72,7 @@ where sequencer_da_pub_key: Vec, phantom: std::marker::PhantomData, prover_config: Option, - code_commitment: Vm::CodeCommitment, + code_commitments_by_spec: HashMap, l1_block_cache: Arc>>, sync_blocks_count: u64, fork_manager: ForkManager, @@ -111,7 +112,7 @@ where init_variant: InitVariant, prover_service: Option, prover_config: Option, - code_commitment: Vm::CodeCommitment, + code_commitments_by_spec: HashMap, sync_blocks_count: u64, fork_manager: ForkManager, soft_confirmation_tx: broadcast::Sender, @@ -158,7 +159,7 @@ where sequencer_da_pub_key: public_keys.sequencer_da_pub_key, phantom: std::marker::PhantomData, prover_config, - code_commitment, + code_commitments_by_spec, l1_block_cache: Arc::new(Mutex::new(L1BlockCache::new())), sync_blocks_count, fork_manager, @@ -790,28 +791,22 @@ where // l1_height => (tx_id, proof, transition_data) // save proof along with tx id to db, should be queriable by slot number or slot hash - let transition_data: sov_modules_api::StateTransition< - ::Spec, - Stf::StateRoot, - > = Vm::extract_output(&proof).expect("Proof should be deserializable"); + let (transition_data, receipt) = + Vm::extract_output::<::Spec, Stf::StateRoot>(&proof) + .expect("Proof should be deserializable"); match proof { Proof::PublicInput(_) => { warn!("Proof is public input, skipping"); } - Proof::Full(ref proof) => { + Proof::Full(_) => { info!("Verifying proof!"); - let transition_data_from_proof = - Vm::verify_and_extract_output::<::Spec, Stf::StateRoot>( - &proof.clone(), - &self.code_commitment, - ) - .expect("Proof should be verifiable"); - - info!( - "transition data from proof: {:?}", - transition_data_from_proof - ); + let receipt = receipt.expect("Receipt must exist in full proof"); + let code_commitment = self + .code_commitments_by_spec + .get(&transition_data.final_spec_id) + .expect("Proof public input must contain valid spec id"); + receipt.verify(code_commitment.clone())?; } } diff --git a/crates/risc0-bonsai/src/host.rs b/crates/risc0-bonsai/src/host.rs index b829e938da..f17c7c46a0 100644 --- a/crates/risc0-bonsai/src/host.rs +++ b/crates/risc0-bonsai/src/host.rs @@ -358,18 +358,24 @@ impl<'a> ZkvmHost for Risc0BonsaiHost<'a> { fn extract_output( proof: &Proof, - ) -> Result, Self::Error> { - let journal = match proof { + ) -> Result< + ( + sov_rollup_interface::zk::StateTransition, + Option, + ), + Self::Error, + > { + let (journal, receipt) = match proof { Proof::PublicInput(journal) => { let journal: Journal = bincode::deserialize(journal)?; - journal + (journal, None) } Proof::Full(data) => { let receipt: Receipt = bincode::deserialize(data)?; - receipt.journal + (receipt.journal.clone(), Some(receipt)) } }; - Ok(BorshDeserialize::try_from_slice(&journal.bytes)?) + Ok((BorshDeserialize::try_from_slice(&journal.bytes)?, receipt)) } fn recover_proving_sessions(&self) -> Result, anyhow::Error> { diff --git a/crates/sovereign-sdk/adapters/mock-zkvm/Cargo.toml b/crates/sovereign-sdk/adapters/mock-zkvm/Cargo.toml index c40998cb7e..433b8c01dd 100644 --- a/crates/sovereign-sdk/adapters/mock-zkvm/Cargo.toml +++ b/crates/sovereign-sdk/adapters/mock-zkvm/Cargo.toml @@ -16,6 +16,7 @@ publish = true anyhow = { workspace = true } borsh = { workspace = true } bincode = { workspace = true } +risc0-zkvm = { workspace = true } serde = { workspace = true } sov-rollup-interface = { path = "../../rollup-interface" } diff --git a/crates/sovereign-sdk/adapters/mock-zkvm/src/lib.rs b/crates/sovereign-sdk/adapters/mock-zkvm/src/lib.rs index c929bc0a8a..03a2e42817 100644 --- a/crates/sovereign-sdk/adapters/mock-zkvm/src/lib.rs +++ b/crates/sovereign-sdk/adapters/mock-zkvm/src/lib.rs @@ -7,6 +7,8 @@ use std::sync::{Arc, Condvar, Mutex}; use anyhow::ensure; use borsh::{BorshDeserialize, BorshSerialize}; +use risc0_zkvm::sha::Digest; +use risc0_zkvm::Receipt; use serde::{Deserialize, Serialize}; use sov_rollup_interface::da::BlockHeaderTrait; use sov_rollup_interface::spec::SpecId; @@ -22,6 +24,12 @@ impl Matches for MockCodeCommitment { } } +impl From for Digest { + fn from(val: MockCodeCommitment) -> Self { + Digest::from_bytes(val.0) + } +} + /// A mock proof generated by a zkVM. #[derive(Debug, Clone, PartialEq, Eq, BorshDeserialize, BorshSerialize, Serialize, Deserialize)] pub struct MockProof { @@ -172,26 +180,35 @@ impl sov_rollup_interface::zk::ZkvmHost } fn extract_output( - proof: &sov_rollup_interface::zk::Proof, - ) -> Result, Self::Error> { + proof: &Proof, + ) -> Result< + ( + sov_rollup_interface::zk::StateTransition, + Option, + ), + Self::Error, + > { match proof { sov_rollup_interface::zk::Proof::PublicInput(pub_input) => { let data: ProofInfo = bincode::deserialize(pub_input)?; let st: StateTransitionData = BorshDeserialize::deserialize(&mut &*data.hint)?; - Ok(sov_rollup_interface::zk::StateTransition { - initial_state_root: st.initial_state_root, - final_state_root: st.final_state_root, - initial_batch_hash: st.initial_batch_hash, - validity_condition: data.validity_condition, - state_diff: Default::default(), - da_slot_hash: st.da_block_header_of_commitments.hash(), - sequencer_public_key: vec![], - sequencer_da_public_key: vec![], - sequencer_commitments_range: (0, 0), - final_spec_id: SpecId::Genesis, - }) + Ok(( + sov_rollup_interface::zk::StateTransition { + initial_state_root: st.initial_state_root, + final_state_root: st.final_state_root, + initial_batch_hash: st.initial_batch_hash, + validity_condition: data.validity_condition, + state_diff: Default::default(), + da_slot_hash: st.da_block_header_of_commitments.hash(), + sequencer_public_key: vec![], + sequencer_da_public_key: vec![], + sequencer_commitments_range: (0, 0), + final_spec_id: SpecId::Genesis, + }, + None, + )) } sov_rollup_interface::zk::Proof::Full(_) => { panic!("Mock DA doesn't generate real proofs") diff --git a/crates/sovereign-sdk/adapters/risc0/src/host.rs b/crates/sovereign-sdk/adapters/risc0/src/host.rs index f1bcf2ce46..d75e97edbc 100644 --- a/crates/sovereign-sdk/adapters/risc0/src/host.rs +++ b/crates/sovereign-sdk/adapters/risc0/src/host.rs @@ -92,18 +92,24 @@ impl<'a> ZkvmHost for Risc0Host<'a> { fn extract_output( proof: &Proof, - ) -> Result, Self::Error> { - let journal = match proof { + ) -> Result< + ( + sov_rollup_interface::zk::StateTransition, + Option, + ), + Self::Error, + > { + let (journal, receipt) = match proof { Proof::PublicInput(journal) => { let journal: Journal = bincode::deserialize(journal)?; - journal + (journal, None) } Proof::Full(data) => { let receipt: Receipt = bincode::deserialize(data)?; - receipt.journal + (receipt.journal.clone(), Some(receipt)) } }; - Ok(BorshDeserialize::deserialize(&mut journal.bytes.as_ref())?) + Ok((BorshDeserialize::try_from_slice(&journal.bytes)?, receipt)) } fn recover_proving_sessions(&self) -> Result, anyhow::Error> { diff --git a/crates/sovereign-sdk/adapters/risc0/src/lib.rs b/crates/sovereign-sdk/adapters/risc0/src/lib.rs index b99bf2d2c4..0ca66f1676 100644 --- a/crates/sovereign-sdk/adapters/risc0/src/lib.rs +++ b/crates/sovereign-sdk/adapters/risc0/src/lib.rs @@ -48,3 +48,9 @@ impl Matches<[u32; 8]> for Risc0MethodId { &self.0 == other } } + +impl From for Digest { + fn from(val: Risc0MethodId) -> Self { + Digest::new(val.0) + } +} diff --git a/crates/sovereign-sdk/fuzz/Cargo.lock b/crates/sovereign-sdk/fuzz/Cargo.lock index cb24aa8862..e5f7ff40f7 100644 --- a/crates/sovereign-sdk/fuzz/Cargo.lock +++ b/crates/sovereign-sdk/fuzz/Cargo.lock @@ -102,6 +102,179 @@ dependencies = [ "derive_arbitrary", ] +[[package]] +name = "ark-bn254" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a22f4561524cd949590d78d7d4c5df8f592430d221f7f3c9497bbafd8972120f" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-std", +] + +[[package]] +name = "ark-crypto-primitives" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3a13b34da09176a8baba701233fdffbaa7c1b1192ce031a3da4e55ce1f1a56" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-relations", + "ark-serialize", + "ark-snark", + "ark-std", + "blake2", + "derivative", + "digest", + "sha2", +] + +[[package]] +name = "ark-ec" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" +dependencies = [ + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", + "itertools 0.10.5", + "num-traits", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm", + "ark-ff-macros", + "ark-serialize", + "ark-std", + "derivative", + "digest", + "itertools 0.10.5", + "num-bigint", + "num-traits", + "paste", + "rustc_version", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-groth16" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20ceafa83848c3e390f1cbf124bc3193b3e639b3f02009e0e290809a501b95fc" +dependencies = [ + "ark-crypto-primitives", + "ark-ec", + "ark-ff", + "ark-poly", + "ark-relations", + "ark-serialize", + "ark-std", +] + +[[package]] +name = "ark-poly" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +dependencies = [ + "ark-ff", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", +] + +[[package]] +name = "ark-relations" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00796b6efc05a3f48225e59cb6a2cda78881e7c390872d5786aaf112f31fb4f0" +dependencies = [ + "ark-ff", + "ark-std", + "tracing", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-serialize-derive", + "ark-std", + "digest", + "num-bigint", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-snark" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84d3cc6833a335bb8a600241889ead68ee89a3cf8448081fb7694c0fe503da63" +dependencies = [ + "ark-ff", + "ark-relations", + "ark-serialize", + "ark-std", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand", +] + [[package]] name = "arrayref" version = "0.3.8" @@ -292,6 +465,26 @@ dependencies = [ "syn_derive", ] +[[package]] +name = "bytemuck" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fd4c6dcc3b0aea2f5c0b4b82c2b15fe39ddbc76041a310848f4706edf76bb31" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc8b54b395f2fcfbb3d90c47b01c7f444d94d05bdeb775811dec868ac3bbc26" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.74", +] + [[package]] name = "byteorder" version = "1.5.0" @@ -528,6 +721,17 @@ dependencies = [ "zeroize", ] +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "derive_arbitrary" version = "1.3.2" @@ -559,10 +763,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", + "const-oid", "crypto-common", "subtle", ] +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + [[package]] name = "dyn-clone" version = "1.0.17" @@ -600,6 +811,12 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +[[package]] +name = "elf" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4445909572dbd556c457c849c4ca58623d84b27c8fff1e74b0b4227d8b90d17b" + [[package]] name = "equivalent" version = "1.0.1" @@ -823,6 +1040,12 @@ dependencies = [ "serde", ] +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + [[package]] name = "http" version = "1.1.0" @@ -1418,6 +1641,12 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "percent-encoding" version = "2.3.1" @@ -1712,6 +1941,136 @@ dependencies = [ "digest", ] +[[package]] +name = "risc0-binfmt" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4003dd96f2e323dfef431b21a2aaddee1c6791fc32dea8eb2bff1b438bf5caf6" +dependencies = [ + "anyhow", + "elf", + "risc0-zkp", + "risc0-zkvm-platform", + "serde", + "tracing", +] + +[[package]] +name = "risc0-circuit-recursion" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c4154d2fbbde5af02a1c35c90340c2749044f5d5cd7834251b616ffa28d467" +dependencies = [ + "anyhow", + "bytemuck", + "hex", + "risc0-core", + "risc0-zkp", + "tracing", +] + +[[package]] +name = "risc0-circuit-rv32im" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce836e7c553e63cbd807d15925ba5dd641a80cdee7d123619eaa60bb555ab014" +dependencies = [ + "anyhow", + "risc0-binfmt", + "risc0-core", + "risc0-zkp", + "risc0-zkvm-platform", + "serde", + "tracing", +] + +[[package]] +name = "risc0-core" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "047cc26c68c092d664ded7488dcac0462d9e31190e1598a7820fe4246d313583" +dependencies = [ + "bytemuck", + "rand_core", +] + +[[package]] +name = "risc0-groth16" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3309c7acaf46ed3d21df3841185afd8ea4aab9fb63dbd1974694dfdae276970" +dependencies = [ + "anyhow", + "ark-bn254", + "ark-ec", + "ark-groth16", + "ark-serialize", + "bytemuck", + "hex", + "num-bigint", + "risc0-binfmt", + "risc0-zkp", + "serde", +] + +[[package]] +name = "risc0-zkp" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae55272541351a2391e5051519b33bfdf41f5648216827cc2cb94a49b6937380" +dependencies = [ + "anyhow", + "blake2", + "bytemuck", + "cfg-if", + "digest", + "hex", + "hex-literal", + "paste", + "rand_core", + "risc0-core", + "risc0-zkvm-platform", + "serde", + "sha2", + "tracing", +] + +[[package]] +name = "risc0-zkvm" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f234694d9dabc1172cf418b7a3ba65447caad15b994f450e9941d2a7cc89e045" +dependencies = [ + "anyhow", + "bytemuck", + "cfg-if", + "getrandom", + "hex", + "risc0-binfmt", + "risc0-circuit-recursion", + "risc0-circuit-rv32im", + "risc0-core", + "risc0-groth16", + "risc0-zkp", + "risc0-zkvm-platform", + "rrs-lib", + "semver", + "serde", + "sha2", + "tracing", +] + +[[package]] +name = "risc0-zkvm-platform" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16735dab52ae8bf0dc30df78fce901b674f469dfd7b5f5dfddd54caea22f14d5" +dependencies = [ + "bytemuck", + "getrandom", + "libm", +] + [[package]] name = "rocksdb" version = "0.22.0" @@ -1728,6 +2087,16 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afab94fb28594581f62d981211a9a4d53cc8130bbcbbb89a0440d9b8e81a7746" +[[package]] +name = "rrs-lib" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4382d3af3a4ebdae7f64ba6edd9114fff92c89808004c4943b393377a25d001" +dependencies = [ + "downcast-rs", + "paste", +] + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -2227,6 +2596,7 @@ dependencies = [ "futures", "hex", "proptest", + "risc0-zkvm", "serde", "sha2", "thiserror", @@ -2800,6 +3170,20 @@ name = "zeroize" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.74", +] [[package]] name = "zstd-sys" diff --git a/crates/sovereign-sdk/module-system/sov-modules-rollup-blueprint/src/lib.rs b/crates/sovereign-sdk/module-system/sov-modules-rollup-blueprint/src/lib.rs index 5fd0b8b749..c71583c990 100644 --- a/crates/sovereign-sdk/module-system/sov-modules-rollup-blueprint/src/lib.rs +++ b/crates/sovereign-sdk/module-system/sov-modules-rollup-blueprint/src/lib.rs @@ -4,6 +4,7 @@ mod runtime_rpc; mod wallet; +use std::collections::HashMap; use std::sync::Arc; use async_trait::async_trait; @@ -12,6 +13,7 @@ use sov_db::ledger_db::LedgerDB; use sov_modules_api::{Context, DaSpec, Spec}; use sov_modules_stf_blueprint::{GenesisParams, Runtime as RuntimeTrait}; use sov_rollup_interface::services::da::DaService; +use sov_rollup_interface::spec::SpecId; use sov_rollup_interface::storage::HierarchicalStorageManager; use sov_rollup_interface::zk::{Zkvm, ZkvmHost}; use sov_state::Storage; @@ -63,8 +65,8 @@ pub trait RollupBlueprint: Sized + Send + Sync { /// Creates a new instance of the blueprint. fn new() -> Self; - /// Get code commitment. - fn get_code_commitment(&self) -> ::CodeCommitment; + /// Get code commitments by fork. + fn get_code_commitments_by_spec(&self) -> HashMap::CodeCommitment>; /// Creates RPC methods for the rollup. fn create_rpc_methods( diff --git a/crates/sovereign-sdk/rollup-interface/Cargo.toml b/crates/sovereign-sdk/rollup-interface/Cargo.toml index 476070f8e1..64d5b06944 100644 --- a/crates/sovereign-sdk/rollup-interface/Cargo.toml +++ b/crates/sovereign-sdk/rollup-interface/Cargo.toml @@ -14,7 +14,6 @@ exclude = [ "specs/assets/*", ] - [dependencies] anyhow = { workspace = true } async-trait = { workspace = true } @@ -22,6 +21,7 @@ borsh = { workspace = true } bytes = { workspace = true, optional = true, default-features = true } digest = { workspace = true } hex = { workspace = true } +risc0-zkvm = { workspace = true } serde = { workspace = true } sha2 = { workspace = true, optional = true } thiserror = { workspace = true, optional = true } diff --git a/crates/sovereign-sdk/rollup-interface/src/spec.rs b/crates/sovereign-sdk/rollup-interface/src/spec.rs index d48c63ed0a..85a30b26cf 100644 --- a/crates/sovereign-sdk/rollup-interface/src/spec.rs +++ b/crates/sovereign-sdk/rollup-interface/src/spec.rs @@ -18,6 +18,7 @@ mod spec { BorshSerialize, Serialize, Deserialize, + Hash, )] #[borsh(use_discriminant = true)] pub enum SpecId { @@ -42,6 +43,7 @@ mod spec { BorshSerialize, Serialize, Deserialize, + Hash, )] #[borsh(use_discriminant = true)] pub enum SpecId { diff --git a/crates/sovereign-sdk/rollup-interface/src/state_machine/zk/mod.rs b/crates/sovereign-sdk/rollup-interface/src/state_machine/zk/mod.rs index 2632f16297..7e34424d47 100644 --- a/crates/sovereign-sdk/rollup-interface/src/state_machine/zk/mod.rs +++ b/crates/sovereign-sdk/rollup-interface/src/state_machine/zk/mod.rs @@ -15,6 +15,7 @@ use core::fmt::Debug; use borsh::{BorshDeserialize, BorshSerialize}; use digest::Digest; +use risc0_zkvm::Receipt; use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; @@ -51,10 +52,10 @@ pub trait ZkvmHost: Zkvm + Clone { /// with some mild performance overhead and is not as easy to debug as [`simulate_with_hints`](ZkvmHost::simulate_with_hints). fn run(&mut self, with_proof: bool) -> Result; - /// Extracts public input form the proof. + /// Extracts public input and receipt from the proof. fn extract_output( proof: &Proof, - ) -> Result, Self::Error>; + ) -> Result<(StateTransition, Option), Self::Error>; /// Host recovers pending proving sessions and returns proving results fn recover_proving_sessions(&self) -> Result, anyhow::Error>; @@ -64,7 +65,11 @@ pub trait ZkvmHost: Zkvm + Clone { /// Must support recursive proofs. pub trait Zkvm: Send + Sync { /// A commitment to the zkVM program which is being proven - type CodeCommitment: Clone + Debug + Serialize + DeserializeOwned; + type CodeCommitment: Clone + + Debug + + Serialize + + DeserializeOwned + + Into; /// The error type which is returned when a proof fails to verify type Error: Debug;