diff --git a/README.md b/README.md index 2d4c920..187408c 100644 --- a/README.md +++ b/README.md @@ -20,22 +20,31 @@ cargo t --release --features="int_tests" -- --test-threads=1 ## Usage The moat-cli utility can be used from the POV of any of the parties involved in the Citadel protocol, let them be: -- **License Provider (LP):** A party receiving onchain requests from users to issue licenses onchain addressed to them. - **User:** A party requesting licenses onchain to LPs, and being able to use the licenses onchain as well. +- **License Provider (LP):** A party receiving onchain requests from users to issue licenses onchain addressed to them. +- **Service Provider (SP):** A party receiving offchain requests from users to grant services. + + +### User + +Users can request licenses and use them. To run the user CLI, simply run: + +```sh +cargo r --release --bin moat-cli-user -- --wallet-path ~/.dusk/rusk-wallet --wallet-pass +``` ### License Provider -LPs can then scan the Blockchain for requests and issue licenses if the requests are valid. To run the LP CLI, simply run: +LPs can scan the Blockchain for requests and issue licenses if the requests are valid. To run the LP CLI, simply run: ```sh cargo r --release --bin moat-cli-lp -- --wallet-path ~/.dusk/rusk-wallet --wallet-pass ``` -### User +### Service Provider -Users can request licenses and use them. To run the user CLI, simply run: +SPs can get requests from users to grant their services, and accept or deny them by checking if the session cookies provided by the users are valid. To run the SP CLI, simply run: ```sh -cargo r --release --bin moat-cli-user -- --wallet-path ~/.dusk/rusk-wallet --wallet-pass +cargo r --release --bin moat-cli-sp -- --wallet-path ~/.dusk/rusk-wallet --wallet-pass ``` - diff --git a/integration-tests/Cargo.toml b/integration-tests/Cargo.toml index cc8dda9..fc3c432 100644 --- a/integration-tests/Cargo.toml +++ b/integration-tests/Cargo.toml @@ -10,7 +10,7 @@ license-provider = { path = "../license-provider" } [dev-dependencies] dusk-wallet = "0.20.1-rc.0" dusk-jubjub = { version = "0.13", default-features = false } -zk-citadel = "0.5.2-rc.0" +zk-citadel = "0.6.0-rc.0" phoenix-core = { version = "0.21", features = ["alloc"] } poseidon-merkle = { version = "0.3", features = ["rkyv-impl"] } dusk-pki = { version = "0.13", default-features = false, features = ["rkyv-impl"] } diff --git a/license-provider/Cargo.toml b/license-provider/Cargo.toml index 42f195a..2f09628 100644 --- a/license-provider/Cargo.toml +++ b/license-provider/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] dusk-wallet = "0.20.1-rc.0" -zk-citadel = "0.5.2-rc.0" +zk-citadel = "0.6.0-rc.0" moat-core={ path = "../moat-core" } wallet-accessor = { path = "../wallet-accessor" } dusk-poseidon = { version = "0.31", default-features = false, features = ["rkyv-impl", "alloc"] } diff --git a/moat-cli-lp/Cargo.toml b/moat-cli-lp/Cargo.toml index 269e102..6ba6eb9 100644 --- a/moat-cli-lp/Cargo.toml +++ b/moat-cli-lp/Cargo.toml @@ -10,7 +10,7 @@ wallet-accessor = { path = "../wallet-accessor" } moat-core = { path = "../moat-core" } dusk-pki = "0.13" license-provider = { path = "../license-provider" } -zk-citadel = "0.5.2-rc.0" +zk-citadel = "0.6.0-rc.0" rkyv = { version = "=0.7.39" } toml-base-config = "0.1" clap = { version = "4.0", features = ["derive", "env"] } diff --git a/moat-cli-sp/Cargo.toml b/moat-cli-sp/Cargo.toml index c4ea1d5..edf2b4e 100644 --- a/moat-cli-sp/Cargo.toml +++ b/moat-cli-sp/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" dusk-wallet = "0.20.1-rc.0" wallet-accessor = { path = "../wallet-accessor" } moat-core = { path = "../moat-core" } -zk-citadel = "0.5.2-rc.0" +zk-citadel = "0.6.0-rc.0" rkyv = { version = "=0.7.39" } dusk-bls12_381 = "0.12" dusk-jubjub = { version = "0.13", default-features = false, features = ["rkyv-impl", "alloc"] } @@ -29,3 +29,4 @@ reqwest = "0.11" bytecheck = "0.6" sha3 = "0.10" thiserror = "1.0" +bs58 = "0.4" diff --git a/moat-cli-sp/src/args.rs b/moat-cli-sp/src/args.rs index 551ebbb..69e82c7 100644 --- a/moat-cli-sp/src/args.rs +++ b/moat-cli-sp/src/args.rs @@ -17,12 +17,12 @@ pub struct Args { pub wallet_path: PathBuf, /// Blockchain access config directory - #[clap(short, long)] + #[clap(short, long, default_value = "./config.toml")] pub config_path: PathBuf, /// Password for the wallet #[clap(long, default_value_t = String::from(""), env = "RUSK_WALLET_PWD")] - pub password: String, + pub wallet_pass: String, /// Hash of the password for the wallet [default: ``] #[clap(short, long, default_value_t = String::from(""))] diff --git a/moat-cli-sp/src/command.rs b/moat-cli-sp/src/command.rs index f32a417..7f4a2d9 100644 --- a/moat-cli-sp/src/command.rs +++ b/moat-cli-sp/src/command.rs @@ -4,13 +4,13 @@ // // Copyright (c) DUSK NETWORK. All rights reserved. -use crate::config::SPCliConfig; use crate::run_result::{ LicenseContractSummary, RunResult, ServiceRequestSummery, SessionSummary, }; use crate::Error; use dusk_bls12_381::BlsScalar; use dusk_bytes::DeserializableSlice; +use dusk_bytes::Serializable; use dusk_jubjub::JubJubAffine; use dusk_pki::PublicSpendKey; use dusk_wallet::RuskHttpClient; @@ -22,7 +22,10 @@ use zk_citadel::license::{Session, SessionCookie}; #[derive(PartialEq, Eq, Hash, Clone, Debug)] pub(crate) enum Command { /// Request Service (User) - RequestService { session_cookie: String }, + VerifyRequestedService { + session_cookie: String, + psk_lp_bytes: String, + }, /// Get session (SP) GetSession { session_id: String }, /// Show state @@ -34,14 +37,18 @@ impl Command { pub async fn run( self, blockchain_access_config: &BlockchainAccessConfig, - config: &SPCliConfig, + psk_sp: PublicSpendKey, ) -> Result { let run_result = match self { - Command::RequestService { session_cookie } => { - Self::request_service( + Command::VerifyRequestedService { + session_cookie, + psk_lp_bytes, + } => { + Self::verify_requested_service( blockchain_access_config, &session_cookie, - config, + &psk_lp_bytes, + &psk_sp, ) .await? } @@ -56,10 +63,11 @@ impl Command { } /// Command: Request Service - async fn request_service( + async fn verify_requested_service( blockchain_access_config: &BlockchainAccessConfig, session_cookie: &str, - config: &SPCliConfig, + psk_lp_bytes: &str, + psk_sp: &PublicSpendKey, ) -> Result { let client = RuskHttpClient::new(blockchain_access_config.rusk_address.clone()); @@ -68,15 +76,17 @@ impl Command { .map_err(|_| Error::InvalidEntry("session cookie".into()))?; let sc: SessionCookie = rkyv::from_bytes(bytes.as_slice()) .map_err(|_| Error::InvalidEntry("session cookie".into()))?; - let psk_lp: &str = &config.psk_lp; - let psk_lp_bytes = hex::decode(psk_lp.as_bytes()).map_err(|_| { - Error::InvalidConfigValue("license provider psk".into()) - })?; - let psk_lp = PublicSpendKey::from_slice(psk_lp_bytes.as_slice()) - .map_err(|_| { - Error::InvalidConfigValue("license provider psk".into()) - })?; + + let psk_lp_bytes_formatted: [u8; 64] = + bs58::decode(&psk_lp_bytes.clone()) + .into_vec() + .unwrap() + .try_into() + .unwrap(); + let psk_lp = + PublicSpendKey::from_bytes(&psk_lp_bytes_formatted).unwrap(); let pk_lp = JubJubAffine::from(*psk_lp.A()); + let pk_sp = JubJubAffine::from(*psk_sp.A()); let session_id = LicenseSessionId { id: sc.session_id }; let session = CitadelInquirer::get_session(&client, session_id) @@ -84,7 +94,7 @@ impl Command { .ok_or(Error::NotFound("Session not found".into()))?; let session = Session::from(&session.public_inputs); - let granted = session.verifies_ok(sc, pk_lp); + let granted = session.verifies_ok(sc, pk_lp, pk_sp); println!("session id={}", hex::encode(session_id.id.to_bytes())); let service_request_summary = ServiceRequestSummery { service_granted: granted, diff --git a/moat-cli-sp/src/config.rs b/moat-cli-sp/src/config.rs index fbc350b..69970d6 100644 --- a/moat-cli-sp/src/config.rs +++ b/moat-cli-sp/src/config.rs @@ -11,7 +11,6 @@ use toml_base_config::BaseConfig; pub struct SPCliConfig { pub rusk_address: String, pub prover_address: String, - pub psk_lp: String, } impl BaseConfig for SPCliConfig { diff --git a/moat-cli-sp/src/error.rs b/moat-cli-sp/src/error.rs index a7bba59..d751b37 100644 --- a/moat-cli-sp/src/error.rs +++ b/moat-cli-sp/src/error.rs @@ -31,9 +31,6 @@ pub enum Error { /// Invalid entry #[error("Invalid entry: {0:?}")] InvalidEntry(Cow<'static, str>), - /// Invalid config value - #[error("Invalid config value: {0:?}")] - InvalidConfigValue(Cow<'static, str>), } impl From for Error { diff --git a/moat-cli-sp/src/interactor.rs b/moat-cli-sp/src/interactor.rs index b7f7062..70c3a94 100644 --- a/moat-cli-sp/src/interactor.rs +++ b/moat-cli-sp/src/interactor.rs @@ -8,6 +8,7 @@ use crate::config::SPCliConfig; use crate::error::Error; use crate::prompt; use crate::{Command, Menu}; +use dusk_pki::PublicSpendKey; use dusk_wallet::WalletPath; use requestty::{ErrorKind, Question}; use wallet_accessor::{BlockchainAccessConfig, Password}; @@ -30,7 +31,7 @@ fn menu_operation() -> Result { let cmd_menu = Menu::new() .add( CommandMenuItem::RequestService, - "Request Service (Off-Chain)", + "Verify Requested Service (Off-Chain)", ) .add(CommandMenuItem::GetSession, "Get Session (SP)") .add(CommandMenuItem::ShowState, "Show state") @@ -46,8 +47,9 @@ fn menu_operation() -> Result { let cmd = cmd_menu.answer(&answer).to_owned(); Ok(match cmd { CommandMenuItem::RequestService => { - OpSelection::Run(Box::from(Command::RequestService { + OpSelection::Run(Box::from(Command::VerifyRequestedService { session_cookie: prompt::request_session_cookie()?, + psk_lp_bytes: prompt::request_psk_lp()?, })) } CommandMenuItem::GetSession => { @@ -69,6 +71,7 @@ pub struct Interactor { pub config: SPCliConfig, pub gas_limit: u64, pub gas_price: u64, + pub psk_sp: PublicSpendKey, } impl Interactor { @@ -79,7 +82,7 @@ impl Interactor { OpSelection::Exit => return Ok(()), OpSelection::Run(command) => { let result = command - .run(&self.blockchain_access_config, &self.config) + .run(&self.blockchain_access_config, self.psk_sp) .await; match result { Ok(run_result) => { @@ -87,7 +90,7 @@ impl Interactor { } Err(error) => { println!("{}", error.to_string()); - } + } } continue; } diff --git a/moat-cli-sp/src/main.rs b/moat-cli-sp/src/main.rs index 549bfaa..18323bb 100644 --- a/moat-cli-sp/src/main.rs +++ b/moat-cli-sp/src/main.rs @@ -24,10 +24,10 @@ use clap::Parser; use crate::config::SPCliConfig; use crate::error::Error; use crate::interactor::Interactor; -use dusk_wallet::WalletPath; +use dusk_wallet::{Wallet, WalletPath}; use toml_base_config::BaseConfig; -use wallet_accessor::BlockchainAccessConfig; use wallet_accessor::Password::{Pwd, PwdHash}; +use wallet_accessor::{BlockchainAccessConfig, WalletAccessor}; #[tokio::main] async fn main() -> Result<(), Error> { @@ -35,7 +35,7 @@ async fn main() -> Result<(), Error> { let config_path = cli.config_path.as_path(); let wallet_path = cli.wallet_path.as_path(); - let password = cli.password; + let password = cli.wallet_pass; let pwd_hash = cli.pwd_hash; let gas_limit = cli.gas_limit; let gas_price = cli.gas_price; @@ -51,6 +51,13 @@ async fn main() -> Result<(), Error> { PwdHash(pwd_hash) }; + let wallet_accessor = + WalletAccessor::create(wallet_path.clone(), psw.clone()).unwrap(); + let wallet = Wallet::from_file(wallet_accessor).unwrap(); + + let (psk_sp, _ssk_sp) = + wallet.spending_keys(wallet.default_address()).unwrap(); + let mut interactor = Interactor { wallet_path, psw, @@ -58,6 +65,7 @@ async fn main() -> Result<(), Error> { config, gas_limit, gas_price, + psk_sp, }; interactor.run_loop().await?; diff --git a/moat-cli-sp/src/prompt.rs b/moat-cli-sp/src/prompt.rs index 35e791e..64c204c 100644 --- a/moat-cli-sp/src/prompt.rs +++ b/moat-cli-sp/src/prompt.rs @@ -45,3 +45,23 @@ pub(crate) fn request_session_cookie() -> Result { let a_str = a.as_string().expect("answer to be a string").to_string(); Ok(a_str) } + +pub(crate) fn request_psk_lp() -> Result { + let q = Question::input("psk_lp_bytes") + .message("Please enter the LP address:".to_string()) + .validate_on_key(|_, _| { + true // todo: add some validation of psk_lp + }) + .validate(|id, _| { + if id.is_empty() { + Err("Please enter a valid address for the LP".to_string()) + } else { + Ok(()) + } + }) + .build(); + + let a = requestty::prompt_one(q)?; + let a_str = a.as_string().expect("answer to be a string").to_string(); + Ok(a_str) +} diff --git a/moat-cli-sp/src/run_result.rs b/moat-cli-sp/src/run_result.rs index 9f7d703..d2dd859 100644 --- a/moat-cli-sp/src/run_result.rs +++ b/moat-cli-sp/src/run_result.rs @@ -34,9 +34,15 @@ impl fmt::Display for RunResult { match self { RequestService(summary) => { if summary.service_granted { - writeln!(f, "Service granted")?; + writeln!( + f, + "Session Cookie is correct, service can be granted" + )?; } else { - writeln!(f, "Service denied")?; + writeln!( + f, + "Session Cookie is NOT correct, service must be denied" + )?; } Ok(()) } diff --git a/moat-cli-user/Cargo.toml b/moat-cli-user/Cargo.toml index fa6da11..c3277b7 100644 --- a/moat-cli-user/Cargo.toml +++ b/moat-cli-user/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" dusk-wallet = "0.20.1-rc.0" wallet-accessor = { path = "../wallet-accessor" } moat-core = { path = "../moat-core" } -zk-citadel = "0.5.2-rc.0" +zk-citadel = "0.6.0-rc.0" dusk-plonk = { version = "0.16", default-features = false, features = ["rkyv-impl", "alloc"] } rkyv = { version = "=0.7.39" } dusk-pki = "0.13" diff --git a/moat-cli-user/src/command.rs b/moat-cli-user/src/command.rs index 21927af..eb281ae 100644 --- a/moat-cli-user/src/command.rs +++ b/moat-cli-user/src/command.rs @@ -119,8 +119,9 @@ impl Command { psk_lp_bytes: String, ) -> Result { let psk_lp_bytes_formatted: [u8; 64] = - hex::decode(psk_lp_bytes.clone()) - .expect("Decoded.") + bs58::decode(&psk_lp_bytes.clone()) + .into_vec() + .unwrap() .try_into() .unwrap(); let psk_lp = diff --git a/moat-core/Cargo.toml b/moat-core/Cargo.toml index b9f8299..f76ad87 100644 --- a/moat-core/Cargo.toml +++ b/moat-core/Cargo.toml @@ -11,7 +11,7 @@ futures-core = "0.3" futures-util = { version = "0.3.28", default-features = false, features = ["sink", "std"] } dusk-wallet = "0.20.1-rc.0" wallet-accessor = { path = "../wallet-accessor" } -zk-citadel = "0.5.2-rc.0" +zk-citadel = "0.6.0-rc.0" dusk-plonk = { version = "0.16", default-features = false, features = ["rkyv-impl", "alloc"] } phoenix-core = { version = "0.21", features = ["alloc"] } dusk-poseidon = { version = "0.31", default-features = false, features = ["rkyv-impl", "alloc"] } diff --git a/testing-utils/test-moat-cli/Cargo.toml b/testing-utils/test-moat-cli/Cargo.toml index e3508fe..5a21606 100644 --- a/testing-utils/test-moat-cli/Cargo.toml +++ b/testing-utils/test-moat-cli/Cargo.toml @@ -8,7 +8,7 @@ dusk-wallet = "0.20.1-rc.0" wallet-accessor = { path = "../../wallet-accessor" } moat-core = { path = "../../moat-core" } license-provider = { path = "../../license-provider" } -zk-citadel = "0.5.2-rc.0" +zk-citadel = "0.6.0-rc.0" dusk-plonk = { version = "0.16", default-features = false, features = ["rkyv-impl", "alloc"] } rkyv = { version = "=0.7.39" } dusk-pki = "0.13"