mirror of
https://github.com/logos-blockchain/logos-blockchain-pocs.git
synced 2026-01-09 16:43:09 +00:00
Finish implementation of the stf
This commit is contained in:
parent
447efee968
commit
ce6569b7a5
@ -1,5 +1,11 @@
|
||||
[workspace]
|
||||
resolver = "2"
|
||||
members = ["app"]
|
||||
members = ["app", "stf/host", "stf/methods"]
|
||||
|
||||
# Always optimize; building and running the guest takes much longer without optimization.
|
||||
[profile.dev]
|
||||
opt-level = 3
|
||||
|
||||
[profile.release]
|
||||
debug = 1
|
||||
lto = true
|
||||
|
||||
@ -5,4 +5,5 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
cl = { path = "../../../cl/cl" }
|
||||
risc0-zkvm = "1.2"
|
||||
risc0-zkvm = "1.2"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
@ -1,25 +1,14 @@
|
||||
use cl::{
|
||||
crust::{
|
||||
balance::{UnitWitness, NOP_COVENANT},
|
||||
Nullifier, Tx, Unit,
|
||||
},
|
||||
mantle::{ledger::Ledger, ZoneId, ZoneState},
|
||||
crust::{InputWitness, Nullifier, NullifierSecret, Tx, Unit},
|
||||
mantle::ZoneId,
|
||||
};
|
||||
use risc0_zkvm::sha::rust_crypto::{Digest, Sha256};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
|
||||
const SWAP_GOAL_UNIT: UnitWitness = UnitWitness {
|
||||
spending_covenant: NOP_COVENANT,
|
||||
minting_covenant: NOP_COVENANT,
|
||||
burning_covenant: NOP_COVENANT,
|
||||
};
|
||||
|
||||
pub struct SwapVmPrivate {
|
||||
pub old: ZoneState,
|
||||
pub new_ledger: Ledger,
|
||||
pub data: ZoneData,
|
||||
}
|
||||
const FUNDS_SK: NullifierSecret = NullifierSecret([0; 16]);
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Swap {
|
||||
pair: Pair,
|
||||
t0_in: u64,
|
||||
@ -28,36 +17,42 @@ pub struct Swap {
|
||||
t1_out: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct AddLiquidity {
|
||||
pair: Pair,
|
||||
t0_in: u64,
|
||||
t1_in: u64,
|
||||
_pair: Pair,
|
||||
_t0_in: u64,
|
||||
_t1_in: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct RemoveLiquidity {
|
||||
shares: Unit,
|
||||
_shares: Unit,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ZoneData {
|
||||
nfs: BTreeSet<Nullifier>,
|
||||
pools: BTreeMap<Pair, Pool>,
|
||||
zone_id: ZoneId,
|
||||
pub nfs: BTreeSet<Nullifier>,
|
||||
pub pools: BTreeMap<Pair, Pool>,
|
||||
pub zone_id: ZoneId,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
|
||||
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Pair {
|
||||
pub t0: Unit,
|
||||
pub t1: Unit,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Pool {
|
||||
pub balance_0: u64,
|
||||
pub balance_1: u64,
|
||||
}
|
||||
|
||||
/// Prove the data was part of the tx output
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct OutputDataProof;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum ZoneOp {
|
||||
Swap {
|
||||
tx: Tx,
|
||||
@ -97,7 +92,7 @@ impl ZoneData {
|
||||
let balance_1_final = balance_1_start + swap.t1_in as u128 - swap.t1_out as u128;
|
||||
|
||||
(balance_0_final * 1000 - 3 * swap.t0_in as u128)
|
||||
* (balance_0_final * 1000 - 3 * swap.t1_in as u128)
|
||||
* (balance_1_final * 1000 - 3 * swap.t1_in as u128)
|
||||
== balance_0_start * balance_1_start
|
||||
}
|
||||
|
||||
@ -112,9 +107,7 @@ impl ZoneData {
|
||||
|
||||
pub fn validate_op(&self, op: &ZoneOp) -> bool {
|
||||
match op {
|
||||
ZoneOp::Swap { tx, swap, proof } => {
|
||||
self.check_swap(&swap) && self.validate_no_pools(&tx)
|
||||
}
|
||||
ZoneOp::Swap { tx, swap, .. } => self.check_swap(&swap) && self.validate_no_pools(&tx), // TODO: check proof
|
||||
ZoneOp::AddLiquidity { tx, .. } => self.validate_no_pools(&tx),
|
||||
ZoneOp::RemoveLiquidity { tx, .. } => self.validate_no_pools(&tx), // should we check shares exist?
|
||||
ZoneOp::Ledger(tx) => {
|
||||
@ -125,6 +118,37 @@ impl ZoneData {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pools_update(&mut self, tx: &Tx, notes: &[InputWitness]) {
|
||||
// check all previous nullifiers are used
|
||||
assert!(self.nfs.iter().all(|nf| tx
|
||||
.updates
|
||||
.iter()
|
||||
.filter(|u| u.zone_id == self.zone_id)
|
||||
.flat_map(|u| u.inputs.iter())
|
||||
.find(|nf2| *nf2 == nf)
|
||||
.is_some()));
|
||||
self.nfs.clear();
|
||||
|
||||
// check the exepected pool balances are reflected in the tx outputs
|
||||
let outputs = tx
|
||||
.updates
|
||||
.iter()
|
||||
.filter(|u| u.zone_id == self.zone_id)
|
||||
.flat_map(|u| u.outputs.iter())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let expected_pool_balances = self.expected_pool_balances();
|
||||
for note in notes {
|
||||
assert_eq!(note.nf_sk, FUNDS_SK);
|
||||
// TODO: check nonce derivation
|
||||
let output = note.to_output();
|
||||
let value = expected_pool_balances.get(&output.unit).unwrap();
|
||||
assert_eq!(note.value, *value);
|
||||
assert!(outputs.contains(&&output.note_commitment()));
|
||||
self.nfs.insert(note.nullifier());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expected_pool_balances(&self) -> BTreeMap<Unit, u64> {
|
||||
let mut expected_pool_balances = BTreeMap::new();
|
||||
for (Pair { t0, t1 }, pool) in self.pools.iter() {
|
||||
@ -137,22 +161,15 @@ impl ZoneData {
|
||||
|
||||
pub fn process_op(&mut self, op: &ZoneOp) {
|
||||
match op {
|
||||
ZoneOp::Swap { tx, swap, proof } => {
|
||||
ZoneOp::Swap { tx, swap, .. } => {
|
||||
self.swap(&swap);
|
||||
self.validate_no_pools(&tx);
|
||||
// TODO: check the proof
|
||||
}
|
||||
ZoneOp::AddLiquidity {
|
||||
tx,
|
||||
add_liquidity,
|
||||
proof,
|
||||
} => {
|
||||
ZoneOp::AddLiquidity { .. } => {
|
||||
todo!()
|
||||
}
|
||||
ZoneOp::RemoveLiquidity {
|
||||
tx,
|
||||
remove_liquidity,
|
||||
proof,
|
||||
} => {
|
||||
ZoneOp::RemoveLiquidity { .. } => {
|
||||
todo!()
|
||||
}
|
||||
ZoneOp::Ledger(tx) => {
|
||||
@ -163,6 +180,10 @@ impl ZoneData {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_and_commit(self) -> ZoneData {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn commit(&self) -> [u8; 32] {
|
||||
let mut hasher = Sha256::new();
|
||||
for nf in &self.nfs {
|
||||
|
||||
@ -1,14 +0,0 @@
|
||||
[workspace]
|
||||
resolver = "2"
|
||||
members = ["host", "methods"]
|
||||
|
||||
[dependencies]
|
||||
app = { path = "../app" }
|
||||
|
||||
# Always optimize; building and running the guest takes much longer without optimization.
|
||||
[profile.dev]
|
||||
opt-level = 3
|
||||
|
||||
[profile.release]
|
||||
debug = 1
|
||||
lto = true
|
||||
@ -8,3 +8,6 @@ methods = { path = "../methods" }
|
||||
risc0-zkvm = { version = "1.2.0" }
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||
serde = "1.0"
|
||||
ledger_proof_statements = { path = "../../../../cl/ledger_proof_statements" }
|
||||
app = { path = "../../app" }
|
||||
cl = { path = "../../../../cl/cl" }
|
||||
32
emmarin/apps/swapvm/stf/host/src/lib.rs
Normal file
32
emmarin/apps/swapvm/stf/host/src/lib.rs
Normal file
@ -0,0 +1,32 @@
|
||||
// These constants represent the RISC-V ELF and the image ID generated by risc0-build.
|
||||
// The ELF is used for proving and the ID is used for verification.
|
||||
use app::ZoneOp;
|
||||
use cl::mantle::{ledger::Ledger, zone::ZoneData};
|
||||
use ledger_proof_statements::ledger::SyncLog;
|
||||
use methods::{STF_ELF, STF_ID};
|
||||
use risc0_zkvm::{ExecutorEnv, Prover, Receipt, Result};
|
||||
|
||||
pub struct StfPrivate {
|
||||
pub zone_data: ZoneData,
|
||||
pub old_ledger: Ledger,
|
||||
pub new_ledger: Ledger,
|
||||
pub sync_logs: Vec<SyncLog>,
|
||||
pub ops: Vec<ZoneOp>,
|
||||
}
|
||||
|
||||
impl StfPrivate {
|
||||
pub fn prove(&self, prover: &impl Prover) -> Result<Receipt> {
|
||||
let env = ExecutorEnv::builder()
|
||||
.write(&self.zone_data)?
|
||||
.write(&self.old_ledger)?
|
||||
.write(&self.new_ledger)?
|
||||
.write(&self.sync_logs)?
|
||||
.write(&STF_ID)?
|
||||
.build()?;
|
||||
|
||||
let prove_info = prover.prove(env, STF_ELF)?;
|
||||
|
||||
debug_assert!(prove_info.receipt.verify(STF_ID).is_ok());
|
||||
Ok(prove_info.receipt)
|
||||
}
|
||||
}
|
||||
@ -1,56 +0,0 @@
|
||||
// These constants represent the RISC-V ELF and the image ID generated by risc0-build.
|
||||
// The ELF is used for proving and the ID is used for verification.
|
||||
use methods::{
|
||||
STF_ELF, STF_ID
|
||||
};
|
||||
use risc0_zkvm::{default_prover, ExecutorEnv};
|
||||
|
||||
fn main() {
|
||||
// Initialize tracing. In order to view logs, run `RUST_LOG=info cargo run`
|
||||
tracing_subscriber::fmt()
|
||||
.with_env_filter(tracing_subscriber::filter::EnvFilter::from_default_env())
|
||||
.init();
|
||||
|
||||
// An executor environment describes the configurations for the zkVM
|
||||
// including program inputs.
|
||||
// A default ExecutorEnv can be created like so:
|
||||
// `let env = ExecutorEnv::builder().build().unwrap();`
|
||||
// However, this `env` does not have any inputs.
|
||||
//
|
||||
// To add guest input to the executor environment, use
|
||||
// ExecutorEnvBuilder::write().
|
||||
// To access this method, you'll need to use ExecutorEnv::builder(), which
|
||||
// creates an ExecutorEnvBuilder. When you're done adding input, call
|
||||
// ExecutorEnvBuilder::build().
|
||||
|
||||
// For example:
|
||||
let input: u32 = 15 * u32::pow(2, 27) + 1;
|
||||
let env = ExecutorEnv::builder()
|
||||
.write(&input)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
// Obtain the default prover.
|
||||
let prover = default_prover();
|
||||
|
||||
// Proof information by proving the specified ELF binary.
|
||||
// This struct contains the receipt along with statistics about execution of the guest
|
||||
let prove_info = prover
|
||||
.prove(env, STF_ELF)
|
||||
.unwrap();
|
||||
|
||||
// extract the receipt.
|
||||
let receipt = prove_info.receipt;
|
||||
|
||||
// TODO: Implement code for retrieving receipt journal here.
|
||||
|
||||
// For example:
|
||||
let _output: u32 = receipt.journal.decode().unwrap();
|
||||
|
||||
// The receipt was verified at the end of proving, but the below code is an
|
||||
// example of how someone else could verify this receipt.
|
||||
receipt
|
||||
.verify(STF_ID)
|
||||
.unwrap();
|
||||
}
|
||||
@ -3,6 +3,9 @@ name = "methods"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
app = { path = "../../app" }
|
||||
|
||||
[build-dependencies]
|
||||
risc0-build = { version = "1.2.0" }
|
||||
|
||||
|
||||
@ -7,3 +7,7 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
risc0-zkvm = { version = "1.2.0", default-features = false, features = ['std'] }
|
||||
app = { path = "../../../app" }
|
||||
ledger_proof_statements = { path = "../../../../../cl/ledger_proof_statements" }
|
||||
cl = { path = "../../../../../cl/cl" }
|
||||
ledger_validity_proof = { path = "../../../../../cl/ledger_validity_proof" }
|
||||
@ -1,50 +1,80 @@
|
||||
use app::{ZoneData, ZoneOp};
|
||||
use cl::{
|
||||
crust::Tx,
|
||||
mantle::{ledger::Ledger, zone::ZoneState},
|
||||
};
|
||||
use ledger_proof_statements::{
|
||||
ledger::{LedgerProofPublic, SyncLog},
|
||||
stf::StfPublic,
|
||||
};
|
||||
use risc0_zkvm::guest::env;
|
||||
|
||||
fn main() {
|
||||
let mut inputs: SwapVmPrivate = env::read();
|
||||
let mut zone_data: ZoneData = env::read();
|
||||
let old_ledger: Ledger = env::read();
|
||||
let ledger: Ledger = env::read();
|
||||
let sync_logs: Vec<SyncLog> = env::read();
|
||||
let stf: [u8; 32] = env::read();
|
||||
let ops: Vec<ZoneOp> = env::read();
|
||||
|
||||
let zone_id = inputs.zone_data.zone_id;
|
||||
let zone_id = zone_data.zone_id;
|
||||
|
||||
assert_eq!(inputs.zone_data.commit(), inputs.old.zone_data);
|
||||
let old_zone_data = zone_data.commit();
|
||||
|
||||
for op in ops {
|
||||
zone_data.process_op(tx);
|
||||
for op in &ops {
|
||||
zone_data.process_op(op);
|
||||
}
|
||||
|
||||
let txs = ops
|
||||
let txs: Vec<&Tx> = ops
|
||||
.iter()
|
||||
.map(|op| match op {
|
||||
ZoneOp::Swap { tx, swap, proof } => tx,
|
||||
ZoneOp::Swap { tx, .. } => tx,
|
||||
ZoneOp::AddLiquidity { tx, .. } => tx,
|
||||
ZoneOp::RemoveLiquidity { tx, .. } => tx,
|
||||
ZoneOp::Ledger(tx) => tx,
|
||||
})
|
||||
.collect();
|
||||
|
||||
let sync_logs = vec![]; // get this from outside
|
||||
|
||||
let outputs = txs
|
||||
.iter()
|
||||
.flat_map(|tx| tx.outputs.clone())
|
||||
.filter(|o| o.zone_id == zone_id)
|
||||
.flat_map(|tx| tx.updates.iter().filter(|u| u.zone_id == zone_id))
|
||||
.flat_map(|u| u.outputs.iter())
|
||||
.copied()
|
||||
.collect();
|
||||
let inputs = txs
|
||||
// TODO: inputs missings from ledger proof public
|
||||
let _inputs: Vec<_> = txs
|
||||
.iter()
|
||||
.flat_map(|tx| tx.inputs.clone())
|
||||
.filter(|i| i.zone_id == zone_id)
|
||||
.flat_map(|tx| tx.updates.iter().filter(|u| u.zone_id == zone_id))
|
||||
.flat_map(|u| u.inputs.iter())
|
||||
.copied()
|
||||
.collect();
|
||||
|
||||
let ledger_public = LedgerProofPublic {
|
||||
old_ledger: inputs.old.ledger,
|
||||
ledger: inputs.new_ledger,
|
||||
old_ledger,
|
||||
ledger,
|
||||
id: zone_id,
|
||||
sync_log,
|
||||
sync_logs,
|
||||
outputs,
|
||||
};
|
||||
|
||||
env::verify(
|
||||
ledger_validity_proof::LEDGER_ID,
|
||||
&serde::to_vec(&ledger_public).unwrap(),
|
||||
&risc0_zkvm::serde::to_vec(&ledger_public).unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let public = StfPublic {
|
||||
old: ZoneState {
|
||||
ledger: old_ledger,
|
||||
zone_data: old_zone_data,
|
||||
stf,
|
||||
},
|
||||
new: ZoneState {
|
||||
ledger,
|
||||
zone_data: zone_data.commit(),
|
||||
stf,
|
||||
},
|
||||
};
|
||||
|
||||
env::commit(&public);
|
||||
}
|
||||
|
||||
@ -73,6 +73,17 @@ impl InputWitness {
|
||||
self.nf_sk.commit(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn to_output(&self) -> OutputWitness {
|
||||
OutputWitness {
|
||||
state: self.state,
|
||||
value: self.value,
|
||||
unit: self.unit_witness.unit(),
|
||||
nonce: self.nonce,
|
||||
zone_id: self.zone_id,
|
||||
nf_pk: self.nf_sk.commit(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user