added database code for the serial number storage
This commit is contained in:
@@ -53,7 +53,7 @@ impl RecoveryStorage {
|
||||
|
||||
pub fn voucher_filename(voucher: &IssuanceBandwidthCredential) -> String {
|
||||
let prefix = voucher.typ().to_string();
|
||||
let suffix = voucher.blinded_g1_serial_number_bs58();
|
||||
let suffix = voucher.blinded_serial_number_bs58();
|
||||
format!("{prefix}-{suffix}.{DUMPED_VOUCHER_EXTENSION}")
|
||||
}
|
||||
|
||||
|
||||
@@ -10,9 +10,9 @@ use thiserror::Error;
|
||||
pub use nym_coconut::{
|
||||
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,
|
||||
VerifyCredentialRequest,
|
||||
BlindSignRequest, BlindedSerialNumber, BlindedSignature, Bytable, CoconutError, KeyPair,
|
||||
Parameters, PrivateAttribute, PublicAttribute, SecretKey, Signature, SignatureShare,
|
||||
VerificationKey, VerifyCredentialRequest,
|
||||
};
|
||||
|
||||
pub const VOUCHER_INFO_TYPE: &str = "BandwidthVoucher";
|
||||
|
||||
@@ -9,10 +9,10 @@ use crate::coconut::bandwidth::{
|
||||
};
|
||||
use crate::coconut::utils::scalar_serde_helper;
|
||||
use crate::error::Error;
|
||||
use bls12_381::G1Projective;
|
||||
use nym_credentials_interface::{
|
||||
aggregate_signature_shares, hash_to_scalar, prepare_blind_sign, Attribute, BlindedSignature,
|
||||
Parameters, PrivateAttribute, PublicAttribute, Signature, SignatureShare, VerificationKey,
|
||||
aggregate_signature_shares, hash_to_scalar, prepare_blind_sign, Attribute, BlindedSerialNumber,
|
||||
BlindedSignature, Parameters, PrivateAttribute, PublicAttribute, Signature, SignatureShare,
|
||||
VerificationKey,
|
||||
};
|
||||
use nym_crypto::asymmetric::{encryption, identity};
|
||||
use nym_validator_client::nym_api::EpochId;
|
||||
@@ -140,15 +140,14 @@ impl IssuanceBandwidthCredential {
|
||||
Self::new(FreePassIssuanceData::new(expiry_date))
|
||||
}
|
||||
|
||||
pub fn blind_serial_number_in_g1subgroup(&self) -> G1Projective {
|
||||
bandwidth_credential_params().gen1() * self.serial_number
|
||||
pub fn blind_serial_number(&self) -> BlindedSerialNumber {
|
||||
(bandwidth_credential_params().gen2() * self.serial_number).into()
|
||||
}
|
||||
|
||||
// NOT TO BE CONFUSED WITH BLINDED SERIAL NUMBER IN CREDENTIAL ITSELF
|
||||
pub fn blinded_g1_serial_number_bs58(&self) -> String {
|
||||
pub fn blinded_serial_number_bs58(&self) -> String {
|
||||
use nym_credentials_interface::Base58;
|
||||
|
||||
self.blind_serial_number_in_g1subgroup().to_bs58()
|
||||
self.blind_serial_number().to_bs58()
|
||||
}
|
||||
|
||||
pub fn typ(&self) -> CredentialType {
|
||||
|
||||
@@ -24,6 +24,7 @@ pub use scheme::setup::Parameters;
|
||||
pub use scheme::verification::check_vk_pairing;
|
||||
pub use scheme::verification::prove_bandwidth_credential;
|
||||
pub use scheme::verification::verify_credential;
|
||||
pub use scheme::verification::BlindedSerialNumber;
|
||||
pub use scheme::verification::VerifyCredentialRequest;
|
||||
pub use scheme::BlindedSignature;
|
||||
pub use scheme::Signature;
|
||||
|
||||
@@ -1,17 +1,46 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2022-2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use bls12_381::G2Projective;
|
||||
use group::Curve;
|
||||
use std::convert::TryFrom;
|
||||
use std::convert::TryInto;
|
||||
|
||||
use crate::error::{CoconutError, Result};
|
||||
use crate::traits::{Base58, Bytable};
|
||||
use crate::utils::try_deserialize_g2_projective;
|
||||
use bls12_381::{G2Affine, G2Projective};
|
||||
use group::Curve;
|
||||
use std::convert::TryFrom;
|
||||
use std::convert::TryInto;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::ops::Deref;
|
||||
|
||||
pub struct BlindedSerialNumber {
|
||||
pub(crate) inner: G2Projective,
|
||||
#[derive(PartialEq, Eq, Clone, Copy)]
|
||||
pub struct BlindedSerialNumber(G2Projective);
|
||||
|
||||
// use custom Debug implementation to show base58 encoding (rather than raw curve elements)
|
||||
impl Debug for BlindedSerialNumber {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_tuple("BlindedSerialNumber")
|
||||
.field(&self.to_bs58())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<G2Projective> for BlindedSerialNumber {
|
||||
fn from(value: G2Projective) -> Self {
|
||||
BlindedSerialNumber(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<G2Affine> for BlindedSerialNumber {
|
||||
fn from(value: G2Affine) -> Self {
|
||||
BlindedSerialNumber(value.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for BlindedSerialNumber {
|
||||
type Target = G2Projective;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&[u8]> for BlindedSerialNumber {
|
||||
@@ -34,13 +63,13 @@ impl TryFrom<&[u8]> for BlindedSerialNumber {
|
||||
),
|
||||
)?;
|
||||
|
||||
Ok(BlindedSerialNumber { inner })
|
||||
Ok(BlindedSerialNumber(inner))
|
||||
}
|
||||
}
|
||||
|
||||
impl Bytable for BlindedSerialNumber {
|
||||
fn to_byte_vec(&self) -> Vec<u8> {
|
||||
self.inner.to_affine().to_compressed().to_vec()
|
||||
self.0.to_affine().to_compressed().to_vec()
|
||||
}
|
||||
|
||||
fn try_from_byte_slice(slice: &[u8]) -> Result<Self> {
|
||||
|
||||
@@ -1,22 +1,21 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use core::ops::Neg;
|
||||
use std::convert::TryFrom;
|
||||
use std::convert::TryInto;
|
||||
|
||||
use bls12_381::{multi_miller_loop, G1Affine, G2Prepared, G2Projective, Scalar};
|
||||
use group::{Curve, Group};
|
||||
|
||||
use crate::error::{CoconutError, Result};
|
||||
use crate::proofs::ProofKappaZeta;
|
||||
use crate::scheme::double_use::BlindedSerialNumber;
|
||||
use crate::scheme::setup::Parameters;
|
||||
use crate::scheme::Signature;
|
||||
use crate::scheme::VerificationKey;
|
||||
use crate::traits::{Base58, Bytable};
|
||||
use crate::utils::try_deserialize_g2_projective;
|
||||
use crate::Attribute;
|
||||
use bls12_381::{multi_miller_loop, G1Affine, G2Prepared, G2Projective, Scalar};
|
||||
use core::ops::Neg;
|
||||
use group::{Curve, Group};
|
||||
use std::convert::TryFrom;
|
||||
use std::convert::TryInto;
|
||||
|
||||
pub use crate::scheme::double_use::BlindedSerialNumber;
|
||||
|
||||
// TODO NAMING: this whole thing
|
||||
// Theta
|
||||
@@ -25,7 +24,7 @@ pub struct VerifyCredentialRequest {
|
||||
// blinded_message (kappa)
|
||||
pub blinded_message: G2Projective,
|
||||
// blinded serial number (zeta)
|
||||
pub blinded_serial_number: G2Projective,
|
||||
pub blinded_serial_number: BlindedSerialNumber,
|
||||
// sigma
|
||||
pub credential: Signature,
|
||||
// pi_v
|
||||
@@ -53,15 +52,10 @@ impl TryFrom<&[u8]> for VerifyCredentialRequest {
|
||||
),
|
||||
)?;
|
||||
|
||||
// safety: we just checked for the length so the unwraps are fine
|
||||
#[allow(clippy::unwrap_used)]
|
||||
let blinded_serial_number_bytes = bytes[96..192].try_into().unwrap();
|
||||
let blinded_serial_number = try_deserialize_g2_projective(
|
||||
&blinded_serial_number_bytes,
|
||||
CoconutError::Deserialization(
|
||||
"failed to deserialize the blinded serial number (zeta)".to_string(),
|
||||
),
|
||||
)?;
|
||||
let blinded_serial_number_bytes = &bytes[96..192];
|
||||
let blinded_serial_number =
|
||||
BlindedSerialNumber::try_from_byte_slice(blinded_serial_number_bytes)?;
|
||||
|
||||
let credential = Signature::try_from(&bytes[192..288])?;
|
||||
|
||||
let pi_v = ProofKappaZeta::from_bytes(&bytes[288..])?;
|
||||
@@ -87,7 +81,7 @@ impl VerifyCredentialRequest {
|
||||
|
||||
pub fn has_blinded_serial_number(&self, blinded_serial_number_bs58: &str) -> Result<bool> {
|
||||
let blinded_serial_number = BlindedSerialNumber::try_from_bs58(blinded_serial_number_bs58)?;
|
||||
let ret = self.blinded_serial_number.eq(&blinded_serial_number.inner);
|
||||
let ret = self.blinded_serial_number.eq(&blinded_serial_number);
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
@@ -112,10 +106,7 @@ impl VerifyCredentialRequest {
|
||||
}
|
||||
|
||||
pub fn blinded_serial_number_bs58(&self) -> String {
|
||||
let blinded_serial_nuumber = BlindedSerialNumber {
|
||||
inner: self.blinded_serial_number,
|
||||
};
|
||||
blinded_serial_nuumber.to_bs58()
|
||||
self.blinded_serial_number.to_bs58()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,7 +189,7 @@ pub fn prove_bandwidth_credential(
|
||||
|
||||
Ok(VerifyCredentialRequest {
|
||||
blinded_message,
|
||||
blinded_serial_number,
|
||||
blinded_serial_number: blinded_serial_number.into(),
|
||||
credential: signature_prime,
|
||||
pi_v,
|
||||
})
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
CREATE TABLE spent_credential
|
||||
(
|
||||
blinded_serial_number_bs58 TEXT NOT NULL PRIMARY KEY UNIQUE,
|
||||
was_freepass BOOLEAN NOT NULL,
|
||||
client_address_bs58 TEXT NOT NULL REFERENCES shared_keys (client_address_bs58)
|
||||
);
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::node::storage::models::PersistedBandwidth;
|
||||
use crate::node::storage::models::{PersistedBandwidth, SpentCredential};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct BandwidthManager {
|
||||
@@ -103,4 +103,54 @@ impl BandwidthManager {
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Mark received credential as spent and insert it into the storage.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `blinded_serial_number_bs58`: the unique blinded serial number embedded in the credential
|
||||
/// * `was_freepass`: indicates whether the spent credential was a freepass
|
||||
/// * `client_address_bs58`: address of the client that spent the credential
|
||||
pub(crate) async fn insert_spent_credential(
|
||||
&self,
|
||||
blinded_serial_number_bs58: &str,
|
||||
was_freepass: bool,
|
||||
client_address_bs58: &str,
|
||||
) -> Result<(), sqlx::Error> {
|
||||
sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO spent_credential
|
||||
(blinded_serial_number_bs58, was_freepass, client_address_bs58)
|
||||
VALUES (?, ?, ?)
|
||||
"#,
|
||||
blinded_serial_number_bs58,
|
||||
was_freepass,
|
||||
client_address_bs58
|
||||
)
|
||||
.execute(&self.connection_pool)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Retrieve the spent credential with the provided blinded serial number from the storage.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `blinded_serial_number_bs58`: the unique blinded serial number embedded in the credential
|
||||
pub(crate) async fn retrieve_spent_credential(
|
||||
&self,
|
||||
blinded_serial_number_bs58: &str,
|
||||
) -> Result<Option<SpentCredential>, sqlx::Error> {
|
||||
sqlx::query_as!(
|
||||
SpentCredential,
|
||||
r#"
|
||||
SELECT * FROM spent_credential
|
||||
WHERE blinded_serial_number_bs58 = ?
|
||||
LIMIT 1
|
||||
"#,
|
||||
blinded_serial_number_bs58,
|
||||
)
|
||||
.fetch_optional(&self.connection_pool)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ use crate::node::storage::models::{PersistedSharedKeys, StoredMessage};
|
||||
use crate::node::storage::shared_keys::SharedKeysManager;
|
||||
use async_trait::async_trait;
|
||||
use log::{debug, error};
|
||||
use nym_credentials_interface::{Base58, BlindedSerialNumber};
|
||||
use nym_gateway_requests::registration::handshake::SharedKeys;
|
||||
use nym_sphinx::DestinationAddressBytes;
|
||||
use sqlx::ConnectOptions;
|
||||
@@ -134,6 +135,29 @@ pub(crate) trait Storage: Send + Sync {
|
||||
client_address: DestinationAddressBytes,
|
||||
amount: i64,
|
||||
) -> Result<(), StorageError>;
|
||||
|
||||
/// Mark received credential as spent and insert it into the storage.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `blinded_serial_number`: the unique blinded serial number embedded in the credential
|
||||
/// * `client_address`: address of the client that spent the credential
|
||||
async fn insert_spent_credential(
|
||||
&self,
|
||||
blinded_serial_number: BlindedSerialNumber,
|
||||
was_freepass: bool,
|
||||
client_address: DestinationAddressBytes,
|
||||
) -> Result<(), StorageError>;
|
||||
|
||||
/// Check if the credential with the provided blinded serial number if already present in the storage.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `blinded_serial_number`: the unique blinded serial number embedded in the credential
|
||||
async fn contains_credential(
|
||||
&self,
|
||||
blinded_serial_number: &BlindedSerialNumber,
|
||||
) -> Result<bool, StorageError>;
|
||||
}
|
||||
|
||||
// note that clone here is fine as upon cloning the same underlying pool will be used
|
||||
@@ -304,6 +328,34 @@ impl Storage for PersistentStorage {
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn insert_spent_credential(
|
||||
&self,
|
||||
blinded_serial_number: BlindedSerialNumber,
|
||||
was_freepass: bool,
|
||||
client_address: DestinationAddressBytes,
|
||||
) -> Result<(), StorageError> {
|
||||
self.bandwidth_manager
|
||||
.insert_spent_credential(
|
||||
&blinded_serial_number.to_bs58(),
|
||||
was_freepass,
|
||||
&client_address.as_base58_string(),
|
||||
)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn contains_credential(
|
||||
&self,
|
||||
blinded_serial_number: &BlindedSerialNumber,
|
||||
) -> Result<bool, StorageError> {
|
||||
let cred = self
|
||||
.bandwidth_manager
|
||||
.retrieve_spent_credential(&blinded_serial_number.to_bs58())
|
||||
.await?;
|
||||
|
||||
Ok(cred.is_some())
|
||||
}
|
||||
}
|
||||
|
||||
/// In-memory implementation of `Storage`. The intention is primarily in testing environments.
|
||||
@@ -393,4 +445,19 @@ impl Storage for InMemStorage {
|
||||
) -> Result<(), StorageError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn insert_spent_credential(
|
||||
&self,
|
||||
blinded_serial_number: BlindedSerialNumber,
|
||||
client_address: DestinationAddressBytes,
|
||||
) -> Result<(), StorageError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn contains_credential(
|
||||
&self,
|
||||
blinded_serial_number: &BlindedSerialNumber,
|
||||
) -> Result<bool, StorageError> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use sqlx::FromRow;
|
||||
|
||||
pub(crate) struct PersistedSharedKeys {
|
||||
pub(crate) client_address_bs58: String,
|
||||
pub(crate) derived_aes128_ctr_blake3_hmac_keys_bs58: String,
|
||||
@@ -18,3 +20,13 @@ pub(crate) struct PersistedBandwidth {
|
||||
pub(crate) client_address_bs58: String,
|
||||
pub(crate) available: i64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, FromRow)]
|
||||
pub(crate) struct SpentCredential {
|
||||
#[allow(dead_code)]
|
||||
pub(crate) blinded_serial_number_bs58: String,
|
||||
#[allow(dead_code)]
|
||||
pub(crate) was_freepass: bool,
|
||||
#[allow(dead_code)]
|
||||
pub(crate) client_address_bs58: String,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user