diff --git a/emmarin/apps/swapvm/app/Cargo.toml b/emmarin/apps/swapvm/app/Cargo.toml index 069b7d8..71b2f9e 100644 --- a/emmarin/apps/swapvm/app/Cargo.toml +++ b/emmarin/apps/swapvm/app/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] +rand = "0.8.5" cl = { path = "../../../cl/cl" } risc0-zkvm = "1.2" -serde = { version = "1.0", features = ["derive"] } \ No newline at end of file +serde = { version = "1.0", features = ["derive"] } diff --git a/emmarin/apps/swapvm/app/src/lib.rs b/emmarin/apps/swapvm/app/src/lib.rs index c5bf27c..b7d4837 100644 --- a/emmarin/apps/swapvm/app/src/lib.rs +++ b/emmarin/apps/swapvm/app/src/lib.rs @@ -6,11 +6,76 @@ use cl::{ }, mantle::ZoneId, }; +use rand::RngCore; use risc0_zkvm::sha::rust_crypto::{Digest, Sha256}; use serde::{Deserialize, Serialize}; use std::collections::{BTreeMap, BTreeSet}; const FUNDS_SK: NullifierSecret = NullifierSecret([0; 16]); +pub const ZONE_ID: [u8; 32] = [128; 32]; + +pub fn swap_goal_unit() -> UnitWitness { + UnitWitness::nop(b"SWAP") +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +pub struct SwapOutput { + // value will be set at the market price + pub state: [u8; 32], + pub unit: Unit, + pub nonce: Nonce, + pub zone_id: ZoneId, + pub nf_pk: NullifierCommitment, +} +impl SwapOutput { + pub fn basic( + unit: Unit, + zone_id: ZoneId, + nf_pk: NullifierCommitment, + rng: impl RngCore, + ) -> Self { + Self { + state: [0; 32], + unit, + nonce: Nonce::random(rng), + zone_id, + nf_pk, + } + } +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct SwapArgs { + // the user specifies the template forthe output note + pub output: SwapOutput, + // minimum value of the output note + pub limit: u64, +} + +impl SwapArgs { + pub fn to_output(self, value: u64) -> OutputWitness { + assert!(value >= self.limit); + OutputWitness { + state: self.output.state, + value, + unit: self.output.unit, + nonce: self.output.nonce, + zone_id: self.output.zone_id, + nf_pk: self.output.nf_pk, + } + } +} + +pub fn swap_goal_note(rng: impl RngCore) -> OutputWitness { + OutputWitness { + state: [0u8; 32], + value: 1, + unit: swap_goal_unit().unit(), + nonce: Nonce::random(rng), + zone_id: ZONE_ID, + nf_pk: NullifierSecret::zero().commit(), + } +} // TODO: order pair tokens lexicographically fn get_pair_share_unit(pair: Pair) -> UnitWitness { @@ -230,7 +295,7 @@ impl ZoneData { assert!(zone_update.has_output(&shares.note_commitment())); } - // TODO: chech shares have been burned + // TODO: check shares have been burned } pub fn expected_pool_balances(&self) -> BTreeMap { diff --git a/emmarin/cl/cl/Cargo.toml b/emmarin/cl/cl/Cargo.toml index a210628..45edc9d 100644 --- a/emmarin/cl/cl/Cargo.toml +++ b/emmarin/cl/cl/Cargo.toml @@ -9,6 +9,7 @@ rand_core = "0.6.0" hex = "0.4.3" risc0-zkvm = "1.2" itertools = "0.14" +bincode = { version = "2", features = ["serde"] } [dev-dependencies] rand = "0.8.5" diff --git a/emmarin/cl/cl/src/crust/balance.rs b/emmarin/cl/cl/src/crust/balance.rs index 8de4ac6..c14eca6 100644 --- a/emmarin/cl/cl/src/crust/balance.rs +++ b/emmarin/cl/cl/src/crust/balance.rs @@ -14,6 +14,15 @@ pub struct UnitWitness { } impl UnitWitness { + pub fn nop(args: &[u8]) -> Self { + Self { + spending_covenant: NOP_COVENANT, + minting_covenant: NOP_COVENANT, + burning_covenant: NOP_COVENANT, + arg: crate::hash(args), + } + } + pub fn unit(&self) -> Unit { let mut hasher = Hash::new(); hasher.update(b"NOMOS_CL_UNIT"); diff --git a/emmarin/cl/cl/src/crust/tx.rs b/emmarin/cl/cl/src/crust/tx.rs index c8904c5..31c0c7c 100644 --- a/emmarin/cl/cl/src/crust/tx.rs +++ b/emmarin/cl/cl/src/crust/tx.rs @@ -113,8 +113,9 @@ impl TxWitness { self } - pub fn add_output(mut self, output: OutputWitness, data: Vec) -> Self { - self.outputs.push((output, data)); + pub fn add_output(mut self, output: OutputWitness, data: impl Serialize) -> Self { + self.outputs.push((output, crate::serialize(data))); + self } diff --git a/emmarin/cl/cl/src/lib.rs b/emmarin/cl/cl/src/lib.rs index 923997a..1932417 100644 --- a/emmarin/cl/cl/src/lib.rs +++ b/emmarin/cl/cl/src/lib.rs @@ -3,6 +3,7 @@ pub mod ds; pub mod mantle; pub use risc0_zkvm::sha::rust_crypto::{Digest, Sha256}; +use serde::{de::DeserializeOwned, Serialize}; pub type Hash = Sha256; @@ -11,3 +12,15 @@ pub fn hash(data: &[u8]) -> [u8; 32] { hasher.update(data); hasher.finalize().into() } + +// TODO: spec serializiation +pub fn serialize(data: impl Serialize) -> Vec { + bincode::serde::encode_to_vec(data, bincode::config::standard()).unwrap() +} + +pub fn deserialize(bytes: &[u8]) -> T { + let (value, bytes_read) = bincode::serde::decode_from_slice(bytes, bincode::config::standard()) + .expect("failed to deserialize"); + assert_eq!(bytes_read, bytes.len()); + value +}