From e41796b157a848f736e54b04a7c56377f7a071dc Mon Sep 17 00:00:00 2001 From: Simon Wicky Date: Mon, 23 Oct 2023 11:27:06 +0200 Subject: [PATCH] WIP spending ecash --- Cargo.lock | 1 + common/bandwidth-controller/src/error.rs | 4 ++ common/bandwidth-controller/src/lib.rs | 70 ++++++++++--------- .../client-libs/gateway-client/src/client.rs | 8 +-- .../src/ephemeral_storage.rs | 8 +++ .../src/persistent_storage.rs | 7 ++ common/credential-storage/src/storage.rs | 13 ++++ .../connection_handler/authenticated.rs | 8 ++- nym-api/src/coconut/comm.rs | 6 +- nym-api/src/coconut/mod.rs | 13 ++-- 10 files changed, 92 insertions(+), 46 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4e31782267..0be8e336bb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7658,6 +7658,7 @@ dependencies = [ "nym-network-defaults", "nym-service-provider-directory-common", "nym-vesting-contract-common", + "nym_compact_ecash", "openssl", "prost 0.12.1", "reqwest", diff --git a/common/bandwidth-controller/src/error.rs b/common/bandwidth-controller/src/error.rs index 5f464c82e5..f8f9315956 100644 --- a/common/bandwidth-controller/src/error.rs +++ b/common/bandwidth-controller/src/error.rs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use nym_coconut_interface::CoconutError; +use nym_compact_ecash::error::CompactEcashError; use nym_credential_storage::error::StorageError; use nym_credentials::error::Error as CredentialsError; use nym_crypto::asymmetric::encryption::KeyRecoveryError; @@ -28,6 +29,9 @@ pub enum BandwidthControllerError { #[error("Coconut error - {0}")] CoconutError(#[from] CoconutError), + #[error("Ecash error - {0}")] + EcashError(#[from] CompactEcashError), + #[error("Validator client error - {0}")] ValidatorError(#[from] ValidatorClientError), diff --git a/common/bandwidth-controller/src/lib.rs b/common/bandwidth-controller/src/lib.rs index d9a714b263..fb13bbe84b 100644 --- a/common/bandwidth-controller/src/lib.rs +++ b/common/bandwidth-controller/src/lib.rs @@ -2,17 +2,15 @@ // SPDX-License-Identifier: Apache-2.0 use crate::error::BandwidthControllerError; +use nym_compact_ecash::scheme::{Payment, Wallet}; +use nym_compact_ecash::setup::{setup, GroupParameters}; +use nym_compact_ecash::{generate_keypair_user, Base58, PayInfo}; use nym_credential_storage::error::StorageError; use nym_credential_storage::storage::Storage; +use nym_credentials::obtain_aggregate_verification_key; use nym_validator_client::coconut::all_coconut_api_clients; use nym_validator_client::nyxd::contract_traits::DkgQueryClient; use std::str::FromStr; -use { - nym_coconut_interface::Base58, - nym_credentials::coconut::{ - bandwidth::prepare_for_spending, utils::obtain_aggregate_verification_key, - }, -}; pub mod acquire; pub mod error; @@ -31,57 +29,63 @@ impl BandwidthController { &self.storage } - pub async fn prepare_coconut_credential( + pub async fn prepare_ecash_credential( &self, - ) -> Result<(nym_coconut_interface::Credential, i64), BandwidthControllerError> + ) -> Result<(Payment, String, i64), BandwidthControllerError> where C: DkgQueryClient + Sync + Send, ::StorageError: Send + Sync + 'static, { - let bandwidth_credential = self + let ecash_credential = self .storage - .get_next_coconut_credential() + .get_next_ecash_credential() .await .map_err(|err| BandwidthControllerError::CredentialStorageError(Box::new(err)))?; - let voucher_value = u64::from_str(&bandwidth_credential.voucher_value) + let voucher_value = u64::from_str(&ecash_credential.voucher_value) .map_err(|_| StorageError::InconsistentData)?; - let voucher_info = bandwidth_credential.voucher_info.clone(); - let serial_number = - nym_coconut_interface::Attribute::try_from_bs58(bandwidth_credential.serial_number)?; - let binding_number = - nym_coconut_interface::Attribute::try_from_bs58(bandwidth_credential.binding_number)?; - let signature = - nym_coconut_interface::Signature::try_from_bs58(bandwidth_credential.signature)?; - let epoch_id = u64::from_str(&bandwidth_credential.epoch_id) + let voucher_info = ecash_credential.voucher_info.clone(); + let wallet = Wallet::try_from_bs58(ecash_credential.wallet)?; + let epoch_id = u64::from_str(&ecash_credential.epoch_id) .map_err(|_| StorageError::InconsistentData)?; let coconut_api_clients = all_coconut_api_clients(&self.client, epoch_id).await?; let verification_key = obtain_aggregate_verification_key(&coconut_api_clients).await?; + let some_L_I_guess = 100; //SW: TEMPORARY VALUE + let params = setup(some_L_I_guess); + let sk_user = generate_keypair_user(&GroupParameters::new()?).secret_key(); //SW : TODO Retreive key fro mcredential storage + let pay_info = PayInfo { info: [0u8; 32] }; //SW: TEMPORARY VALUE. Waiting for actual computation + let nb_tickets = 1u64; //SW: TEMPORARY VALUE, what should we put there? + // the below would only be executed once we know where we want to spend it (i.e. which gateway and stuff) - Ok(( - prepare_for_spending( - voucher_value, - voucher_info, - serial_number, - binding_number, - epoch_id, - &signature, - &verification_key, - )?, - bandwidth_credential.id, - )) + + let (payment, _) = wallet.spend( + ¶ms, + &verification_key, + &sk_user, + &pay_info, + false, + nb_tickets, + )?; + + //SW : TODO Store new wallet + + Ok((payment, wallet.to_bs58(), ecash_credential.id)) } - pub async fn consume_credential(&self, id: i64) -> Result<(), BandwidthControllerError> + pub async fn update_ecash_credential( + &self, + wallet: String, + id: i64, + ) -> Result<(), BandwidthControllerError> where ::StorageError: Send + Sync + 'static, { // JS: shouldn't we send some contract/validator/gateway message here to actually, you know, // consume it? self.storage - .consume_coconut_credential(id) + .update_ecash_credential(wallet, id) .await .map_err(|err| BandwidthControllerError::CredentialStorageError(Box::new(err))) } diff --git a/common/client-libs/gateway-client/src/client.rs b/common/client-libs/gateway-client/src/client.rs index a95fee0bf7..d9cbe28691 100644 --- a/common/client-libs/gateway-client/src/client.rs +++ b/common/client-libs/gateway-client/src/client.rs @@ -567,18 +567,18 @@ impl GatewayClient { return self.try_claim_testnet_bandwidth().await; } - let (credential, credential_id) = self + let (payment, new_wallet, new_wallet_id) = self .bandwidth_controller .as_ref() .unwrap() - .prepare_coconut_credential() + .prepare_ecash_credential() .await?; - self.claim_coconut_bandwidth(credential).await?; + //self.claim_ecash_bandwidth(payment).await?; self.bandwidth_controller .as_ref() .unwrap() - .consume_credential(credential_id) + .update_ecash_credential(new_wallet, new_wallet_id) .await?; Ok(()) diff --git a/common/credential-storage/src/ephemeral_storage.rs b/common/credential-storage/src/ephemeral_storage.rs index 8e966da06d..89f8c87c6c 100644 --- a/common/credential-storage/src/ephemeral_storage.rs +++ b/common/credential-storage/src/ephemeral_storage.rs @@ -91,4 +91,12 @@ impl Storage for EphemeralStorage { Ok(()) } + + async fn update_ecash_credential(&self, wallet: String, id: i64) -> Result<(), StorageError> { + // self.coconut_credential_manager + // .update_ecash_credential(wallet, id) + // .await; + //S W: TBD + Ok(()) + } } diff --git a/common/credential-storage/src/persistent_storage.rs b/common/credential-storage/src/persistent_storage.rs index 9802e0a471..9e8e25a896 100644 --- a/common/credential-storage/src/persistent_storage.rs +++ b/common/credential-storage/src/persistent_storage.rs @@ -122,4 +122,11 @@ impl Storage for PersistentStorage { Ok(()) } + + async fn update_ecash_credential(&self, release: String, id: i64) -> Result<(), StorageError> { + // self.coconut_credential_manager + //// .await?; + /// SW: TBD + Ok(()) + } } diff --git a/common/credential-storage/src/storage.rs b/common/credential-storage/src/storage.rs index 2c0748c5bc..66b806728a 100644 --- a/common/credential-storage/src/storage.rs +++ b/common/credential-storage/src/storage.rs @@ -57,4 +57,17 @@ pub trait Storage: Send + Sync { /// /// * `id`: Id of the credential to be consumed. async fn consume_coconut_credential(&self, id: i64) -> Result<(), Self::StorageError>; + + /// Update in the database the specified credential. + /// + /// # Arguments + /// + /// * `wallet` : New Ecash wallet credential + /// * `id`: Id of the credential to be consumed. + /// + async fn update_ecash_credential( + &self, + wallet: String, + id: i64, + ) -> Result<(), Self::StorageError>; } diff --git a/gateway/src/node/client_handling/websocket/connection_handler/authenticated.rs b/gateway/src/node/client_handling/websocket/connection_handler/authenticated.rs index 103c1ad102..4780481025 100644 --- a/gateway/src/node/client_handling/websocket/connection_handler/authenticated.rs +++ b/gateway/src/node/client_handling/websocket/connection_handler/authenticated.rs @@ -250,7 +250,13 @@ where let aggregated_verification_key = nym_credentials::obtain_aggregate_verification_key(&credential_api_clients).await?; - if !credential.verify(&aggregated_verification_key) { + let aggregated_verification_key_converted = + nym_coconut_interface::VerificationKey::try_from( + aggregated_verification_key.to_bytes().as_slice(), + ) + .expect("converstion should not fail"); //SW : TEMPORARY workaround for type conversion + + if !credential.verify(&aggregated_verification_key_converted) { return Err(RequestHandlingError::InvalidBandwidthCredential( String::from("credential failed to verify on gateway"), )); diff --git a/nym-api/src/coconut/comm.rs b/nym-api/src/coconut/comm.rs index 9358af95be..f0e074905a 100644 --- a/nym-api/src/coconut/comm.rs +++ b/nym-api/src/coconut/comm.rs @@ -4,14 +4,14 @@ use crate::coconut::error::Result; use crate::nyxd; use nym_coconut_dkg_common::types::EpochId; -use nym_coconut_interface::VerificationKey; +use nym_compact_ecash::VerificationKeyAuth; use nym_credentials::coconut::utils::obtain_aggregate_verification_key; use nym_validator_client::coconut::all_coconut_api_clients; use std::ops::Deref; #[async_trait] pub trait APICommunicationChannel { - async fn aggregated_verification_key(&self, epoch_id: EpochId) -> Result; + async fn aggregated_verification_key(&self, epoch_id: EpochId) -> Result; } pub(crate) struct QueryCommunicationChannel { @@ -26,7 +26,7 @@ impl QueryCommunicationChannel { #[async_trait] impl APICommunicationChannel for QueryCommunicationChannel { - async fn aggregated_verification_key(&self, epoch_id: EpochId) -> Result { + async fn aggregated_verification_key(&self, epoch_id: EpochId) -> Result { let client = self.nyxd_client.0.read().await; let coconut_api_clients = all_coconut_api_clients(client.deref(), epoch_id).await?; let vk = obtain_aggregate_verification_key(&coconut_api_clients).await?; diff --git a/nym-api/src/coconut/mod.rs b/nym-api/src/coconut/mod.rs index 13dbaf5ed2..9fa58f475e 100644 --- a/nym-api/src/coconut/mod.rs +++ b/nym-api/src/coconut/mod.rs @@ -12,6 +12,7 @@ use keypair::KeyPair; use nym_api_requests::coconut::{ BlindSignRequestBody, BlindedSignatureResponse, VerifyCredentialBody, VerifyCredentialResponse, }; +use nym_coconut::VerificationKey; use nym_coconut_bandwidth_contract_common::spend_credential::{ funds_from_cosmos_msgs, SpendCredentialStatus, }; @@ -137,10 +138,7 @@ impl State { } } - pub async fn verification_key( - &self, - epoch_id: EpochId, - ) -> Result { + pub async fn verification_key(&self, epoch_id: EpochId) -> Result { self.comm_channel .aggregated_verification_key(epoch_id) .await @@ -281,9 +279,14 @@ pub async fn verify_bandwidth_credential( let verification_key = state .verification_key(*verify_credential_body.credential().epoch_id()) .await?; + + let verification_key_converted = + VerificationKey::try_from(verification_key.to_bytes().as_slice()) + .expect("converstion should not fail"); //SW : TEMPORARY workaround for type conversion + let mut vote_yes = verify_credential_body .credential() - .verify(&verification_key); + .verify(&verification_key_converted); vote_yes &= Coin::from(proposed_release_funds) == Coin::new(