diff --git a/Cargo.toml b/Cargo.toml index a0940aa..7db52db 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,2 +1,2 @@ [workspace] -members = ["testing-utils/test-moat-cli", "moat-cli-user", "moat-cli-lp", "moat-cli-sp", "testing-utils/test-moat-request", "moat-core", "wallet-accessor", "integration-tests", "license-provider", "macros/code-hasher"] +members = ["testing-utils/test-moat-cli", "moat-cli-user", "moat-cli-lp", "moat-cli-sp", "testing-utils/test-moat-request", "moat-core", "wallet-accessor", "integration-tests", "macros/code-hasher", "moat-example"] diff --git a/integration-tests/Cargo.toml b/integration-tests/Cargo.toml index fc3c432..9bf2645 100644 --- a/integration-tests/Cargo.toml +++ b/integration-tests/Cargo.toml @@ -5,7 +5,6 @@ edition = "2021" [dependencies] moat-core={ path = "../moat-core" } -license-provider = { path = "../license-provider" } [dev-dependencies] dusk-wallet = "0.20.1-rc.0" diff --git a/integration-tests/tests/citadel/int_test_lp.rs b/integration-tests/tests/citadel/int_test_lp.rs index cc82d1c..5839960 100644 --- a/integration-tests/tests/citadel/int_test_lp.rs +++ b/integration-tests/tests/citadel/int_test_lp.rs @@ -4,7 +4,7 @@ // // Copyright (c) DUSK NETWORK. All rights reserved. -use license_provider::ReferenceLP; +use moat_core::license_provider::ReferenceLP; use moat_core::Error; use toml_base_config::BaseConfig; use wallet_accessor::BlockchainAccessConfig; diff --git a/integration-tests/tests/citadel/int_test_user.rs b/integration-tests/tests/citadel/int_test_user.rs index a96805a..f83126a 100644 --- a/integration-tests/tests/citadel/int_test_user.rs +++ b/integration-tests/tests/citadel/int_test_user.rs @@ -24,13 +24,13 @@ use dusk_bytes::DeserializableSlice; use dusk_pki::SecretSpendKey; use dusk_plonk::prelude::*; use dusk_wallet::{RuskHttpClient, WalletPath}; -use license_provider::{LicenseIssuer, ReferenceLP}; +use moat_core::license_provider::{LicenseIssuer, ReferenceLP}; use moat_core::{ BcInquirer, CitadelInquirer, CrsGetter, Error, JsonLoader, LicenseCircuit, LicenseSessionId, LicenseUser, PayloadRetriever, RequestCreator, RequestJson, RequestSender, TxAwaiter, }; -use rand::rngs::StdRng; +use rand::rngs::{OsRng, StdRng}; use rand::SeedableRng; use std::path::PathBuf; use toml_base_config::BaseConfig; @@ -251,7 +251,7 @@ async fn user_round_trip() -> Result<(), Error> { &verifier, &license, opening.unwrap(), - &mut rng, + &mut OsRng, &challenge, GAS_LIMIT, GAS_PRICE, diff --git a/integration-tests/tests/citadel/issue_license.rs b/integration-tests/tests/citadel/issue_license.rs index fc21107..57efa51 100644 --- a/integration-tests/tests/citadel/issue_license.rs +++ b/integration-tests/tests/citadel/issue_license.rs @@ -6,7 +6,7 @@ use dusk_jubjub::JubJubScalar; use dusk_wallet::WalletPath; -use license_provider::{LicenseIssuer, ReferenceLP}; +use moat_core::license_provider::{LicenseIssuer, ReferenceLP}; use moat_core::{Error, JsonLoader, RequestCreator, RequestJson}; use rand::rngs::StdRng; use rand::SeedableRng; diff --git a/license-provider/Cargo.toml b/license-provider/Cargo.toml deleted file mode 100644 index 2f09628..0000000 --- a/license-provider/Cargo.toml +++ /dev/null @@ -1,32 +0,0 @@ -[package] -name = "license-provider" -version = "0.1.0" -edition = "2021" - -[dependencies] -dusk-wallet = "0.20.1-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"] } -dusk-jubjub = { version = "0.13", default-features = false } -dusk-bls12_381 = "0.12" -dusk-pki = { version = "0.13", default-features = false, features = ["rkyv-impl"] } -rusk-abi = { version = "0.11", default-features = false } -rkyv = { version = "=0.7.39" } -serde = { version = "1", features = ["derive"] } -serde_json = "1.0" -thiserror = "1.0" -toml-base-config = "0.1" -bytecheck = "0.6" -gql_client = "1" -base64 = "0.21" -hex = "0.4" -rand = "0.8" -dusk-bytes = "0.1" -blake3 = "1.3" -tracing = "0.1" -sha3 = "0.10" - -[dev-dependencies] -tokio = { version = "1.15", features = ["rt-multi-thread", "time", "fs", "macros"] } diff --git a/license-provider/README.md b/license-provider/README.md deleted file mode 100644 index 794a9a7..0000000 --- a/license-provider/README.md +++ /dev/null @@ -1,26 +0,0 @@ -# dusk moat - license provider - reference implementation - -`license-provider` is a reference implementation of a hipothetical license provider, the following points summarize the -functionality provided by the license provider: - -- initializes itself with a given identity (as defined by Citadel, a public spend key and a secret spend key) -- scans the entire blockchain for requests addressed to "self" (is able to filter requests) -- alternatively, scans the last N blocks for requests addressed to "self" -- holds a collection of requests to process along with a set of requests hashes to avoid duplication caused by multiple scanning of the same blocks - -## how to test - -to run a local unit tests with a hardcoded set of transactions do: - -```sh -cd license-provider -cargo t --release -``` - -to run integration test against a life blockchain do: - -```sh -cd integration-tests -cargo t lp --release --features exp_tests -``` -Make sure blockchain access data in `config.toml` in integration-tests/tests/config is up-to-date. diff --git a/moat-cli-lp/Cargo.toml b/moat-cli-lp/Cargo.toml index 6ba6eb9..ea9acd1 100644 --- a/moat-cli-lp/Cargo.toml +++ b/moat-cli-lp/Cargo.toml @@ -9,7 +9,6 @@ dusk-jubjub = { version = "0.13", default-features = false } wallet-accessor = { path = "../wallet-accessor" } moat-core = { path = "../moat-core" } dusk-pki = "0.13" -license-provider = { path = "../license-provider" } zk-citadel = "0.6.0-rc.0" rkyv = { version = "=0.7.39" } toml-base-config = "0.1" diff --git a/moat-cli-lp/src/command.rs b/moat-cli-lp/src/command.rs index 78b79b4..3f7204f 100644 --- a/moat-cli-lp/src/command.rs +++ b/moat-cli-lp/src/command.rs @@ -11,7 +11,7 @@ use crate::SeedableRng; use dusk_jubjub::JubJubScalar; use dusk_pki::SecretSpendKey; use dusk_wallet::{RuskHttpClient, WalletPath}; -use license_provider::{LicenseIssuer, ReferenceLP}; +use moat_core::license_provider::{LicenseIssuer, ReferenceLP}; use moat_core::{BcInquirer, CitadelInquirer, Error}; use rand::rngs::StdRng; use wallet_accessor::{BlockchainAccessConfig, Password}; diff --git a/moat-cli-user/src/command.rs b/moat-cli-user/src/command.rs index eb281ae..288b801 100644 --- a/moat-cli-user/src/command.rs +++ b/moat-cli-user/src/command.rs @@ -18,7 +18,7 @@ use moat_core::{ BcInquirer, CitadelInquirer, CrsGetter, Error, LicenseCircuit, LicenseUser, RequestCreator, RequestSender, TxAwaiter, }; -use rand::rngs::StdRng; +use rand::rngs::{OsRng, StdRng}; use wallet_accessor::{BlockchainAccessConfig, Password}; use zk_citadel::license::{License, SessionCookie}; @@ -311,7 +311,6 @@ impl Command { RuskHttpClient::new(blockchain_access_config.rusk_address.clone()); // let (_, _, num_sessions) = CitadelInquirer::get_info(&client).await?; // let challenge = JubJubScalar::from(num_sessions as u64 + 1); - let mut rng = StdRng::seed_from_u64(0xbeef); let setup_holder = match sh_opt { Some(sh) => sh, @@ -381,7 +380,7 @@ impl Command { &setup_holder.verifier, license, opening, - &mut rng, + &mut OsRng, &challenge, gas_limit, gas_price, diff --git a/moat-core/Cargo.toml b/moat-core/Cargo.toml index f76ad87..24f6b3d 100644 --- a/moat-core/Cargo.toml +++ b/moat-core/Cargo.toml @@ -38,6 +38,8 @@ tracing = "0.1" bytes = "1.4" reqwest = "0.11" sha2 = "0.10" +sha3 = "0.10" +bs58 = "0.4" [dev-dependencies] tokio = { version = "1.15", features = ["rt-multi-thread", "time", "fs", "macros"] } diff --git a/moat-core/src/api.rs b/moat-core/src/api.rs new file mode 100644 index 0000000..05bff0d --- /dev/null +++ b/moat-core/src/api.rs @@ -0,0 +1,224 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// +// Copyright (c) DUSK NETWORK. All rights reserved. + +use dusk_jubjub::{JubJubAffine, JubJubScalar}; +use dusk_pki::{PublicSpendKey, SecretSpendKey}; +use dusk_wallet::{RuskHttpClient, Wallet, WalletPath}; + +use zk_citadel::license::{Session, SessionCookie}; + +use crate::license_provider::{LicenseIssuer, ReferenceLP}; +use crate::utils::MoatCoreUtils; +use crate::{ + CitadelInquirer, LicenseSessionId, RequestCreator, RequestSender, TxAwaiter, +}; +use wallet_accessor::Password::{self, Pwd}; +use wallet_accessor::{BlockchainAccessConfig, WalletAccessor}; + +use rand::rngs::OsRng; +use std::path::Path; +use toml_base_config::BaseConfig; + +pub struct MoatCore {} + +impl MoatCore { + /// Retrieve the keypair (psk, ssk) from the installed wallet, given the + /// Moat Context + pub fn get_wallet_keypair( + moat_context: &MoatContext, + ) -> (PublicSpendKey, SecretSpendKey) { + // We access the wallet to get the key pair + let wallet_accessor = WalletAccessor::create( + moat_context.wallet_path.clone(), + moat_context.wallet_password.clone(), + ) + .unwrap(); + let wallet = Wallet::from_file(wallet_accessor).unwrap(); + + wallet.spending_keys(wallet.default_address()).unwrap() + } + + /// Create and send a transaction containing a license request + pub async fn request_license( + ssk_user: &SecretSpendKey, + psk_lp: &PublicSpendKey, + moat_context: &MoatContext, + rng: &mut OsRng, + ) -> String { + let request = RequestCreator::create(ssk_user, psk_lp, rng).unwrap(); + let request_hash = MoatCoreUtils::to_hash_hex(&request); + + let tx_id = RequestSender::send_request( + request, + &moat_context.blockchain_access_config, + &moat_context.wallet_path, + &moat_context.wallet_password, + moat_context.gas_limit, + moat_context.gas_price, + ) + .await + .unwrap(); + + let client = RuskHttpClient::new( + moat_context.blockchain_access_config.rusk_address.clone(), + ); + TxAwaiter::wait_for(&client, tx_id).await.unwrap(); + + request_hash + } + + /// Create and send a transaction containing a license for a given request + pub async fn issue_license( + request_hash: &String, + ssk_lp: &SecretSpendKey, + moat_context: &MoatContext, + attr_data: &JubJubScalar, + rng: &mut OsRng, + ) -> String { + let mut reference_lp = ReferenceLP::create_with_ssk(ssk_lp).unwrap(); + + let (_total_count, _this_lp_count) = reference_lp + .scan(&moat_context.blockchain_access_config) + .await + .unwrap(); + + let request = reference_lp.get_request(request_hash); + + match request { + Some(request) => { + let license_issuer = LicenseIssuer::new( + moat_context.blockchain_access_config.clone(), + moat_context.wallet_path.clone(), + moat_context.wallet_password.clone(), + moat_context.gas_limit, + moat_context.gas_price, + ); + let (_tx_id, license_blob) = license_issuer + .issue_license( + rng, + &request, + &reference_lp.ssk_lp, + attr_data, + ) + .await + .unwrap(); + MoatCoreUtils::blob_to_hash_hex(&license_blob) + } + _ => "nothing to do".to_string(), + } + } + + /// Create and send a transaction containing a proof that uses a given + /// license + pub async fn use_license( + moat_context: &MoatContext, + psk_lp: &PublicSpendKey, + psk_sp: &PublicSpendKey, + ssk: &SecretSpendKey, + challenge: &JubJubScalar, + license_hash: &str, + rng: &mut OsRng, + ) -> Option { + let pos_license = MoatCoreUtils::get_license_to_use( + &moat_context.blockchain_access_config, + ssk, + license_hash.to_owned(), + ) + .await + .unwrap(); + + match pos_license { + Some((pos, license)) => { + println!( + "using license: {}", + MoatCoreUtils::to_hash_hex(&license) + ); + + let (_tx_id, session_cookie) = + MoatCoreUtils::prove_and_send_use_license( + &moat_context.blockchain_access_config, + &moat_context.wallet_path, + &moat_context.wallet_password, + psk_lp, + psk_sp, + ssk, + challenge, + &license, + pos, + moat_context.gas_limit, + moat_context.gas_price, + &mut None, + rng, + ) + .await + .unwrap(); + + Some(session_cookie) + } + _ => None, + } + } + + /// Given a session cookie, verify that it corresponds to an existing + /// session in the Blockchain + pub async fn verify_requested_service( + moat_context: &MoatContext, + psk_lp: &PublicSpendKey, + psk_sp: &PublicSpendKey, + session_cookie: &SessionCookie, + ) -> bool { + let client = RuskHttpClient::new( + moat_context.blockchain_access_config.rusk_address.clone(), + ); + + let pk_lp = JubJubAffine::from(*psk_lp.A()); + let pk_sp = JubJubAffine::from(*psk_sp.A()); + + let session_id = LicenseSessionId { + id: session_cookie.session_id, + }; + let session = CitadelInquirer::get_session(&client, session_id) + .await + .unwrap() + .unwrap(); + + let session = Session::from(&session.public_inputs); + session.verifies_ok(*session_cookie, pk_lp, pk_sp) + } +} + +pub struct MoatContext { + blockchain_access_config: BlockchainAccessConfig, + wallet_path: WalletPath, + wallet_password: Password, + gas_limit: u64, + gas_price: u64, +} + +impl MoatContext { + /// Create a new Moat Context given the required configurations + pub fn new( + config_path: &String, + wallet_path: &String, + wallet_password: &String, + gas_limit: u64, + gas_price: u64, + ) -> Self { + let wallet_path = WalletPath::from(Path::new(&wallet_path)); + let wallet_password = Pwd(wallet_password.to_string()); + + let blockchain_access_config = + BlockchainAccessConfig::load_path(config_path).unwrap(); + + Self { + blockchain_access_config, + wallet_path, + wallet_password, + gas_limit, + gas_price, + } + } +} diff --git a/moat-core/src/citadel_licenses/license_user.rs b/moat-core/src/citadel_licenses/license_user.rs index 6f93158..a8487b4 100644 --- a/moat-core/src/citadel_licenses/license_user.rs +++ b/moat-core/src/citadel_licenses/license_user.rs @@ -16,7 +16,7 @@ use dusk_pki::{PublicSpendKey, SecretSpendKey}; use dusk_plonk::prelude::{Proof, Prover, Verifier}; use dusk_wallet::WalletPath; use poseidon_merkle::Opening; -use rand::rngs::StdRng; +use rand::rngs::OsRng; use rkyv::{Archive, Deserialize, Serialize}; use wallet_accessor::{BlockchainAccessConfig, Password}; use zk_citadel::license::{CitadelProverParameters, License, SessionCookie}; @@ -47,7 +47,7 @@ impl LicenseUser { verifier: &Verifier, license: &License, opening: Opening<(), DEPTH, ARITY>, - rng: &mut StdRng, + rng: &mut OsRng, challenge: &JubJubScalar, gas_limit: u64, gas_price: u64, diff --git a/moat-core/src/lib.rs b/moat-core/src/lib.rs index 73f279b..cf4da0d 100644 --- a/moat-core/src/lib.rs +++ b/moat-core/src/lib.rs @@ -22,6 +22,10 @@ mod citadel_types; mod contract_queries; mod error; mod json_loader; +mod utils; + +pub mod api; +pub mod license_provider; pub use bc_types::*; pub use blockchain_payloads::{ diff --git a/license-provider/src/license_issuer.rs b/moat-core/src/license_provider/license_issuer.rs similarity index 99% rename from license-provider/src/license_issuer.rs rename to moat-core/src/license_provider/license_issuer.rs index a0fb1d2..269c216 100644 --- a/license-provider/src/license_issuer.rs +++ b/moat-core/src/license_provider/license_issuer.rs @@ -4,15 +4,15 @@ // // Copyright (c) DUSK NETWORK. All rights reserved. +use crate::{ + Error, PayloadSender, TxAwaiter, ISSUE_LICENSE_METHOD_NAME, + LICENSE_CONTRACT_ID, MAX_LICENSE_SIZE, +}; use dusk_bls12_381::BlsScalar; use dusk_jubjub::{JubJubAffine, JubJubScalar}; use dusk_pki::SecretSpendKey; use dusk_poseidon::sponge; use dusk_wallet::{RuskHttpClient, WalletPath}; -use moat_core::{ - Error, PayloadSender, TxAwaiter, ISSUE_LICENSE_METHOD_NAME, - LICENSE_CONTRACT_ID, MAX_LICENSE_SIZE, -}; use rand::{CryptoRng, RngCore}; use tracing::trace; use wallet_accessor::{BlockchainAccessConfig, Password}; diff --git a/license-provider/src/lib.rs b/moat-core/src/license_provider/mod.rs similarity index 100% rename from license-provider/src/lib.rs rename to moat-core/src/license_provider/mod.rs diff --git a/license-provider/src/reference_lp.rs b/moat-core/src/license_provider/reference_lp.rs similarity index 98% rename from license-provider/src/reference_lp.rs rename to moat-core/src/license_provider/reference_lp.rs index a8c6eac..ea723d9 100644 --- a/license-provider/src/reference_lp.rs +++ b/moat-core/src/license_provider/reference_lp.rs @@ -4,10 +4,10 @@ // // Copyright (c) DUSK NETWORK. All rights reserved. +use crate::{Error, JsonLoader, RequestScanner, MAX_REQUEST_SIZE}; use blake3::OUT_LEN; use dusk_bytes::DeserializableSlice; use dusk_pki::{PublicSpendKey, SecretSpendKey, ViewKey}; -use moat_core::{Error, JsonLoader, RequestScanner, MAX_REQUEST_SIZE}; use rkyv::ser::serializers::AllocSerializer; use sha3::{Digest, Sha3_256}; use std::collections::BTreeSet; diff --git a/moat-core/src/utils.rs b/moat-core/src/utils.rs new file mode 100644 index 0000000..2db62eb --- /dev/null +++ b/moat-core/src/utils.rs @@ -0,0 +1,182 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// +// Copyright (c) DUSK NETWORK. All rights reserved. + +use dusk_pki::{PublicSpendKey, SecretSpendKey}; +use dusk_wallet::WalletPath; +use rand::rngs::OsRng; +use wallet_accessor::BlockchainAccessConfig; +use wallet_accessor::Password; + +use zk_citadel::license::{License, SessionCookie}; + +use dusk_jubjub::JubJubScalar; + +use crate::{ + BcInquirer, CitadelInquirer, CrsGetter, Error, LicenseCircuit, LicenseUser, + TxAwaiter, +}; +use dusk_wallet::RuskHttpClient; +use rkyv::ser::serializers::AllocSerializer; +use sha3::{Digest, Sha3_256}; + +use dusk_bls12_381::BlsScalar; + +use dusk_plonk::prelude::*; + +use std::fs::File; +use std::io::prelude::*; + +static LABEL: &[u8] = b"dusk-network"; + +pub struct SetupHolder { + pub prover: Prover, + pub verifier: Verifier, +} + +pub struct MoatCoreUtils {} + +impl MoatCoreUtils { + pub fn to_hash_hex(object: &T) -> String + where + T: rkyv::Serialize>, + { + let blob = rkyv::to_bytes::<_, 16386>(object) + .expect("Serializing should be infallible") + .to_vec(); + Self::blob_to_hash_hex(blob.as_slice()) + } + + pub fn blob_to_hash_hex(blob: &[u8]) -> String { + let mut hasher = Sha3_256::new(); + hasher.update(blob); + let result = hasher.finalize(); + hex::encode(result) + } + + pub async fn get_license_to_use( + blockchain_access_config: &BlockchainAccessConfig, + ssk: &SecretSpendKey, + license_hash: String, + ) -> Result, Error> { + let client = + RuskHttpClient::new(blockchain_access_config.rusk_address.clone()); + let end_height = BcInquirer::block_height(&client).await?; + let block_heights = 0..(end_height + 1); + + let mut licenses_stream = + CitadelInquirer::get_licenses(&client, block_heights).await?; + + let pairs = + CitadelInquirer::find_owned_licenses(*ssk, &mut licenses_stream)?; + Ok(if pairs.is_empty() { + None + } else { + for (pos, license) in pairs.iter() { + if license_hash == Self::to_hash_hex(license) { + return Ok(Some((*pos, license.clone()))); + } + } + None + }) + } + + #[allow(clippy::too_many_arguments)] + pub async fn prove_and_send_use_license( + blockchain_access_config: &BlockchainAccessConfig, + wallet_path: &WalletPath, + psw: &Password, + psk_lp: &PublicSpendKey, + psk_sp: &PublicSpendKey, + ssk_user: &SecretSpendKey, + challenge: &JubJubScalar, + license: &License, + pos: u64, + gas_limit: u64, + gas_price: u64, + sh_opt: &mut Option, + rng: &mut OsRng, + ) -> Result<(BlsScalar, SessionCookie), Error> { + let client = + RuskHttpClient::new(blockchain_access_config.rusk_address.clone()); + + let setup_holder = match sh_opt { + Some(sh) => sh, + _ => { + let wallet_dir_path = match wallet_path.dir() { + Some(path) => path, + None => panic!(), + }; + + let prover_path = &wallet_dir_path.join("moat_prover.dat"); + let verifier_path = &wallet_dir_path.join("moat_verifier.dat"); + + if prover_path.exists() && verifier_path.exists() { + let mut file = File::open(prover_path)?; + let mut prover_bytes = vec![]; + file.read_to_end(&mut prover_bytes)?; + let prover = Prover::try_from_bytes(prover_bytes).unwrap(); + + file = File::open(verifier_path)?; + let mut verifier_bytes = vec![]; + file.read_to_end(&mut verifier_bytes)?; + let verifier = + Verifier::try_from_bytes(verifier_bytes).unwrap(); + + let sh = SetupHolder { prover, verifier }; + *sh_opt = Some(sh); + sh_opt.as_ref().unwrap() + } else { + println!("obtaining setup"); + let pp_vec = CrsGetter::get_crs(&client).await?; + let pp = + // SAFETY: CRS vector is checked by the hash check when it is received from the node + unsafe { PublicParameters::from_slice_unchecked(pp_vec.as_slice()) }; + println!("compiling circuit"); + let (prover, verifier) = + Compiler::compile::(&pp, LABEL) + .expect("Compiling circuit should succeed"); + + let mut file = File::create(prover_path)?; + file.write_all(prover.to_bytes().as_slice())?; + + file = File::create(verifier_path)?; + file.write_all(verifier.to_bytes().as_slice())?; + + let sh = SetupHolder { prover, verifier }; + *sh_opt = Some(sh); + sh_opt.as_ref().unwrap() + } + } + }; + + let opening = CitadelInquirer::get_merkle_opening(&client, pos) + .await? + .expect("Opening obtained successfully"); + + println!( + "calculating proof and calling license contract's use_license" + ); + let (tx_id, session_cookie) = LicenseUser::prove_and_use_license( + blockchain_access_config, + wallet_path, + psw, + ssk_user, + psk_lp, + psk_sp, + &setup_holder.prover, + &setup_holder.verifier, + license, + opening, + rng, + challenge, + gas_limit, + gas_price, + ) + .await?; + TxAwaiter::wait_for(&client, tx_id).await?; + Ok((tx_id, session_cookie)) + } +} diff --git a/license-provider/tests/config/test_keys_lp.json b/moat-core/tests/config/test_keys_lp.json similarity index 100% rename from license-provider/tests/config/test_keys_lp.json rename to moat-core/tests/config/test_keys_lp.json diff --git a/license-provider/tests/test_lp.rs b/moat-core/tests/test_lp.rs similarity index 94% rename from license-provider/tests/test_lp.rs rename to moat-core/tests/test_lp.rs index 9cb2bc1..a1376cf 100644 --- a/license-provider/tests/test_lp.rs +++ b/moat-core/tests/test_lp.rs @@ -4,7 +4,7 @@ // // Copyright (c) DUSK NETWORK. All rights reserved. -use license_provider::ReferenceLP; +use moat_core::license_provider::ReferenceLP; use moat_core::{Error, JsonLoader, RequestScanner, Transactions}; #[test] @@ -16,7 +16,7 @@ fn lp_filter_requests() -> Result<(), Error> { let reference_lp = ReferenceLP::create(&lp_config_path)?; let txs_path = - concat!(env!("CARGO_MANIFEST_DIR"), "/tests/tx/transactions.json"); + concat!(env!("CARGO_MANIFEST_DIR"), "/tests/tx/transactions_lp.json"); let txs = Transactions::from_file(txs_path) .expect("transactions file should load correctly"); diff --git a/license-provider/tests/tx/transactions.json b/moat-core/tests/tx/transactions_lp.json similarity index 100% rename from license-provider/tests/tx/transactions.json rename to moat-core/tests/tx/transactions_lp.json diff --git a/moat-example/Cargo.toml b/moat-example/Cargo.toml new file mode 100644 index 0000000..c520fcb --- /dev/null +++ b/moat-example/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "moat-example" +version = "0.1.0" +edition = "2021" + +[dependencies] +dusk-jubjub = { version = "0.13", default-features = false } +moat-core = { path = "../moat-core" } +tokio = { version = "1.21", features = ["full"] } +rand = "0.8" diff --git a/moat-example/config.toml b/moat-example/config.toml new file mode 100644 index 0000000..f4fa14b --- /dev/null +++ b/moat-example/config.toml @@ -0,0 +1,2 @@ +rusk_address = "http://192.168.1.57:8080" +prover_address = "http://192.168.1.57:8080" diff --git a/moat-example/src/main.rs b/moat-example/src/main.rs new file mode 100644 index 0000000..ea61add --- /dev/null +++ b/moat-example/src/main.rs @@ -0,0 +1,91 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// +// Copyright (c) DUSK NETWORK. All rights reserved. + +use dusk_jubjub::JubJubScalar; +use rand::rngs::OsRng; + +use moat_core::api::{MoatContext, MoatCore}; + +#[tokio::main] +#[allow(non_snake_case)] +async fn main() { + // Specify a configuration file path to connect to the Blockchain + let config_path = "./config.toml".to_string(); + + // Specify a wallet file path and its encryption password + let wallet_path = "/path/to/rusk-wallet/wallet.dat".to_string(); + let wallet_password = "password".to_string(); + + // Specify the gas configuration for the transactions + let gas_limit = 500000000; + let gas_price = 1; + + // Build a configuration object with the previously set information + let moat_context = MoatContext::new( + &config_path, + &wallet_path, + &wallet_password, + gas_limit, + gas_price, + ); + + // Retrieve the keypair from the installed wallet + let (psk_user, ssk_user) = MoatCore::get_wallet_keypair(&moat_context); + + // Submit a request to the Blockchain + let psk_lp = psk_user; // we specify the same key just for testing + let request_hash = MoatCore::request_license( + &ssk_user, + &psk_lp, + &moat_context, + &mut OsRng, + ) + .await; + println!("Request transacted: {:?}", request_hash); + + // Issue a license + let attr_data = JubJubScalar::from("1234".parse::().unwrap()); + let rng = &mut OsRng; + let ssk_lp = ssk_user; // we set the same key just for testing + let license_hash = MoatCore::issue_license( + &request_hash, + &ssk_lp, + &moat_context, + &attr_data, + rng, + ) + .await; + println!("License issued: {:?}", license_hash); + + // Use a license + let psk_sp = psk_lp; // we set the same one than the LP just for testing + let challenge = JubJubScalar::from("1234".parse::().unwrap()); + let session_cookie = MoatCore::use_license( + &moat_context, + &psk_lp, + &psk_sp, + &ssk_user, + &challenge, + &license_hash, + rng, + ) + .await; + println!("Session cookie for the used license: {:?}", session_cookie); + + // Verify a session cookie + if MoatCore::verify_requested_service( + &moat_context, + &psk_lp, + &psk_sp, + &session_cookie.unwrap(), + ) + .await + { + println!("Session Cookie was correct, service should be granted."); + } else { + println!("Session Cookie was not correct, service must be denied."); + } +} diff --git a/testing-utils/test-moat-cli/Cargo.toml b/testing-utils/test-moat-cli/Cargo.toml index 5a21606..ea9fb20 100644 --- a/testing-utils/test-moat-cli/Cargo.toml +++ b/testing-utils/test-moat-cli/Cargo.toml @@ -7,7 +7,6 @@ edition = "2021" 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.6.0-rc.0" dusk-plonk = { version = "0.16", default-features = false, features = ["rkyv-impl", "alloc"] } rkyv = { version = "=0.7.39" } diff --git a/testing-utils/test-moat-cli/src/command.rs b/testing-utils/test-moat-cli/src/command.rs index 3da12b0..e433745 100644 --- a/testing-utils/test-moat-cli/src/command.rs +++ b/testing-utils/test-moat-cli/src/command.rs @@ -10,19 +10,18 @@ use crate::run_result::{ RequestsSummary, RunResult, SessionSummary, SubmitRequestSummary, UseLicenseSummary, }; -use crate::SeedableRng; use dusk_bls12_381::BlsScalar; use dusk_bytes::DeserializableSlice; use dusk_pki::{PublicSpendKey, SecretSpendKey}; use dusk_plonk::prelude::*; use dusk_wallet::{RuskHttpClient, WalletPath}; -use license_provider::{LicenseIssuer, ReferenceLP}; +use moat_core::license_provider::{LicenseIssuer, ReferenceLP}; use moat_core::{ BcInquirer, CitadelInquirer, CrsGetter, Error, JsonLoader, LicenseCircuit, LicenseSessionId, LicenseUser, RequestCreator, RequestJson, RequestScanner, RequestSender, TxAwaiter, }; -use rand::rngs::StdRng; +use rand::rngs::OsRng; use std::path::{Path, PathBuf}; use wallet_accessor::{BlockchainAccessConfig, Password, WalletAccessor}; use zk_citadel::license::{License, SessionCookie}; @@ -165,11 +164,10 @@ impl Command { Some(request_path) => RequestJson::from_file(request_path)?, _ => request_json.expect("request should be provided"), }; - let rng = &mut StdRng::from_entropy(); // seed_from_u64(0xcafe); let request = RequestCreator::create_from_hex_args( request_json.user_ssk, request_json.provider_psk.clone(), - rng, + &mut OsRng, )?; let request_hash = RunResult::to_hash_hex(&request); let tx_id = RequestSender::send_request( @@ -273,7 +271,6 @@ impl Command { lp_config_path: Option, request_hash: String, ) -> Result { - let mut rng = StdRng::from_entropy(); // seed_from_u64(0xbeef); let lp_config_path = match lp_config_path { Some(lp_config_path) => lp_config_path, _ => PathBuf::from(lp_config), @@ -297,7 +294,7 @@ impl Command { let (tx_id, license_blob) = license_issuer .issue_license( - &mut rng, + &mut OsRng, &request, &reference_lp.ssk_lp, &JubJubScalar::from(ATTRIBUTE_DATA_EXAMPLE), @@ -506,7 +503,6 @@ impl Command { // let (_, _, num_sessions) = CitadelInquirer::get_info(&client).await?; // let challenge = JubJubScalar::from(num_sessions as u64 + 1); let challenge = JubJubScalar::from(0xcafebabeu64); - let mut rng = StdRng::seed_from_u64(0xbeef); let setup_holder = match sh_opt { Some(sh) => sh, @@ -548,7 +544,7 @@ impl Command { &setup_holder.verifier, license, opening, - &mut rng, + &mut OsRng, &challenge, gas_limit, gas_price, diff --git a/testing-utils/test-moat-cli/src/main.rs b/testing-utils/test-moat-cli/src/main.rs index c0876f5..65fcf64 100644 --- a/testing-utils/test-moat-cli/src/main.rs +++ b/testing-utils/test-moat-cli/src/main.rs @@ -25,7 +25,6 @@ use crate::error::CliError; use crate::interactor::Interactor; use dusk_wallet::WalletPath; use moat_core::{JsonLoader, RequestJson}; -use rand::SeedableRng; use toml_base_config::BaseConfig; use wallet_accessor::BlockchainAccessConfig; use wallet_accessor::Password::{Pwd, PwdHash};