Skip to content

Commit

Permalink
Getting CRS from host via HTTP with CRS hash in header (#39)
Browse files Browse the repository at this point in the history
  • Loading branch information
miloszm authored Nov 14, 2023
1 parent 34e463f commit bffb209
Show file tree
Hide file tree
Showing 10 changed files with 135 additions and 24 deletions.
33 changes: 33 additions & 0 deletions integration-tests/tests/blockchain/get_crs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// 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_wallet::RuskHttpClient;
use moat_core::{CrsGetter, Error};
use toml_base_config::BaseConfig;
use tracing::trace;
use wallet_accessor::BlockchainAccessConfig;

const MIN_CRS_SIZE: usize = 10 * 1024 * 1024;

#[tokio::test(flavor = "multi_thread")]
#[cfg_attr(not(feature = "int_tests"), ignore)]
async fn get_crs() -> Result<(), Error> {
let config_path =
concat!(env!("CARGO_MANIFEST_DIR"), "/tests/config/config.toml");

let cfg = BlockchainAccessConfig::load_path(config_path)?;

let client = RuskHttpClient::new(cfg.rusk_address);

let crs = CrsGetter::get_crs(&client).await?;

assert!(crs.len() >= MIN_CRS_SIZE);

trace!("crs={}...", hex::encode(&crs[0..64]));
trace!("crs length={}", crs.len());

Ok(())
}
1 change: 1 addition & 0 deletions integration-tests/tests/blockchain/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
//
// Copyright (c) DUSK NETWORK. All rights reserved.

mod get_crs;
mod retrieve_txs;
mod stake_add_owner;
26 changes: 14 additions & 12 deletions integration-tests/tests/citadel/int_test_user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use dusk_plonk::prelude::*;
use dusk_wallet::{RuskHttpClient, WalletPath};
use license_provider::{LicenseIssuer, ReferenceLP};
use moat_core::{
BcInquirer, CitadelInquirer, Error, JsonLoader, LicenseCircuit,
BcInquirer, CitadelInquirer, CrsGetter, Error, JsonLoader, LicenseCircuit,
LicenseSessionId, LicenseUser, PayloadRetriever, RequestCreator,
RequestJson, RequestSender, TxAwaiter,
};
Expand All @@ -46,7 +46,6 @@ const GAS_LIMIT: u64 = 5_000_000_000;
const GAS_PRICE: u64 = 1;

static LABEL: &[u8] = b"dusk-network";
const CAPACITY: usize = 17; // capacity required for the setup

/// Calls license contract's issue license method.
/// Awaits for confirmation of the contract-calling transaction.
Expand Down Expand Up @@ -122,33 +121,36 @@ async fn user_round_trip() -> Result<(), Error> {
// PUB_PARAMS initialization code
let mut rng = StdRng::seed_from_u64(0xbeef);

info!("performing setup");
let pp = PublicParameters::setup(1 << CAPACITY, &mut rng)
.expect("Initializing public parameters should succeed");
let blockchain_config_path =
concat!(env!("CARGO_MANIFEST_DIR"), "/tests/config/config.toml");

let blockchain_config =
BlockchainAccessConfig::load_path(blockchain_config_path)?;

let client = RuskHttpClient::new(blockchain_config.rusk_address.clone());

info!("obtaining CRS");
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()) };

info!("compiling circuit");
let (prover, verifier) = Compiler::compile::<LicenseCircuit>(&pp, LABEL)
.expect("Compiling circuit should succeed");

let request_path =
concat!(env!("CARGO_MANIFEST_DIR"), "/tests/request/request.json");
let blockchain_config_path =
concat!(env!("CARGO_MANIFEST_DIR"), "/tests/config/config.toml");

let lp_config_path =
concat!(env!("CARGO_MANIFEST_DIR"), "/tests/config/lp2.json");

let reference_lp = ReferenceLP::create(&lp_config_path)?;

let blockchain_config =
BlockchainAccessConfig::load_path(blockchain_config_path)?;

let wallet_path = WalletPath::from(
PathBuf::from(WALLET_PATH).as_path().join("wallet.dat"),
);

let client = RuskHttpClient::new(blockchain_config.rusk_address.clone());

// create request
let request_json: RequestJson = RequestJson::from_file(request_path)?;
let ssk_user_bytes = hex::decode(request_json.user_ssk.clone())?;
Expand Down
11 changes: 6 additions & 5 deletions moat-cli-user/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use dusk_pki::{PublicSpendKey, SecretSpendKey};
use dusk_plonk::prelude::*;
use dusk_wallet::{RuskHttpClient, WalletPath};
use moat_core::{
BcInquirer, CitadelInquirer, Error, LicenseCircuit, LicenseUser,
BcInquirer, CitadelInquirer, CrsGetter, Error, LicenseCircuit, LicenseUser,
RequestCreator, RequestJson, RequestScanner, RequestSender, TxAwaiter,
};
use rand::rngs::StdRng;
Expand All @@ -41,7 +41,6 @@ pub(crate) enum Command {
}

static LABEL: &[u8] = b"dusk-network";
const CAPACITY: usize = 17; // capacity required for the setup

impl Command {
#[allow(clippy::too_many_arguments)]
Expand Down Expand Up @@ -340,9 +339,11 @@ impl Command {
let setup_holder = match sh_opt {
Some(sh) => sh,
_ => {
println!("performing setup");
let pp = PublicParameters::setup(1 << CAPACITY, &mut rng)
.expect("Initializing public parameters should succeed");
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::<LicenseCircuit>(&pp, LABEL)
Expand Down
11 changes: 6 additions & 5 deletions moat-cli/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use dusk_plonk::prelude::*;
use dusk_wallet::{RuskHttpClient, WalletPath};
use license_provider::{LicenseIssuer, ReferenceLP};
use moat_core::{
BcInquirer, CitadelInquirer, Error, JsonLoader, LicenseCircuit,
BcInquirer, CitadelInquirer, CrsGetter, Error, JsonLoader, LicenseCircuit,
LicenseSessionId, LicenseUser, RequestCreator, RequestJson, RequestScanner,
RequestSender, TxAwaiter,
};
Expand Down Expand Up @@ -57,7 +57,6 @@ pub(crate) enum Command {
}

static LABEL: &[u8] = b"dusk-network";
const CAPACITY: usize = 17; // capacity required for the setup

impl Command {
#[allow(clippy::too_many_arguments)]
Expand Down Expand Up @@ -504,9 +503,11 @@ impl Command {
let setup_holder = match sh_opt {
Some(sh) => sh,
_ => {
println!("performing setup");
let pp = PublicParameters::setup(1 << CAPACITY, &mut rng)
.expect("Initializing public parameters should succeed");
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::<LicenseCircuit>(&pp, LABEL)
Expand Down
2 changes: 1 addition & 1 deletion moat-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ code-hasher={ path = "../macros/code-hasher" }
tracing = "0.1"
bytes = "1.4"
reqwest = "0.11"
sha2 = "0.10"

[dev-dependencies]
tokio = { version = "1.15", features = ["rt-multi-thread", "time", "fs", "macros"] }
sha2 = "0.10"
53 changes: 53 additions & 0 deletions moat-core/src/blockchain_queries/crs_getter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// 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 crate::Error;
use dusk_wallet::{RuskHttpClient, RuskRequest};
use reqwest::Response;
use sha2::{Digest, Sha256};

pub struct CrsGetter;

type CRSHash = [u8; 32];
const CRS_HASH_HEADER: &str = "crs-hash";

impl CrsGetter {
pub async fn get_crs(client: &RuskHttpClient) -> Result<Vec<u8>, Error> {
let crs_request = RuskRequest::new("crs", vec![]);
let result = client.call_raw(2, "rusk", &crs_request, false).await;
match result {
Ok(response) => {
let received_hash = Self::hash_from_header(&response)?;
let crs = response.bytes().await?;
let this_hash = Self::hash_of_bytes(crs.as_ref());
if received_hash != this_hash {
return Err(Error::CRS(Box::from("corrupted CRS")));
}
Ok(crs.to_vec())
}
Err(err) => Err(err.into()),
}
}

fn hash_from_header(response: &Response) -> Result<CRSHash, Error> {
let crs_hash = response
.headers()
.get(CRS_HASH_HEADER)
.ok_or(Error::CRS(Box::from("missing CRS hash header")))?;
let crs_hash = crs_hash.to_str().map_err(|_| {
Error::CRS(Box::from("failed CRS hash header string conversion"))
})?;
let mut h = CRSHash::default();
hex::decode_to_slice(crs_hash, h.as_mut_slice())?;
Ok(h)
}

fn hash_of_bytes<T: AsRef<[u8]>>(bytes: T) -> CRSHash {
let mut hasher = Sha256::new();
hasher.update(bytes.as_ref());
hasher.finalize().into()
}
}
2 changes: 2 additions & 0 deletions moat-core/src/blockchain_queries/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
// Copyright (c) DUSK NETWORK. All rights reserved.

mod bc_inquirer;
mod crs_getter;
mod tx_awaiter;
mod tx_inquirer;

pub use bc_inquirer::BcInquirer;
pub use crs_getter::CrsGetter;
pub use tx_awaiter::TxAwaiter;
pub use tx_inquirer::TxInquirer;
18 changes: 18 additions & 0 deletions moat-core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ pub enum Error {
Transaction(Box<str>),
#[error("Stream item not present or stream error: {0:?}")]
Stream(Box<str>),
#[error("A PLONK error occurred: {0:?}")]
Plonk(Arc<dusk_plonk::error::Error>),
#[error("A CRS error occurred: {0:?}")]
CRS(Box<str>),
#[error(transparent)]
HttpClient(Arc<reqwest::Error>),
}

impl From<serde_json::Error> for Error {
Expand Down Expand Up @@ -82,3 +88,15 @@ impl From<tokio_tungstenite::tungstenite::Error> for Error {
Error::WebSocket(Arc::from(e))
}
}

impl From<dusk_plonk::error::Error> for Error {
fn from(e: dusk_plonk::error::Error) -> Self {
Error::Plonk(Arc::from(e))
}
}

impl From<reqwest::Error> for Error {
fn from(e: reqwest::Error) -> Self {
Error::HttpClient(Arc::from(e))
}
}
2 changes: 1 addition & 1 deletion moat-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ pub use bc_types::*;
pub use blockchain_payloads::{
PayloadExtractor, PayloadRetriever, PayloadSender,
};
pub use blockchain_queries::{BcInquirer, TxAwaiter, TxInquirer};
pub use blockchain_queries::{BcInquirer, CrsGetter, TxAwaiter, TxInquirer};
pub use circuit::*;
pub use citadel_licenses::LicenseUser;
pub use citadel_queries::{
Expand Down

0 comments on commit bffb209

Please sign in to comment.