Skip to content

Feature/consumable bandwidth #766

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Sep 9, 2021
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 16 additions & 6 deletions clients/tauri-client/src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
)]

use coconut_interface::{
self, Attribute, Credential, Parameters, Signature, Theta, VerificationKey,
self, hash_to_scalar, Attribute, Credential, Parameters, Signature, Theta, VerificationKey,
};
use credentials::{obtain_aggregate_signature, obtain_aggregate_verification_key};
use std::sync::Arc;
Expand All @@ -15,19 +15,29 @@ struct State {
signatures: Vec<Signature>,
n_attributes: u32,
params: Parameters,
public_attributes_bytes: Vec<Vec<u8>>,
public_attributes: Vec<Attribute>,
private_attributes: Vec<Attribute>,
aggregated_verification_key: Option<VerificationKey>,
}

impl State {
fn init(public_attributes: Vec<Attribute>, private_attributes: Vec<Attribute>) -> State {
let n_attributes = (public_attributes.len() + private_attributes.len()) as u32;
fn init(public_attributes_bytes: Vec<Vec<u8>>, private_attributes_bytes: Vec<Vec<u8>>) -> State {
let n_attributes = (public_attributes_bytes.len() + private_attributes_bytes.len()) as u32;
let params = Parameters::new(n_attributes).unwrap();
let public_attributes = public_attributes_bytes
.iter()
.map(hash_to_scalar)
.collect::<Vec<Attribute>>();
let private_attributes = private_attributes_bytes
.iter()
.map(hash_to_scalar)
.collect::<Vec<Attribute>>();
State {
signatures: Vec::new(),
n_attributes,
params,
public_attributes_bytes,
public_attributes,
private_attributes,
aggregated_verification_key: None,
Expand Down Expand Up @@ -137,7 +147,7 @@ async fn verify_credential(
let credential = Credential::new(
state.n_attributes,
theta,
&state.public_attributes,
state.public_attributes_bytes.clone(),
state
.signatures
.get(idx)
Expand Down Expand Up @@ -170,8 +180,8 @@ async fn get_credential(
}

fn main() {
let public_attributes = vec![coconut_interface::hash_to_scalar("public_key")];
let private_attributes = vec![coconut_interface::hash_to_scalar("private_key")];
let public_attributes = vec![b"public_key".to_vec()];
let private_attributes = vec![b"private_key".to_vec()];
tauri::Builder::default()
.manage(Arc::new(RwLock::new(State::init(
public_attributes,
Expand Down
28 changes: 11 additions & 17 deletions common/coconut-interface/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,43 +16,37 @@ pub struct Credential {
n_params: u32,
#[getset(get = "pub")]
theta: Theta,
public_attributes: Vec<String>,
public_attributes: Vec<Vec<u8>>,
#[getset(get = "pub")]
signature: Signature,
}
impl Credential {
pub fn new(
n_params: u32,
theta: Theta,
public_attributes: &[Attribute],
public_attributes: Vec<Vec<u8>>,
signature: &Signature,
) -> Credential {
Credential {
n_params,
theta,
public_attributes: public_attributes
.iter()
.map(|attr| attr.to_bs58())
.collect(),
public_attributes,
signature: *signature,
}
}

pub fn public_attributes(&self) -> Vec<Attribute> {
self.public_attributes
.iter()
.map(|x| Attribute::try_from_bs58(x).unwrap())
.collect()
pub fn public_attributes(&self) -> Vec<Vec<u8>> {
self.public_attributes.clone()
}

pub fn verify(&self, verification_key: &VerificationKey) -> bool {
let params = Parameters::new(self.n_params).unwrap();
coconut_rs::verify_credential(
&params,
verification_key,
&self.theta,
&self.public_attributes(),
)
let public_attributes = self
.public_attributes
.iter()
.map(hash_to_scalar)
.collect::<Vec<Attribute>>();
coconut_rs::verify_credential(&params, verification_key, &self.theta, &public_attributes)
}
}

Expand Down
17 changes: 9 additions & 8 deletions common/credentials/src/bandwidth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,22 @@
// right now this has no double-spending protection, spender binding, etc
// it's the simplest possible case

use url::Url;

use crate::error::Error;
use crate::utils::{obtain_aggregate_signature, prepare_credential_for_spending};
use coconut_interface::{hash_to_scalar, Credential, Parameters, Signature, VerificationKey};
use url::Url;

const BANDWIDTH_VALUE: &str = "Bandwidth: infinite (for now)";
const BANDWIDTH_VALUE: u64 = 1024 * 1024; // 1 MB

pub const PUBLIC_ATTRIBUTES: u32 = 1;
pub const PRIVATE_ATTRIBUTES: u32 = 1;
pub const TOTAL_ATTRIBUTES: u32 = PUBLIC_ATTRIBUTES + PRIVATE_ATTRIBUTES;

// TODO: this definitely has to be moved somewhere else. It's just a temporary solution
pub async fn obtain_signature(raw_identity: &[u8], validators: &[Url]) -> Result<Signature, Error> {
let public_attributes = vec![hash_to_scalar(raw_identity)];
let private_attributes = vec![hash_to_scalar(BANDWIDTH_VALUE)];
let public_attributes = vec![hash_to_scalar(BANDWIDTH_VALUE.to_be_bytes())];
let private_attributes = vec![hash_to_scalar(raw_identity)];

let params = Parameters::new(TOTAL_ATTRIBUTES)?;

Expand All @@ -32,15 +33,15 @@ pub fn prepare_for_spending(
signature: &Signature,
verification_key: &VerificationKey,
) -> Result<Credential, Error> {
let public_attributes = vec![hash_to_scalar(raw_identity)];
let private_attributes = vec![hash_to_scalar(BANDWIDTH_VALUE)];
let public_attributes = vec![BANDWIDTH_VALUE.to_be_bytes().to_vec()];
let private_attributes = vec![raw_identity.to_vec()];

let params = Parameters::new(TOTAL_ATTRIBUTES)?;

prepare_credential_for_spending(
&params,
&public_attributes,
&private_attributes,
public_attributes,
private_attributes,
signature,
verification_key,
)
Expand Down
9 changes: 9 additions & 0 deletions common/credentials/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,13 @@ pub enum Error {

#[error("Run into a validato client error - {0}")]
ValidatorClientError(#[from] ValidatorClientError),

#[error("Not enough public attributes were specified")]
NotEnoughPublicAttributes,

#[error("Bandwidth is expected to be represented on 8 bytes")]
InvalidBandwidthSize,

#[error("Bandwidth value doesn't fit in 8 bytes. Use some of the already allocated bandwidth")]
BandwidthOverflow,
}
16 changes: 10 additions & 6 deletions common/credentials/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@

use crate::error::Error;
use coconut_interface::{
aggregate_signature_shares, aggregate_verification_keys, prepare_blind_sign, prove_credential,
Attribute, BlindSignRequestBody, Credential, Parameters, Signature, SignatureShare,
VerificationKey,
aggregate_signature_shares, aggregate_verification_keys, hash_to_scalar, prepare_blind_sign,
prove_credential, Attribute, BlindSignRequestBody, Credential, Parameters, Signature,
SignatureShare, VerificationKey,
};
use url::Url;

Expand Down Expand Up @@ -118,12 +118,16 @@ pub async fn obtain_aggregate_signature(
// TODO: better type flow
pub fn prepare_credential_for_spending(
params: &Parameters,
public_attributes: &[Attribute],
private_attributes: &[Attribute],
public_attributes: Vec<Vec<u8>>,
private_attributes: Vec<Vec<u8>>,
signature: &Signature,
verification_key: &VerificationKey,
) -> Result<Credential, Error> {
let theta = prove_credential(params, verification_key, signature, private_attributes)?;
let private_attributes = private_attributes
.iter()
.map(hash_to_scalar)
.collect::<Vec<Attribute>>();
let theta = prove_credential(params, verification_key, signature, &private_attributes)?;

Ok(Credential::new(
(public_attributes.len() + private_attributes.len()) as u32,
Expand Down
1 change: 1 addition & 0 deletions gateway/gateway-requests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ crypto = { path = "../../common/crypto" }
pemstore = { path = "../../common/pemstore" }

coconut-interface = { path = "../../common/coconut-interface" }
credentials = { path = "../../common/credentials"}

[dependencies.tungstenite]
version = "0.13.0"
Expand Down
77 changes: 77 additions & 0 deletions gateway/src/node/client_handling/bandwidth.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Copyright 2021 - Nym Technologies SA <[email protected]>
// SPDX-License-Identifier: Apache-2.0

use std::collections::HashMap;
use std::convert::TryFrom;
use std::sync::atomic::AtomicU64;
use std::sync::Arc;
use tokio::sync::RwLock;

use coconut_interface::Credential;
use credentials::error::Error;
use nymsphinx::DestinationAddressBytes;

pub type BandwidthDatabase = Arc<RwLock<HashMap<DestinationAddressBytes, AtomicU64>>>;

const BANDWIDTH_INDEX: usize = 0;

pub struct Bandwidth {
value: u64,
}

impl Bandwidth {
pub fn value(&self) -> u64 {
self.value
}

pub async fn consume_bandwidth(
bandwidths: &BandwidthDatabase,
remote_address: &DestinationAddressBytes,
consumed: u64,
) -> bool {
if let Some(bandwidth) = bandwidths.write().await.get_mut(remote_address) {
let bandwidth_mut = bandwidth.get_mut();
if *bandwidth_mut >= consumed {
*bandwidth_mut -= consumed;
return true;
}
}
false
}

pub async fn increase_bandwidth(
bandwidths: &BandwidthDatabase,
remote_address: &DestinationAddressBytes,
increase: u64,
) -> Result<(), Error> {
let mut db = bandwidths.write().await;
if let Some(bandwidth) = db.get_mut(remote_address) {
let bandwidth_mut = bandwidth.get_mut();
if let Some(new_bandwidth) = bandwidth_mut.checked_add(increase) {
*bandwidth_mut = new_bandwidth;
} else {
return Err(Error::BandwidthOverflow);
}
} else {
db.insert(*remote_address, AtomicU64::new(increase));
}
Ok(())
}
}

impl TryFrom<Credential> for Bandwidth {
type Error = Error;

fn try_from(credential: Credential) -> Result<Self, Self::Error> {
match credential.public_attributes().get(BANDWIDTH_INDEX) {
None => Err(Error::NotEnoughPublicAttributes),
Some(attr) => match <[u8; 8]>::try_from(attr.as_slice()) {
Ok(bandwidth_bytes) => {
let value = u64::from_be_bytes(bandwidth_bytes);
Ok(Self { value })
}
Err(_) => Err(Error::InvalidBandwidthSize),
},
}
}
}
1 change: 1 addition & 0 deletions gateway/src/node/client_handling/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Copyright 2020 - Nym Technologies SA <[email protected]>
// SPDX-License-Identifier: Apache-2.0

mod bandwidth;
pub(crate) mod clients_handler;
pub(crate) mod websocket;
Loading