From 6e72433f997afde4243fcbaa08f91df73b4af85d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogdan-=C8=98tefan=20Neac=C5=9Fu?= Date: Tue, 28 Mar 2023 15:08:54 +0300 Subject: [PATCH] Feature/coconut hash (#3231) * Hash over public attributes too * Improve and fix api unit test * Rename hash function --- common/nymcoconut/src/proofs/mod.rs | 12 +++-- common/nymcoconut/src/scheme/issuance.rs | 14 ++++-- common/nymcoconut/src/scheme/mod.rs | 7 +-- nym-api/src/coconut/tests.rs | 59 +++++++----------------- 4 files changed, 35 insertions(+), 57 deletions(-) diff --git a/common/nymcoconut/src/proofs/mod.rs b/common/nymcoconut/src/proofs/mod.rs index 462f3845af..84c7211aa2 100644 --- a/common/nymcoconut/src/proofs/mod.rs +++ b/common/nymcoconut/src/proofs/mod.rs @@ -14,9 +14,10 @@ use itertools::izip; use sha2::Sha256; use crate::error::{CoconutError, Result}; +use crate::scheme::issuance::compute_hash; use crate::scheme::setup::Parameters; use crate::scheme::VerificationKey; -use crate::utils::{hash_g1, try_deserialize_scalar, try_deserialize_scalar_vec}; +use crate::utils::{try_deserialize_scalar, try_deserialize_scalar_vec}; use crate::Attribute; // as per the reference python implementation @@ -91,6 +92,7 @@ impl ProofCmCs { commitments: &[G1Projective], pedersen_commitments_openings: &[Scalar], private_attributes: &[Attribute], + public_attributes: &[Attribute], ) -> Self { // note: this is only called from `prepare_blind_sign` that already checks // whether private attributes are non-empty and whether we don't have too many @@ -104,7 +106,7 @@ impl ProofCmCs { let witness_attributes = params.n_random_scalars(private_attributes.len()); // recompute h - let h = hash_g1(commitment.to_bytes()); + let h = compute_hash(*commitment, public_attributes); let hs_bytes = params .gen_hs() .iter() @@ -186,7 +188,7 @@ impl ProofCmCs { } // recompute h - let h = hash_g1(commitment.to_bytes()); + let h = compute_hash(*commitment, public_attributes); let g1 = params.gen1(); let hs_bytes = params @@ -531,7 +533,7 @@ mod tests { let private_attributes = params.n_random_scalars(1); // 0 public 1 private - let pi_s = ProofCmCs::construct(¶ms, &cm, &r, &cms, &rs, &private_attributes); + let pi_s = ProofCmCs::construct(¶ms, &cm, &r, &cms, &rs, &private_attributes, &[]); let bytes = pi_s.to_bytes(); assert_eq!(ProofCmCs::from_bytes(&bytes).unwrap(), pi_s); @@ -547,7 +549,7 @@ mod tests { let private_attributes = params.n_random_scalars(2); // 0 public 2 privates - let pi_s = ProofCmCs::construct(¶ms, &cm, &r, &cms, &rs, &private_attributes); + let pi_s = ProofCmCs::construct(¶ms, &cm, &r, &cms, &rs, &private_attributes, &[]); let bytes = pi_s.to_bytes(); assert_eq!(ProofCmCs::from_bytes(&bytes).unwrap(), pi_s); diff --git a/common/nymcoconut/src/scheme/issuance.rs b/common/nymcoconut/src/scheme/issuance.rs index aa1970cb73..710fc41df9 100644 --- a/common/nymcoconut/src/scheme/issuance.rs +++ b/common/nymcoconut/src/scheme/issuance.rs @@ -201,8 +201,13 @@ pub fn compute_pedersen_commitments_for_private_attributes( (commitments_openings, pedersen_commitments) } -pub fn compute_commitment_hash(commitment: G1Projective) -> G1Projective { - hash_g1(commitment.to_bytes()) +pub fn compute_hash(commitment: G1Projective, public_attributes: &[Attribute]) -> G1Projective { + let mut buff = Vec::new(); + buff.extend_from_slice(commitment.to_bytes().as_ref()); + for attr in public_attributes { + buff.extend_from_slice(attr.to_bytes().as_ref()); + } + hash_g1(buff) } /// Builds cryptographic material required for blind sign. @@ -230,7 +235,7 @@ pub fn prepare_blind_sign( compute_attributes_commitment(params, private_attributes, public_attributes, hs); // Compute the challenge as the commitment hash - let commitment_hash = compute_commitment_hash(commitment); + let commitment_hash = compute_hash(commitment, public_attributes); let (pedersen_commitments_openings, pedersen_commitments) = compute_pedersen_commitments_for_private_attributes( @@ -246,6 +251,7 @@ pub fn prepare_blind_sign( &pedersen_commitments, &pedersen_commitments_openings, private_attributes, + public_attributes, ); Ok(( @@ -276,7 +282,7 @@ pub fn blind_sign( } // Verify the commitment hash - let h = hash_g1(blind_sign_request.commitment.to_bytes()); + let h = compute_hash(blind_sign_request.commitment, public_attributes); if !(h == blind_sign_request.commitment_hash) { return Err(CoconutError::Issuance( "Failed to verify the commitment hash".to_string(), diff --git a/common/nymcoconut/src/scheme/mod.rs b/common/nymcoconut/src/scheme/mod.rs index 343cb472fb..9e642716ca 100644 --- a/common/nymcoconut/src/scheme/mod.rs +++ b/common/nymcoconut/src/scheme/mod.rs @@ -237,14 +237,11 @@ impl SignatureShare { #[cfg(test)] mod tests { - use group::GroupEncoding; - use crate::hash_to_scalar; use crate::scheme::aggregation::{aggregate_signatures, aggregate_verification_keys}; - use crate::scheme::issuance::{blind_sign, prepare_blind_sign, sign}; + use crate::scheme::issuance::{blind_sign, compute_hash, prepare_blind_sign, sign}; use crate::scheme::keygen::{keygen, ttp_keygen}; use crate::scheme::verification::{prove_bandwidth_credential, verify, verify_credential}; - use crate::utils::hash_g1; use super::*; @@ -262,7 +259,7 @@ mod tests { let wrong_commitment_opening = params.random_scalar(); let wrong_commitment = params.gen1() * wrong_commitment_opening; - let fake_commitment_hash = hash_g1(wrong_commitment.to_bytes()); + let fake_commitment_hash = compute_hash(wrong_commitment, &[]); let wrong_commitments_openings = params.n_random_scalars(private_attributes.len()); assert!(sig1 diff --git a/nym-api/src/coconut/tests.rs b/nym-api/src/coconut/tests.rs index bfba43ad75..3ac36af6fc 100644 --- a/nym-api/src/coconut/tests.rs +++ b/nym-api/src/coconut/tests.rs @@ -23,9 +23,7 @@ use nym_credentials::coconut::params::{ use nym_crypto::shared_key::recompute_shared_key; use nym_crypto::symmetric::stream_cipher; use nymcoconut::tests::helpers::theta_from_keys_and_attributes; -use nymcoconut::{ - prepare_blind_sign, ttp_keygen, Base58, BlindSignRequest, BlindedSignature, Parameters, -}; +use nymcoconut::{prepare_blind_sign, ttp_keygen, Base58, BlindedSignature, Parameters}; use validator_client::nym_api::routes::{ API_VERSION, BANDWIDTH, COCONUT_BLIND_SIGN, COCONUT_ROUTES, COCONUT_VERIFY_BANDWIDTH_CREDENTIAL, }; @@ -729,21 +727,16 @@ async fn blind_sign_correct() { let params = Parameters::new(4).unwrap(); let mut rng = OsRng; + let identity_keypair = identity::KeyPair::new(&mut rng); + let encryption_keypair = encryption::KeyPair::new(&mut rng); let voucher = BandwidthVoucher::new( ¶ms, "1234".to_string(), VOUCHER_INFO.to_string(), tx_hash, - identity::PrivateKey::from_base58_string( - identity::KeyPair::new(&mut rng) - .private_key() - .to_base58_string(), - ) - .unwrap(), - encryption::PrivateKey::from_bytes( - &encryption::KeyPair::new(&mut rng).private_key().to_bytes(), - ) - .unwrap(), + identity::PrivateKey::from_base58_string(identity_keypair.private_key().to_base58_string()) + .unwrap(), + encryption::PrivateKey::from_bytes(&encryption_keypair.private_key().to_bytes()).unwrap(), ); let key_pair = ttp_keygen(¶ms, 1, 1).unwrap().remove(0); @@ -768,13 +761,17 @@ async fn blind_sign_correct() { }, Tag { key: DEPOSIT_IDENTITY_KEY.parse().unwrap(), - value: "64auwDkWan7R8yH1Mwe9dS4qXgrDBCUNDg3Q4KFnd2P5" + value: identity_keypair + .public_key() + .to_base58_string() .parse() .unwrap(), }, Tag { key: DEPOSIT_ENCRYPTION_KEY.parse().unwrap(), - value: "HxnTpWTkgigSTAysVKLE8pEiUULHdTT1BxFfzfJvQRi6" + value: encryption_keypair + .public_key() + .to_base58_string() .parse() .unwrap(), }, @@ -801,36 +798,12 @@ async fn blind_sign_correct() { .await .expect("valid rocket instance"); - // hard-coded values, that generate a correct signature - let blind_sign_req = BlindSignRequest::from_bytes(&[ - 176, 113, 19, 237, 218, 252, 113, 20, 225, 238, 59, 88, 217, 45, 233, 178, 65, 28, 242, 0, - 222, 48, 110, 216, 26, 111, 51, 235, 61, 74, 200, 15, 130, 245, 45, 170, 155, 190, 156, 77, - 180, 142, 29, 63, 15, 224, 150, 31, 139, 24, 65, 175, 143, 153, 11, 203, 33, 16, 152, 22, - 221, 203, 99, 233, 208, 142, 161, 194, 46, 227, 177, 96, 119, 30, 175, 69, 104, 14, 2, 191, - 26, 94, 30, 165, 15, 28, 40, 176, 1, 78, 253, 79, 20, 137, 102, 74, 2, 0, 0, 0, 0, 0, 0, 0, - 131, 133, 112, 115, 53, 98, 58, 166, 240, 70, 185, 210, 203, 12, 114, 66, 180, 38, 139, 12, - 187, 45, 250, 201, 68, 102, 159, 172, 218, 124, 151, 23, 172, 18, 216, 122, 246, 7, 185, - 76, 20, 167, 123, 122, 152, 241, 175, 226, 176, 8, 170, 70, 140, 252, 36, 130, 67, 204, - 111, 116, 107, 92, 200, 77, 252, 31, 138, 18, 10, 215, 165, 243, 95, 199, 193, 61, 200, - 187, 22, 198, 109, 213, 145, 71, 171, 132, 174, 68, 105, 248, 0, 115, 50, 55, 199, 84, 67, - 16, 125, 216, 250, 154, 115, 174, 9, 206, 44, 88, 63, 163, 124, 10, 239, 64, 158, 191, 27, - 169, 177, 194, 223, 142, 202, 206, 189, 122, 123, 91, 171, 15, 40, 192, 148, 75, 174, 24, - 116, 229, 127, 170, 110, 183, 151, 2, 118, 168, 22, 113, 87, 237, 91, 228, 249, 120, 114, - 255, 53, 175, 245, 39, 2, 0, 0, 0, 0, 0, 0, 0, 225, 45, 230, 25, 62, 202, 96, 166, 171, - 241, 206, 137, 254, 51, 154, 255, 122, 130, 107, 54, 5, 206, 207, 120, 193, 214, 64, 10, - 111, 195, 86, 55, 201, 36, 10, 18, 154, 158, 183, 87, 185, 59, 228, 89, 134, 193, 217, 188, - 64, 164, 249, 21, 248, 20, 207, 58, 31, 10, 19, 176, 246, 150, 45, 48, 2, 0, 0, 0, 0, 0, 0, - 0, 173, 60, 65, 209, 100, 114, 138, 186, 158, 150, 109, 230, 111, 86, 101, 72, 194, 237, - 173, 195, 139, 175, 238, 25, 169, 18, 188, 75, 77, 54, 111, 20, 115, 235, 195, 2, 123, 133, - 164, 81, 15, 45, 11, 84, 139, 38, 8, 224, 197, 181, 95, 147, 49, 77, 193, 207, 52, 141, - 195, 195, 66, 137, 17, 32, - ]) - .unwrap(); let request_body = BlindSignRequestBody::new( - &blind_sign_req, + voucher.blind_sign_request(), tx_hash.to_string(), - "gSFgpma5GAVMcsmZwKieqGNHNd3dPzcfa8eT2Qn2LoBccSeyiJdphREbNrkuh5XWxMe2hUsranaYzLro48L9Qhd" - .to_string(), + voucher + .sign(voucher.blind_sign_request()) + .to_base58_string(), &voucher.get_public_attributes(), voucher.get_public_attributes_plain(), 4,