From aea962b5466f2478225bbd99830168c776fbc768 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Thu, 25 Jul 2024 12:57:09 +0100 Subject: [PATCH] explicit aliases for ExpirationDate and TicketType --- common/ecash-time/src/lib.rs | 7 +- common/network-defaults/src/ecash.rs | 2 +- .../src/constants.rs | 4 +- .../nym_offline_compact_ecash/src/helpers.rs | 28 +++++++- common/nym_offline_compact_ecash/src/lib.rs | 2 + .../src/scheme/aggregation.rs | 18 ++--- .../src/scheme/expiration_date_signatures.rs | 53 ++++++--------- .../src/scheme/identify.rs | 15 ++--- .../src/scheme/keygen.rs | 4 -- .../src/scheme/mod.rs | 40 ++++++----- .../src/scheme/withdrawal.rs | 67 ++++++++----------- .../src/tests/e2e.rs | 3 +- .../src/tests/helpers.rs | 9 +-- common/nym_offline_compact_ecash/src/utils.rs | 5 -- 14 files changed, 125 insertions(+), 132 deletions(-) diff --git a/common/ecash-time/src/lib.rs b/common/ecash-time/src/lib.rs index e6ac459508..332b51e2e6 100644 --- a/common/ecash-time/src/lib.rs +++ b/common/ecash-time/src/lib.rs @@ -6,13 +6,16 @@ use time::{Duration, PrimitiveDateTime, Time}; pub use time::{Date, OffsetDateTime}; pub trait EcashTime { - fn ecash_unix_timestamp(&self) -> u64 { + fn ecash_unix_timestamp(&self) -> u32 { let ts = self.ecash_datetime().unix_timestamp(); // just panic on pre-1970 timestamps... assert!(ts > 0); - ts as u64 + // and on anything in 22nd century... + assert!(ts <= u32::MAX as i64); + + ts as u32 } fn ecash_date(&self) -> Date { diff --git a/common/network-defaults/src/ecash.rs b/common/network-defaults/src/ecash.rs index 35a49d88f0..f6ceb630aa 100644 --- a/common/network-defaults/src/ecash.rs +++ b/common/network-defaults/src/ecash.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 /// Specifies the maximum validity of the issued ticketbooks. -pub const TICKETBOOK_VALIDITY_DAYS: u64 = 7; +pub const TICKETBOOK_VALIDITY_DAYS: u32 = 7; /// Specifies the number of tickets in each issued ticketbook. pub const TICKETBOOK_SIZE: u64 = 50; diff --git a/common/nym_offline_compact_ecash/src/constants.rs b/common/nym_offline_compact_ecash/src/constants.rs index 72b0893cbd..0902c2fa0f 100644 --- a/common/nym_offline_compact_ecash/src/constants.rs +++ b/common/nym_offline_compact_ecash/src/constants.rs @@ -9,9 +9,9 @@ pub const PUBLIC_ATTRIBUTES_LEN: usize = 2; //expiration date and ticket type pub const PRIVATE_ATTRIBUTES_LEN: usize = 2; //user and wallet secret pub const ATTRIBUTES_LEN: usize = PUBLIC_ATTRIBUTES_LEN + PRIVATE_ATTRIBUTES_LEN; // number of attributes encoded in a single zk-nym credential -pub const CRED_VALIDITY_PERIOD_DAYS: u64 = TICKETBOOK_VALIDITY_DAYS; +pub const CRED_VALIDITY_PERIOD_DAYS: u32 = TICKETBOOK_VALIDITY_DAYS; -pub(crate) const SECONDS_PER_DAY: u64 = 86400; +pub(crate) const SECONDS_PER_DAY: u32 = 86400; /// Total number of tickets in each issued ticket book. pub const NB_TICKETS: u64 = TICKETBOOK_SIZE; diff --git a/common/nym_offline_compact_ecash/src/helpers.rs b/common/nym_offline_compact_ecash/src/helpers.rs index 1fa0a15245..7c18214c7d 100644 --- a/common/nym_offline_compact_ecash/src/helpers.rs +++ b/common/nym_offline_compact_ecash/src/helpers.rs @@ -2,8 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 use crate::utils::try_deserialize_g1_projective; -use crate::CompactEcashError; -use bls12_381::G1Projective; +use crate::{CompactEcashError, EncodedDate, EncodedTicketType}; +use bls12_381::{G1Projective, Scalar}; use group::Curve; use std::any::{type_name, Any}; @@ -35,3 +35,27 @@ pub(crate) fn recover_g1_tuple( Ok((first, second)) } + +pub(crate) fn date_scalar(date: EncodedDate) -> Scalar { + Scalar::from(date as u64) +} + +// TODO: this will not work for **all** scalars, +// but timestamps have extremely (relatively speaking) limited range, +// so this should be fine +pub(crate) fn scalar_date(scalar: &Scalar) -> EncodedDate { + let b = scalar.to_bytes(); + u64::from_le_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]]) as EncodedDate +} + +pub(crate) fn type_scalar(t_type: EncodedTicketType) -> Scalar { + Scalar::from(t_type as u64) +} + +// TODO: this will not work for **all** scalars, +// but ticket types have extremely (relatively speaking) limited range, +// so this should be fine +pub(crate) fn scalar_type(scalar: &Scalar) -> EncodedTicketType { + let b = scalar.to_bytes(); + u64::from_le_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]]) as EncodedTicketType +} diff --git a/common/nym_offline_compact_ecash/src/lib.rs b/common/nym_offline_compact_ecash/src/lib.rs index b47ee4b56e..f522145047 100644 --- a/common/nym_offline_compact_ecash/src/lib.rs +++ b/common/nym_offline_compact_ecash/src/lib.rs @@ -42,6 +42,8 @@ mod traits; pub mod utils; pub type Attribute = Scalar; +pub type EncodedTicketType = u8; +pub type EncodedDate = u32; pub fn ecash_parameters() -> &'static setup::Parameters { static ECASH_PARAMS: OnceLock = OnceLock::new(); diff --git a/common/nym_offline_compact_ecash/src/scheme/aggregation.rs b/common/nym_offline_compact_ecash/src/scheme/aggregation.rs index e961efc189..4d7c116121 100644 --- a/common/nym_offline_compact_ecash/src/scheme/aggregation.rs +++ b/common/nym_offline_compact_ecash/src/scheme/aggregation.rs @@ -1,23 +1,19 @@ // Copyright 2024 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use core::iter::Sum; -use core::ops::Mul; - -use bls12_381::{G2Prepared, G2Projective, Scalar}; -use group::Curve; -use itertools::Itertools; - use crate::common_types::{PartialSignature, Signature, SignatureShare, SignerIndex}; use crate::error::{CompactEcashError, Result}; -use crate::scheme::expiration_date_signatures::scalar_date; +use crate::helpers::{scalar_date, scalar_type}; use crate::scheme::keygen::{SecretKeyUser, VerificationKeyAuth}; use crate::scheme::withdrawal::RequestInfo; use crate::scheme::{PartialWallet, Wallet, WalletSignatures}; -use crate::utils::{ - check_bilinear_pairing, perform_lagrangian_interpolation_at_origin, scalar_type, -}; +use crate::utils::{check_bilinear_pairing, perform_lagrangian_interpolation_at_origin}; use crate::{ecash_group_parameters, Attribute}; +use bls12_381::{G2Prepared, G2Projective, Scalar}; +use core::iter::Sum; +use core::ops::Mul; +use group::Curve; +use itertools::Itertools; pub(crate) trait Aggregatable: Sized { fn aggregate(aggregatable: &[Self], indices: Option<&[SignerIndex]>) -> Result; diff --git a/common/nym_offline_compact_ecash/src/scheme/expiration_date_signatures.rs b/common/nym_offline_compact_ecash/src/scheme/expiration_date_signatures.rs index b419d0ef73..ca0078b012 100644 --- a/common/nym_offline_compact_ecash/src/scheme/expiration_date_signatures.rs +++ b/common/nym_offline_compact_ecash/src/scheme/expiration_date_signatures.rs @@ -2,11 +2,12 @@ // SPDX-License-Identifier: Apache-2.0 use crate::common_types::{Signature, SignerIndex}; -use crate::constants; use crate::error::{CompactEcashError, Result}; +use crate::helpers::date_scalar; use crate::scheme::keygen::{SecretKeyAuth, VerificationKeyAuth}; use crate::utils::generate_lagrangian_coefficients_at_origin; use crate::utils::{batch_verify_signatures, hash_g1}; +use crate::{constants, EncodedDate}; use bls12_381::{G1Projective, Scalar}; use itertools::Itertools; use serde::{Deserialize, Serialize}; @@ -19,8 +20,8 @@ pub type PartialExpirationDateSignature = ExpirationDateSignature; #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] pub struct AnnotatedExpirationDateSignature { pub signature: ExpirationDateSignature, - pub expiration_timestamp: u64, - pub spending_timestamp: u64, + pub expiration_timestamp: EncodedDate, + pub spending_timestamp: EncodedDate, } impl Borrow for AnnotatedExpirationDateSignature { @@ -66,17 +67,17 @@ where /// The validity period is determined by the constant `CRED_VALIDITY_PERIOD` in the `constants` module. pub fn sign_expiration_date( sk_auth: &SecretKeyAuth, - expiration_unix_timestamp: u64, + expiration_unix_timestamp: EncodedDate, ) -> Result> { if sk_auth.ys.len() < 3 { return Err(CompactEcashError::KeyTooShort); } - let m0: Scalar = Scalar::from(expiration_unix_timestamp); + let m0: Scalar = date_scalar(expiration_unix_timestamp); let m2: Scalar = constants::TYPE_EXP; let partial_s_exponent = sk_auth.x + sk_auth.ys[0] * m0 + sk_auth.ys[2] * m2; - let sign_expiration = |offset: u64| { + let sign_expiration = |offset: u32| { // we produce tuples of (assuming CRED_VALIDITY_PERIOD_DAYS = 30): // (expiration, expiration - 29) // (expiration, expiration - 28) @@ -84,7 +85,7 @@ pub fn sign_expiration_date( // (expiration, expiration) let spending_unix_timestamp = expiration_unix_timestamp - ((constants::CRED_VALIDITY_PERIOD_DAYS - offset - 1) * constants::SECONDS_PER_DAY); - let m1: Scalar = Scalar::from(spending_unix_timestamp); + let m1: Scalar = date_scalar(spending_unix_timestamp); // Compute the hash let h = hash_g1([m0.to_bytes(), m1.to_bytes()].concat()); // Sign the attributes by performing scalar-point multiplications and accumulating the result @@ -136,22 +137,22 @@ pub fn sign_expiration_date( pub fn verify_valid_dates_signatures( vk: &VerificationKeyAuth, signatures: &[B], - expiration_date: u64, + expiration_date: EncodedDate, ) -> Result<()> where B: Borrow, { - let m0: Scalar = Scalar::from(expiration_date); + let m0: Scalar = date_scalar(expiration_date); let m2: Scalar = constants::TYPE_EXP; let partially_signed = vk.alpha + vk.beta_g2[0] * m0 + vk.beta_g2[2] * m2; let mut pairing_terms = Vec::with_capacity(signatures.len()); for (i, sig) in signatures.iter().enumerate() { - let l = i as u64; + let l = i as u32; let valid_date = expiration_date - ((constants::CRED_VALIDITY_PERIOD_DAYS - l - 1) * constants::SECONDS_PER_DAY); - let m1: Scalar = Scalar::from(valid_date); + let m1: Scalar = date_scalar(valid_date); // Compute the hash let h = hash_g1([m0.to_bytes(), m1.to_bytes()].concat()); @@ -199,7 +200,7 @@ where /// fn _aggregate_expiration_signatures( vk: &VerificationKeyAuth, - expiration_date: u64, + expiration_date: EncodedDate, signatures_shares: &[ExpirationDateSignatureShare], validate_shares: bool, ) -> Result> @@ -244,12 +245,12 @@ where let mut aggregated_date_signatures: Vec = Vec::with_capacity(constants::CRED_VALIDITY_PERIOD_DAYS as usize); - let m0: Scalar = Scalar::from(expiration_date); + let m0: Scalar = date_scalar(expiration_date); for l in 0..constants::CRED_VALIDITY_PERIOD_DAYS { let valid_date = expiration_date - ((constants::CRED_VALIDITY_PERIOD_DAYS - l - 1) * constants::SECONDS_PER_DAY); - let m1: Scalar = Scalar::from(valid_date); + let m1: Scalar = date_scalar(valid_date); // Compute the hash let h = hash_g1([m0.to_bytes(), m1.to_bytes()].concat()); @@ -299,7 +300,7 @@ where /// pub fn aggregate_expiration_signatures( vk: &VerificationKeyAuth, - expiration_date: u64, + expiration_date: EncodedDate, signatures_shares: &[ExpirationDateSignatureShare], ) -> Result> where @@ -314,7 +315,7 @@ where /// It further annotates the result with timestamp information pub fn aggregate_annotated_expiration_signatures( vk: &VerificationKeyAuth, - expiration_date: u64, + expiration_date: EncodedDate, signatures_shares: &[ExpirationDateSignatureShare], ) -> Result> { // it's sufficient to just verify the first share as if the rest of them don't match, @@ -332,7 +333,7 @@ pub fn aggregate_annotated_expiration_signatures( return Err(CompactEcashError::ExpirationDateSignatureVerification); } - let l = i as u64; + let l = i as u32; let expected_spending = sig.expiration_timestamp - ((constants::CRED_VALIDITY_PERIOD_DAYS - l - 1) * constants::SECONDS_PER_DAY); @@ -361,7 +362,7 @@ pub fn aggregate_annotated_expiration_signatures( /// It is expected the caller has already pre-validated them via manual calls to `verify_valid_dates_signatures` pub fn unchecked_aggregate_expiration_signatures( vk: &VerificationKeyAuth, - expiration_date: u64, + expiration_date: EncodedDate, signatures_shares: &[ExpirationDateSignatureShare], ) -> Result> { _aggregate_expiration_signatures(vk, expiration_date, signatures_shares, false) @@ -383,13 +384,13 @@ pub fn unchecked_aggregate_expiration_signatures( /// If a valid index is found, returns `Ok(index)`. If no valid index is found /// (i.e., `spend_date` is earlier than `expiration_date - 30`), returns `Err(InvalidDateError)`. /// -pub fn find_index(spend_date: u64, expiration_date: u64) -> Result { +pub fn find_index(spend_date: EncodedDate, expiration_date: EncodedDate) -> Result { let start_date = expiration_date - ((constants::CRED_VALIDITY_PERIOD_DAYS - 1) * constants::SECONDS_PER_DAY); if spend_date >= start_date { let index_a = ((spend_date - start_date) / constants::SECONDS_PER_DAY) as usize; - if index_a as u64 >= constants::CRED_VALIDITY_PERIOD_DAYS { + if index_a as u32 >= constants::CRED_VALIDITY_PERIOD_DAYS { Err(CompactEcashError::SpendDateTooLate) } else { Ok(index_a) @@ -399,18 +400,6 @@ pub fn find_index(spend_date: u64, expiration_date: u64) -> Result { } } -pub fn date_scalar(date: u64) -> Scalar { - Scalar::from(date) -} - -// TODO: this will not work for **all** scalars, -// but timestamps have extremely (relatively speaking) limited range, -// so this should be fine -pub fn scalar_date(scalar: &Scalar) -> u64 { - let b = scalar.to_bytes(); - u64::from_le_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]]) -} - #[cfg(test)] mod tests { use super::*; diff --git a/common/nym_offline_compact_ecash/src/scheme/identify.rs b/common/nym_offline_compact_ecash/src/scheme/identify.rs index df6c9096f3..38489e28c9 100644 --- a/common/nym_offline_compact_ecash/src/scheme/identify.rs +++ b/common/nym_offline_compact_ecash/src/scheme/identify.rs @@ -54,7 +54,6 @@ pub fn identify( #[cfg(test)] mod tests { - use crate::scheme::expiration_date_signatures::date_scalar; use crate::scheme::identify::{identify, IdentifyResult}; use crate::scheme::keygen::{PublicKeyUser, SecretKeyAuth, SecretKeyUser}; use crate::setup::Parameters; @@ -165,12 +164,12 @@ mod tests { .unwrap(); assert!(payment1 - .spend_verify(&verification_key, &pay_info1, date_scalar(spend_date)) + .spend_verify(&verification_key, &pay_info1, spend_date) .is_ok()); let payment2 = payment1.clone(); assert!(payment2 - .spend_verify(&verification_key, &pay_info1, date_scalar(spend_date)) + .spend_verify(&verification_key, &pay_info1, spend_date) .is_ok()); let identify_result = identify(&payment1, &payment2, pay_info1, pay_info1); @@ -275,7 +274,7 @@ mod tests { .unwrap(); assert!(payment1 - .spend_verify(&verification_key, &pay_info1, date_scalar(spend_date)) + .spend_verify(&verification_key, &pay_info1, spend_date) .is_ok()); let pay_info2 = PayInfo { @@ -295,7 +294,7 @@ mod tests { .unwrap(); assert!(payment2 - .spend_verify(&verification_key, &pay_info2, date_scalar(spend_date)) + .spend_verify(&verification_key, &pay_info2, spend_date) .is_ok()); let identify_result = identify(&payment1, &payment2, pay_info1, pay_info2); @@ -411,7 +410,7 @@ mod tests { .unwrap(); assert!(payment1 - .spend_verify(&verification_key, &pay_info1, date_scalar(spend_date)) + .spend_verify(&verification_key, &pay_info1, spend_date) .is_ok()); // let's reverse the spending counter in the wallet to create a double spending payment @@ -435,7 +434,7 @@ mod tests { .unwrap(); assert!(payment2 - .spend_verify(&verification_key, &pay_info2, date_scalar(spend_date)) + .spend_verify(&verification_key, &pay_info2, spend_date) .is_ok()); let identify_result = identify(&payment1, &payment2, pay_info1, pay_info2); @@ -555,7 +554,7 @@ mod tests { .unwrap(); assert!(payment1 - .spend_verify(&verification_key, &pay_info1, date_scalar(spend_date)) + .spend_verify(&verification_key, &pay_info1, spend_date) .is_ok()); // let's reverse the spending counter in the wallet to create a double spending payment diff --git a/common/nym_offline_compact_ecash/src/scheme/keygen.rs b/common/nym_offline_compact_ecash/src/scheme/keygen.rs index 375d974e9c..ade891b01f 100644 --- a/common/nym_offline_compact_ecash/src/scheme/keygen.rs +++ b/common/nym_offline_compact_ecash/src/scheme/keygen.rs @@ -97,10 +97,6 @@ impl SecretKeyAuth { self.ys.len() } - pub(crate) fn get_y_by_idx(&self, i: usize) -> Option<&Scalar> { - self.ys.get(i) - } - pub fn verification_key(&self) -> VerificationKeyAuth { let params = ecash_group_parameters(); let g1 = params.gen1(); diff --git a/common/nym_offline_compact_ecash/src/scheme/mod.rs b/common/nym_offline_compact_ecash/src/scheme/mod.rs index 187b7cf1c3..050a9e7eb6 100644 --- a/common/nym_offline_compact_ecash/src/scheme/mod.rs +++ b/common/nym_offline_compact_ecash/src/scheme/mod.rs @@ -3,17 +3,18 @@ use crate::common_types::{Signature, SignerIndex}; use crate::error::{CompactEcashError, Result}; +use crate::helpers::{date_scalar, type_scalar}; use crate::proofs::proof_spend::{SpendInstance, SpendProof, SpendWitness}; use crate::scheme::coin_indices_signatures::CoinIndexSignature; -use crate::scheme::expiration_date_signatures::{date_scalar, find_index, ExpirationDateSignature}; +use crate::scheme::expiration_date_signatures::{find_index, ExpirationDateSignature}; use crate::scheme::keygen::{SecretKeyUser, VerificationKeyAuth}; use crate::scheme::setup::{GroupParameters, Parameters}; use crate::traits::Bytable; use crate::utils::{ batch_verify_signatures, check_bilinear_pairing, hash_to_scalar, try_deserialize_scalar, }; -use crate::Base58; use crate::{constants, ecash_group_parameters}; +use crate::{Base58, EncodedDate, EncodedTicketType}; use bls12_381::{G1Projective, G2Prepared, G2Projective, Scalar}; use group::Curve; use serde::{Deserialize, Deserializer, Serialize, Serializer}; @@ -228,7 +229,7 @@ impl Wallet { spend_value: u64, valid_dates_signatures: &[ExpirationDateSignature], coin_indices_signatures: &[CoinIndexSignature], - spend_date_timestamp: u64, + spend_date_timestamp: EncodedDate, ) -> Result { self.check_remaining_allowance(params, spend_value)?; @@ -269,8 +270,8 @@ pub struct WalletSignatures { #[zeroize(skip)] sig: Signature, v: Scalar, - expiration_date_timestamp: u64, - t_type: u64, + expiration_date_timestamp: EncodedDate, + t_type: EncodedTicketType, } impl WalletSignatures { @@ -314,8 +315,8 @@ pub fn compute_pay_info_hash(pay_info: &PayInfo, k: u64) -> Scalar { } impl WalletSignatures { - // signature size (96) + secret size (32) + expiration size (8) + t_type (8) - pub const SERIALISED_SIZE: usize = 144; + // signature size (96) + secret size (32) + expiration size (4) + t_type (1) + pub const SERIALISED_SIZE: usize = 133; pub fn signature(&self) -> &Signature { &self.sig @@ -335,8 +336,8 @@ impl WalletSignatures { let mut bytes = [0u8; Self::SERIALISED_SIZE]; bytes[0..96].copy_from_slice(&self.sig.to_bytes()); bytes[96..128].copy_from_slice(&self.v.to_bytes()); - bytes[128..136].copy_from_slice(&self.expiration_date_timestamp.to_be_bytes()); - bytes[136..144].copy_from_slice(&self.t_type.to_be_bytes()); + bytes[128..132].copy_from_slice(&self.expiration_date_timestamp.to_be_bytes()); + bytes[132] = self.t_type; bytes } @@ -356,15 +357,12 @@ impl WalletSignatures { let v_bytes: &[u8; 32] = &bytes[96..128].try_into().unwrap(); #[allow(clippy::unwrap_used)] - let expiration_date_bytes = bytes[128..136].try_into().unwrap(); - - #[allow(clippy::unwrap_used)] - let t_type_bytes = bytes[136..].try_into().unwrap(); + let expiration_date_bytes = bytes[128..132].try_into().unwrap(); let sig = Signature::try_from(sig_bytes.as_slice())?; let v = Scalar::from_bytes(v_bytes).unwrap(); - let expiration_date_timestamp = u64::from_be_bytes(expiration_date_bytes); - let t_type = u64::from_be_bytes(t_type_bytes); + let expiration_date_timestamp = EncodedDate::from_be_bytes(expiration_date_bytes); + let t_type = bytes[132]; Ok(WalletSignatures { sig, @@ -401,7 +399,7 @@ impl WalletSignatures { spend_value: u64, valid_dates_signatures: &[BE], coin_indices_signatures: &[BI], - spend_date_timestamp: u64, + spend_date_timestamp: EncodedDate, ) -> Result where BI: Borrow, @@ -596,7 +594,7 @@ fn pseudorandom_f_g_v(params: &GroupParameters, v: &Scalar, l: u64) -> Result, pub spend_value: u64, pub cc: G1Projective, - pub t_type: u64, + pub t_type: EncodedTicketType, pub zk_proof: SpendProof, } @@ -720,7 +718,7 @@ impl Payment { return Err(CompactEcashError::SpendSignaturesValidity); } - let kappa_type = self.kappa + verification_key.beta_g2[3] * Scalar::from(self.t_type); + let kappa_type = self.kappa + verification_key.beta_g2[3] * type_scalar(self.t_type); if !check_bilinear_pairing( &self.sig.h.to_affine(), &G2Prepared::from(kappa_type.to_affine()), @@ -950,7 +948,7 @@ impl Payment { &self, verification_key: &VerificationKeyAuth, pay_info: &PayInfo, - spend_date: Scalar, + spend_date: EncodedDate, ) -> Result<()> { // check if all serial numbers are different self.no_duplicate_serial_numbers()?; @@ -959,7 +957,7 @@ impl Payment { // Verify whether the payment signature and kappa are correct self.check_signature_validity(verification_key)?; // Verify whether the expiration date signature and kappa_e are correct - self.check_exp_signature_validity(verification_key, spend_date)?; + self.check_exp_signature_validity(verification_key, date_scalar(spend_date))?; // Verify whether the coin indices signatures and kappa_k are correct self.batch_check_coin_index_signatures(verification_key)?; diff --git a/common/nym_offline_compact_ecash/src/scheme/withdrawal.rs b/common/nym_offline_compact_ecash/src/scheme/withdrawal.rs index 12bb32e767..082f969508 100644 --- a/common/nym_offline_compact_ecash/src/scheme/withdrawal.rs +++ b/common/nym_offline_compact_ecash/src/scheme/withdrawal.rs @@ -3,6 +3,7 @@ use crate::common_types::{BlindedSignature, Signature, SignerIndex}; use crate::error::{CompactEcashError, Result}; +use crate::helpers::{date_scalar, type_scalar}; use crate::proofs::proof_withdrawal::{ WithdrawalReqInstance, WithdrawalReqProof, WithdrawalReqWitness, }; @@ -10,7 +11,7 @@ use crate::scheme::keygen::{PublicKeyUser, SecretKeyAuth, SecretKeyUser, Verific use crate::scheme::setup::GroupParameters; use crate::scheme::PartialWallet; use crate::utils::{check_bilinear_pairing, hash_g1}; -use crate::{constants, ecash_group_parameters, Attribute}; +use crate::{constants, ecash_group_parameters, Attribute, EncodedDate, EncodedTicketType}; use bls12_381::{multi_miller_loop, G1Projective, G2Prepared, G2Projective, Scalar}; use group::{Curve, Group, GroupEncoding}; use serde::{Deserialize, Serialize}; @@ -141,28 +142,25 @@ fn compute_private_attribute_commitments( /// openings for private attributes, `v`, and the expiration date. pub fn withdrawal_request( sk_user: &SecretKeyUser, - expiration_date: u64, - t_type: u64, + expiration_date: EncodedDate, + t_type: EncodedTicketType, ) -> Result<(WithdrawalRequest, RequestInfo)> { let params = ecash_group_parameters(); // Generate random and unique wallet secret let v = params.random_scalar(); let joined_commitment_opening = params.random_scalar(); + + let gamma = params.gammas(); + let expiration_date = date_scalar(expiration_date); + let t_type = type_scalar(t_type); + // Compute joined commitment for all attributes (public and private) - //SAFETY: params is static with length 3 - #[allow(clippy::unwrap_used)] - let joined_commitment: G1Projective = params.gen1() * joined_commitment_opening - + params.gamma_idx(0).unwrap() * sk_user.sk - + params.gamma_idx(1).unwrap() * v; + let joined_commitment = + params.gen1() * joined_commitment_opening + gamma[0] * sk_user.sk + gamma[1] * v; // Compute commitment hash h - #[allow(clippy::unwrap_used)] - let joined_commitment_hash = hash_g1( - (joined_commitment - + params.gamma_idx(2).unwrap() * Scalar::from(expiration_date) - + params.gamma_idx(3).unwrap() * Scalar::from(t_type)) - .to_bytes(), - ); + let joined_commitment_hash = + hash_g1((joined_commitment + gamma[2] * expiration_date + gamma[3] * t_type).to_bytes()); // Compute Pedersen commitments for private attributes (wallet secret and user's secret) let private_attributes = vec![sk_user.sk, v]; @@ -199,8 +197,8 @@ pub fn withdrawal_request( joined_commitment_opening, private_attributes_openings: private_attributes_openings.clone(), wallet_secret: v, - expiration_date: Scalar::from(expiration_date), - t_type: Scalar::from(t_type), + expiration_date, + t_type, }, )) } @@ -222,18 +220,17 @@ pub fn withdrawal_request( pub fn request_verify( req: &WithdrawalRequest, pk_user: PublicKeyUser, - expiration_date: u64, - t_type: u64, + expiration_date: EncodedDate, + t_type: EncodedTicketType, ) -> Result<()> { let params = ecash_group_parameters(); - // Verify the joined commitment hash - //SAFETY: params is static with length 3 - #[allow(clippy::unwrap_used)] + + let gamma = params.gammas(); + let expiration_date = date_scalar(expiration_date); + let t_type = type_scalar(t_type); + let expected_commitment_hash = hash_g1( - (req.joined_commitment - + params.gamma_idx(2).unwrap() * Scalar::from(expiration_date) - + params.gamma_idx(3).unwrap() * Scalar::from(t_type)) - .to_bytes(), + (req.joined_commitment + gamma[2] * expiration_date + gamma[3] * t_type).to_bytes(), ); if req.joined_commitment_hash != expected_commitment_hash { return Err(CompactEcashError::WithdrawalRequestVerification); @@ -270,13 +267,10 @@ pub fn request_verify( /// authentication secret key index is out of bounds. fn sign_expiration_date( joined_commitment_hash: &G1Projective, - expiration_date: u64, + expiration_date: EncodedDate, sk_auth: &SecretKeyAuth, ) -> G1Projective { - //SAFETY : this fn assumes a long enough key - #[allow(clippy::unwrap_used)] - let yi = sk_auth.get_y_by_idx(2).unwrap(); - joined_commitment_hash * (yi * Scalar::from(expiration_date)) + joined_commitment_hash * (sk_auth.ys[2] * date_scalar(expiration_date)) } /// Signs a transaction type using a joined commitment hash and a secret key. @@ -296,13 +290,10 @@ fn sign_expiration_date( /// The resulting G1Projective point representing the signed ticket type. fn sign_t_type( joined_commitment_hash: &G1Projective, - t_type: u64, + t_type: EncodedTicketType, sk_auth: &SecretKeyAuth, ) -> G1Projective { - //SAFETY : this fn assumes a long enough key - #[allow(clippy::unwrap_used)] - let yi = sk_auth.get_y_by_idx(3).unwrap(); - joined_commitment_hash * (yi * Scalar::from(t_type)) + joined_commitment_hash * (sk_auth.ys[3] * type_scalar(t_type)) } /// Issues a blinded signature for a withdrawal request, after verifying its integrity. @@ -327,8 +318,8 @@ pub fn issue( sk_auth: &SecretKeyAuth, pk_user: PublicKeyUser, withdrawal_req: &WithdrawalRequest, - expiration_date: u64, - t_type: u64, + expiration_date: EncodedDate, + t_type: EncodedTicketType, ) -> Result { // Verify the withdrawal request request_verify(withdrawal_req, pk_user, expiration_date, t_type)?; diff --git a/common/nym_offline_compact_ecash/src/tests/e2e.rs b/common/nym_offline_compact_ecash/src/tests/e2e.rs index 24c74c813d..6bed36fb30 100644 --- a/common/nym_offline_compact_ecash/src/tests/e2e.rs +++ b/common/nym_offline_compact_ecash/src/tests/e2e.rs @@ -5,7 +5,6 @@ mod tests { use crate::error::Result; use crate::scheme::aggregation::{aggregate_verification_keys, aggregate_wallets}; - use crate::scheme::expiration_date_signatures::date_scalar; use crate::scheme::keygen::{ generate_keypair_user, ttp_keygen, SecretKeyAuth, VerificationKeyAuth, }; @@ -125,7 +124,7 @@ mod tests { )?; assert!(payment - .spend_verify(&verification_key, &pay_info, date_scalar(spend_date)) + .spend_verify(&verification_key, &pay_info, spend_date) .is_ok()); let payment_bytes = payment.to_bytes(); diff --git a/common/nym_offline_compact_ecash/src/tests/helpers.rs b/common/nym_offline_compact_ecash/src/tests/helpers.rs index 664b4c421e..5533dc0f48 100644 --- a/common/nym_offline_compact_ecash/src/tests/helpers.rs +++ b/common/nym_offline_compact_ecash/src/tests/helpers.rs @@ -15,12 +15,13 @@ use crate::scheme::Payment; use crate::setup::Parameters; use crate::{ aggregate_verification_keys, aggregate_wallets, constants, generate_keypair_user, issue, - issue_verify, withdrawal_request, PartialWallet, PayInfo, VerificationKeyAuth, + issue_verify, withdrawal_request, EncodedDate, EncodedTicketType, PartialWallet, PayInfo, + VerificationKeyAuth, }; use itertools::izip; pub fn generate_expiration_date_signatures( - expiration_date: u64, + expiration_date: EncodedDate, secret_keys_authorities: &[&SecretKeyAuth], verification_keys_auth: &[VerificationKeyAuth], verification_key: &VerificationKeyAuth, @@ -82,8 +83,8 @@ pub fn generate_coin_indices_signatures( pub fn payment_from_keys_and_expiration_date( ecash_keypairs: &Vec, indices: &[SignerIndex], - expiration_date: u64, - t_type: u64, + expiration_date: EncodedDate, + t_type: EncodedTicketType, ) -> Result<(Payment, PayInfo)> { let total_coins = 32; let params = Parameters::new(total_coins); diff --git a/common/nym_offline_compact_ecash/src/utils.rs b/common/nym_offline_compact_ecash/src/utils.rs index e182069017..57a648fff2 100644 --- a/common/nym_offline_compact_ecash/src/utils.rs +++ b/common/nym_offline_compact_ecash/src/utils.rs @@ -402,8 +402,3 @@ mod tests { assert_ne!(hash_to_scalar(msg1), hash_to_scalar(msg2)); } } - -pub fn scalar_type(scalar: &Scalar) -> u64 { - let b = scalar.to_bytes(); - u64::from_le_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]]) -}