missing serialization
This commit is contained in:
Generated
+1
@@ -5388,6 +5388,7 @@ dependencies = [
|
||||
"bls12_381",
|
||||
"nym-coconut",
|
||||
"serde",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -45,4 +45,7 @@ pub enum BandwidthControllerError {
|
||||
|
||||
#[error("Threshold not set yet")]
|
||||
NoThreshold,
|
||||
|
||||
#[error("can't handle recovering storage with revision {stored}. {expected} was expected")]
|
||||
UnsupportedCredentialStorageRevision { stored: u8, expected: u8 },
|
||||
}
|
||||
|
||||
@@ -2,40 +2,21 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::error::BandwidthControllerError;
|
||||
use nym_credential_storage::models::{StorableIssuedCredential, StoredIssuedCredential};
|
||||
use nym_credential_storage::models::StoredIssuedCredential;
|
||||
use nym_credentials::coconut::bandwidth::issued::CURRENT_SERIALIZATION_REVISION;
|
||||
use nym_credentials::coconut::bandwidth::IssuedBandwidthCredential;
|
||||
use nym_validator_client::nym_api::EpochId;
|
||||
|
||||
pub fn stored_credential_to_issued_bandwidth(
|
||||
cred: StoredIssuedCredential,
|
||||
) -> Result<IssuedBandwidthCredential, BandwidthControllerError> {
|
||||
/*
|
||||
let bandwidth_credential = self
|
||||
.storage
|
||||
.get_next_coconut_credential()
|
||||
.await
|
||||
.map_err(|err| BandwidthControllerError::CredentialStorageError(Box::new(err)))?;
|
||||
let voucher_value = u64::from_str(&bandwidth_credential.voucher_value)
|
||||
.map_err(|_| StorageError::InconsistentData)?;
|
||||
let voucher_info = bandwidth_credential.voucher_info.clone();
|
||||
let serial_number = Zeroizing::new(nym_coconut_interface::Attribute::try_from_bs58(
|
||||
bandwidth_credential.serial_number,
|
||||
)?);
|
||||
let binding_number = Zeroizing::new(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)
|
||||
.map_err(|_| StorageError::InconsistentData)?;
|
||||
if cred.serialization_revision != CURRENT_SERIALIZATION_REVISION {
|
||||
return Err(
|
||||
BandwidthControllerError::UnsupportedCredentialStorageRevision {
|
||||
stored: cred.serialization_revision,
|
||||
expected: CURRENT_SERIALIZATION_REVISION,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
*/
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn issued_bandwidth_to_stored_credential(
|
||||
issued: IssuedBandwidthCredential,
|
||||
epoch_id: EpochId,
|
||||
) -> StoredIssuedCredential {
|
||||
todo!()
|
||||
Ok(IssuedBandwidthCredential::unpack_v1(&cred.credential_data)?)
|
||||
}
|
||||
|
||||
@@ -13,5 +13,6 @@ license.workspace = true
|
||||
[dependencies]
|
||||
bls12_381 = { workspace = true, default-features = false }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
thiserror = { workspace = true }
|
||||
|
||||
nym-coconut = { path = "../nymcoconut" }
|
||||
|
||||
@@ -4,9 +4,11 @@
|
||||
use bls12_381::Scalar;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::str::FromStr;
|
||||
use thiserror::Error;
|
||||
|
||||
pub use nym_coconut::{
|
||||
aggregate_signature_shares, aggregate_verification_keys, blind_sign, hash_to_scalar,
|
||||
aggregate_signature_shares, aggregate_verification_keys, blind_sign, hash_to_scalar, keygen,
|
||||
prepare_blind_sign, prove_bandwidth_credential, verify_credential, Attribute, Base58,
|
||||
BlindSignRequest, BlindedSignature, Bytable, CoconutError, KeyPair, Parameters,
|
||||
PrivateAttribute, PublicAttribute, SecretKey, Signature, SignatureShare, VerificationKey,
|
||||
@@ -20,12 +22,30 @@ pub const FREE_PASS_INFO_TYPE: &str = "FreeBandwidthPass";
|
||||
// fn prove_credential(&self) -> Result<(), ()>;
|
||||
// }
|
||||
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Debug, Error)]
|
||||
#[error("{0} is not a valid credential type")]
|
||||
pub struct UnknownCredentialType(String);
|
||||
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
|
||||
pub enum CredentialType {
|
||||
Voucher,
|
||||
FreePass,
|
||||
}
|
||||
|
||||
impl FromStr for CredentialType {
|
||||
type Err = UnknownCredentialType;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
if s == VOUCHER_INFO_TYPE {
|
||||
Ok(CredentialType::Voucher)
|
||||
} else if s == FREE_PASS_INFO_TYPE {
|
||||
Ok(CredentialType::FreePass)
|
||||
} else {
|
||||
Err(UnknownCredentialType(s.to_string()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CredentialType {
|
||||
pub fn validate(&self, type_plain: &str) -> bool {
|
||||
match self {
|
||||
@@ -63,7 +83,7 @@ pub struct CredentialSigningData {
|
||||
pub typ: CredentialType,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct CredentialSpendingData {
|
||||
pub embedded_private_attributes: usize,
|
||||
|
||||
|
||||
@@ -127,6 +127,10 @@ impl IssuanceBandwidthCredential {
|
||||
))
|
||||
}
|
||||
|
||||
pub fn new_freepass(expiry_date: Option<OffsetDateTime>) -> Self {
|
||||
Self::new(FreePassIssuanceData::new(expiry_date))
|
||||
}
|
||||
|
||||
pub fn blind_serial_number_in_g1subgroup(&self) -> G1Projective {
|
||||
bandwidth_credential_params().gen1() * self.serial_number
|
||||
}
|
||||
@@ -137,10 +141,6 @@ impl IssuanceBandwidthCredential {
|
||||
self.blind_serial_number_in_g1subgroup().to_bs58()
|
||||
}
|
||||
|
||||
pub fn new_freepass(expiry_date: Option<OffsetDateTime>) -> Self {
|
||||
Self::new(FreePassIssuanceData::new(expiry_date))
|
||||
}
|
||||
|
||||
pub fn typ(&self) -> CredentialType {
|
||||
self.variant_data.info()
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ pub use scheme::issuance::blind_sign;
|
||||
pub use scheme::issuance::prepare_blind_sign;
|
||||
pub use scheme::issuance::verify_partial_blind_signature;
|
||||
pub use scheme::issuance::BlindSignRequest;
|
||||
pub use scheme::keygen::keygen;
|
||||
pub use scheme::keygen::ttp_keygen;
|
||||
pub use scheme::keygen::KeyPair;
|
||||
pub use scheme::keygen::SecretKey;
|
||||
|
||||
@@ -565,7 +565,6 @@ impl TryFrom<&[u8]> for KeyPair {
|
||||
/// Generate a single Coconut keypair ((x, y0, y1...), (g2^x, g2^y0, ...)).
|
||||
/// It is not suitable for threshold credentials as all subsequent calls to `keygen` generate keys
|
||||
/// that are independent of each other.
|
||||
#[cfg(test)]
|
||||
pub fn keygen(params: &Parameters) -> KeyPair {
|
||||
let attributes = params.gen_hs().len();
|
||||
|
||||
|
||||
@@ -32,3 +32,4 @@ nym-credentials-interface = { path = "../../common/credentials-interface" }
|
||||
workspace = true
|
||||
default-features = false
|
||||
|
||||
|
||||
|
||||
@@ -15,7 +15,10 @@ pub mod types;
|
||||
|
||||
/// Defines the current version of the communication protocol between gateway and clients.
|
||||
/// It has to be incremented for any breaking change.
|
||||
pub const PROTOCOL_VERSION: u8 = 1;
|
||||
// history:
|
||||
// 1 - initial release
|
||||
// 2 - changes to client credentials structure
|
||||
pub const PROTOCOL_VERSION: u8 = 2;
|
||||
|
||||
pub type GatewayMac = HmacOutput<GatewayIntegrityHmacAlgorithm>;
|
||||
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
|
||||
use crate::GatewayRequestsError;
|
||||
use nym_credentials::coconut::bandwidth::CredentialSpendingData;
|
||||
use nym_credentials_interface::CoconutError;
|
||||
use nym_credentials_interface::{CoconutError, VerifyCredentialRequest};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct CredentialSpendingWithEpoch {
|
||||
/// The cryptographic material required for spending the underlying credential.
|
||||
pub data: CredentialSpendingData,
|
||||
@@ -16,6 +16,23 @@ pub struct CredentialSpendingWithEpoch {
|
||||
pub epoch_id: u64,
|
||||
}
|
||||
|
||||
// just a helper macro for checking required length and advancing the buffer
|
||||
macro_rules! ensure_len_and_advance {
|
||||
($b:expr, $n:expr) => {{
|
||||
if $b.len() < $n {
|
||||
return Err(GatewayRequestsError::CredentialDeserializationFailureEOF);
|
||||
}
|
||||
// create binding to the desired range
|
||||
let bytes = &$b[..$n];
|
||||
|
||||
// update the initial binding
|
||||
|
||||
$b = &$b[$n..];
|
||||
|
||||
bytes
|
||||
}};
|
||||
}
|
||||
|
||||
impl CredentialSpendingWithEpoch {
|
||||
pub fn new(data: CredentialSpendingData, epoch_id: u64) -> Self {
|
||||
CredentialSpendingWithEpoch { data, epoch_id }
|
||||
@@ -39,10 +56,138 @@ impl CredentialSpendingWithEpoch {
|
||||
}
|
||||
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
todo!()
|
||||
// simple length prefixed serialization
|
||||
// TODO: change it to a standard format instead
|
||||
let mut bytes = Vec::new();
|
||||
|
||||
let embedded_private = (self.data.embedded_private_attributes as u32).to_be_bytes();
|
||||
let theta = self.data.verify_credential_request.to_bytes();
|
||||
let theta_len = (theta.len() as u32).to_be_bytes();
|
||||
|
||||
let public = (self.data.public_attributes_plain.len() as u32).to_be_bytes();
|
||||
let typ = self.data.typ.to_string();
|
||||
let typ_bytes = typ.as_bytes();
|
||||
let typ_len = (typ_bytes.len() as u32).to_be_bytes();
|
||||
|
||||
bytes.extend_from_slice(&embedded_private);
|
||||
bytes.extend_from_slice(&theta_len);
|
||||
bytes.extend_from_slice(&theta);
|
||||
bytes.extend_from_slice(&public);
|
||||
|
||||
for pub_element in &self.data.public_attributes_plain {
|
||||
let bytes_el = pub_element.as_bytes();
|
||||
let len = (bytes_el.len() as u32).to_be_bytes();
|
||||
|
||||
bytes.extend_from_slice(&len);
|
||||
bytes.extend_from_slice(bytes_el);
|
||||
}
|
||||
|
||||
bytes.extend_from_slice(&typ_len);
|
||||
bytes.extend_from_slice(typ_bytes);
|
||||
bytes.extend_from_slice(&self.epoch_id.to_be_bytes());
|
||||
|
||||
bytes
|
||||
}
|
||||
|
||||
pub fn try_from_bytes(raw: &[u8]) -> Result<Self, GatewayRequestsError> {
|
||||
todo!()
|
||||
// initial binding
|
||||
let mut b = raw;
|
||||
let embedded_private_bytes = ensure_len_and_advance!(b, 4);
|
||||
let embedded_private_attributes =
|
||||
u32::from_be_bytes(embedded_private_bytes.try_into().unwrap()) as usize;
|
||||
|
||||
let theta_len_bytes = ensure_len_and_advance!(b, 4);
|
||||
let theta_len = u32::from_be_bytes(theta_len_bytes.try_into().unwrap()) as usize;
|
||||
|
||||
let theta_bytes = ensure_len_and_advance!(b, theta_len);
|
||||
let theta = VerifyCredentialRequest::from_bytes(theta_bytes)
|
||||
.map_err(GatewayRequestsError::CredentialDeserializationFailureMalformedTheta)?;
|
||||
|
||||
let public_bytes = ensure_len_and_advance!(b, 4);
|
||||
let public = u32::from_be_bytes(public_bytes.try_into().unwrap()) as usize;
|
||||
|
||||
let mut public_attributes_plain = Vec::with_capacity(public);
|
||||
for _ in 0..public {
|
||||
let element_len_bytes = ensure_len_and_advance!(b, 4);
|
||||
let element_len = u32::from_be_bytes(element_len_bytes.try_into().unwrap()) as usize;
|
||||
|
||||
let element_bytes = ensure_len_and_advance!(b, element_len);
|
||||
let element = String::from_utf8(element_bytes.to_vec())?;
|
||||
public_attributes_plain.push(element);
|
||||
}
|
||||
|
||||
let typ_len_bytes = ensure_len_and_advance!(b, 4);
|
||||
let typ_len = u32::from_be_bytes(typ_len_bytes.try_into().unwrap()) as usize;
|
||||
|
||||
let typ_bytes = ensure_len_and_advance!(b, typ_len);
|
||||
let raw_typ = String::from_utf8(typ_bytes.to_vec())?;
|
||||
let typ = raw_typ.parse()?;
|
||||
|
||||
// tell the linter to chill out in for this last iteration
|
||||
#[allow(unused_assignments)]
|
||||
let epoch_id_bytes = ensure_len_and_advance!(b, 8);
|
||||
let epoch_id = u64::from_be_bytes(epoch_id_bytes.try_into().unwrap());
|
||||
|
||||
Ok(CredentialSpendingWithEpoch {
|
||||
data: CredentialSpendingData {
|
||||
embedded_private_attributes,
|
||||
verify_credential_request: theta,
|
||||
public_attributes_plain,
|
||||
typ,
|
||||
},
|
||||
epoch_id,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use nym_credentials::coconut::bandwidth::bandwidth_credential_params;
|
||||
use nym_credentials::IssuanceBandwidthCredential;
|
||||
use nym_credentials_interface::{blind_sign, hash_to_scalar};
|
||||
|
||||
#[test]
|
||||
fn credential_roundtrip() {
|
||||
// make valid request
|
||||
let params = bandwidth_credential_params();
|
||||
let keypair = nym_credentials_interface::keygen(params);
|
||||
|
||||
let issuance = IssuanceBandwidthCredential::new_freepass(None);
|
||||
let sig_req = issuance.prepare_for_signing();
|
||||
let pub_attrs_hashed = sig_req
|
||||
.public_attributes_plain
|
||||
.iter()
|
||||
.map(hash_to_scalar)
|
||||
.collect::<Vec<_>>();
|
||||
let pub_attrs = pub_attrs_hashed.iter().collect::<Vec<_>>();
|
||||
let blind_sig = blind_sign(
|
||||
params,
|
||||
keypair.secret_key(),
|
||||
&sig_req.blind_sign_request,
|
||||
&pub_attrs,
|
||||
)
|
||||
.unwrap();
|
||||
let sig = blind_sig
|
||||
.unblind(
|
||||
keypair.verification_key(),
|
||||
&sig_req.pedersen_commitments_openings,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let issued = issuance.into_issued_credential(sig);
|
||||
let spending = issued
|
||||
.prepare_for_spending(keypair.verification_key())
|
||||
.unwrap();
|
||||
|
||||
let with_epoch = CredentialSpendingWithEpoch {
|
||||
data: spending,
|
||||
epoch_id: 42,
|
||||
};
|
||||
|
||||
let bytes = with_epoch.to_bytes();
|
||||
let recovered = CredentialSpendingWithEpoch::try_from_bytes(&bytes).unwrap();
|
||||
|
||||
assert_eq!(with_epoch, recovered);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2020-2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::authentication::encrypted_address::EncryptedAddressBytes;
|
||||
@@ -8,6 +8,7 @@ use crate::registration::handshake::SharedKeys;
|
||||
use crate::{GatewayMacSize, PROTOCOL_VERSION};
|
||||
use log::error;
|
||||
use nym_credentials::coconut::bandwidth::CredentialSpendingData;
|
||||
use nym_credentials_interface::{CoconutError, UnknownCredentialType};
|
||||
use nym_crypto::generic_array::typenum::Unsigned;
|
||||
use nym_crypto::hmac::recompute_keyed_hmac_and_verify_tag;
|
||||
use nym_crypto::symmetric::stream_cipher;
|
||||
@@ -18,6 +19,7 @@ use nym_sphinx::params::{GatewayEncryptionAlgorithm, GatewayIntegrityHmacAlgorit
|
||||
use nym_sphinx::DestinationAddressBytes;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use std::string::FromUtf8Error;
|
||||
use thiserror::Error;
|
||||
use tungstenite::protocol::Message;
|
||||
|
||||
@@ -102,6 +104,18 @@ pub enum GatewayRequestsError {
|
||||
#[from]
|
||||
source: MixPacketFormattingError,
|
||||
},
|
||||
|
||||
#[error("failed to deserialize provided credential: EOF")]
|
||||
CredentialDeserializationFailureEOF,
|
||||
|
||||
#[error("failed to deserialize provided credential: malformed string: {0}")]
|
||||
CredentialDeserializationFailureMalformedString(#[from] FromUtf8Error),
|
||||
|
||||
#[error("failed to deserialize provided credential: {0}")]
|
||||
CredentialDeserializationFailureUnknownType(#[from] UnknownCredentialType),
|
||||
|
||||
#[error("failed to deserialize provided credential: malformed verify request: {0}")]
|
||||
CredentialDeserializationFailureMalformedTheta(CoconutError),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
|
||||
Generated
+1
@@ -3943,6 +3943,7 @@ dependencies = [
|
||||
"bls12_381",
|
||||
"nym-coconut",
|
||||
"serde",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
Generated
+1
@@ -3198,6 +3198,7 @@ dependencies = [
|
||||
"bls12_381",
|
||||
"nym-coconut",
|
||||
"serde",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
Reference in New Issue
Block a user