From 802449d8af9dd01eea28e386c92e9faceace347b Mon Sep 17 00:00:00 2001 From: aniampio Date: Fri, 12 Nov 2021 11:04:19 +0000 Subject: [PATCH] Add function to turn theta into bytes and from bytes --- common/nymcoconut/src/proofs/mod.rs | 51 ++++++++++++++++++++ common/nymcoconut/src/scheme/verification.rs | 39 +++++++++++++++ common/nymcoconut/src/tests/e2e_covid.rs | 11 +++-- 3 files changed, 98 insertions(+), 3 deletions(-) diff --git a/common/nymcoconut/src/proofs/mod.rs b/common/nymcoconut/src/proofs/mod.rs index 70c62384de..84fa6d59d9 100644 --- a/common/nymcoconut/src/proofs/mod.rs +++ b/common/nymcoconut/src/proofs/mod.rs @@ -477,6 +477,57 @@ impl ProofKappa { challenge == self.challenge } + + pub(crate) fn to_bytes(&self) -> Vec { + let attributes_len = self.response_attributes.len() as u64; + let mut bytes = Vec::with_capacity(8 + (attributes_len + 2) as usize * 32); + + bytes.extend_from_slice(&self.challenge.to_bytes()); + bytes.extend_from_slice(&self.response_blinder.to_bytes()); + + bytes.extend_from_slice(&attributes_len.to_le_bytes()); + + for rm in &self.response_attributes { + bytes.extend_from_slice(&rm.to_bytes()); + } + + bytes + } + + pub(crate) fn from_bytes(bytes: &[u8]) -> Result { + // at the very minimum there must be a single attribute being proven + if bytes.len() < 32 * 2 + 8 || (bytes.len() - 8) % 32 != 0 { + return Err( + CoconutError::Deserialization( + "tried to deserialize proof of ciphertexts and commitment with bytes of invalid length".to_string()) + ); + } + + let challenge_bytes = bytes[..32].try_into().unwrap(); + let challenge = try_deserialize_scalar( + &challenge_bytes, + CoconutError::Deserialization("Failed to deserialize challenge".to_string()), + )?; + + let blinder_bytes = bytes[32..64].try_into().unwrap(); + let response_blinder = try_deserialize_scalar( + &blinder_bytes, + CoconutError::Deserialization("failed to deserialize the blinder".to_string()), + )?; + + let rm_len = u64::from_le_bytes(bytes[64..64 + 8].try_into().unwrap()); + let response_attributes = try_deserialize_scalar_vec( + rm_len, + &bytes[64 + 8..], + CoconutError::Deserialization("Failed to deserialize attributes response".to_string()), + )?; + + Ok(ProofKappa { + challenge, + response_attributes, + response_blinder, + }) + } } #[derive(Debug)] diff --git a/common/nymcoconut/src/scheme/verification.rs b/common/nymcoconut/src/scheme/verification.rs index f391b529be..5563f96282 100644 --- a/common/nymcoconut/src/scheme/verification.rs +++ b/common/nymcoconut/src/scheme/verification.rs @@ -58,6 +58,45 @@ impl ThetaCovid { timestamp, ) } + + // kappa || credential || proof + pub fn to_bytes(&self) -> Vec { + let blinded_message_bytes = self.blinded_message.to_affine().to_compressed(); + let credential_bytes = self.credential.to_bytes(); + let proof_bytes = self.pi_v.to_bytes(); + + let mut bytes = Vec::with_capacity(192 + proof_bytes.len()); + bytes.extend_from_slice(&blinded_message_bytes); + bytes.extend_from_slice(&credential_bytes); + bytes.extend_from_slice(&proof_bytes); + + bytes + } + + pub fn from_bytes(bytes: &[u8]) -> Result { + if bytes.len() < 192 { + return Err( + CoconutError::Deserialization( + format!("Tried to deserialize theta with insufficient number of bytes, expected >= 192, got {}", bytes.len()), + )); + } + + let blinded_message_bytes = bytes[..96].try_into().unwrap(); + let blinded_message = try_deserialize_g2_projective( + &blinded_message_bytes, + CoconutError::Deserialization("failed to deserialize kappa".to_string()), + )?; + + let credential = Signature::try_from(&bytes[96..192])?; + + let pi_v = ProofKappa::from_bytes(&bytes[192..])?; + + Ok(ThetaCovid { + blinded_message, + credential, + pi_v, + }) + } } #[derive(Debug)] diff --git a/common/nymcoconut/src/tests/e2e_covid.rs b/common/nymcoconut/src/tests/e2e_covid.rs index 22a6d7bf1e..d6f5e6d9d5 100644 --- a/common/nymcoconut/src/tests/e2e_covid.rs +++ b/common/nymcoconut/src/tests/e2e_covid.rs @@ -1,4 +1,4 @@ -use crate::scheme::verification::{prove_covid_credential, verify_covid_credential}; +use crate::scheme::verification::{prove_covid_credential, verify_covid_credential, ThetaCovid}; use crate::{ aggregate_signature_shares, aggregate_verification_keys, blind_sign, elgamal_keygen, hash_to_scalar, prepare_blind_sign, setup, ttp_keygen, CoconutError, Signature, SignatureShare, @@ -7,7 +7,7 @@ use crate::{ #[test] fn main() -> Result<(), CoconutError> { - let params = setup(10)?; + let params = setup(15)?; // validators keys let coconut_keypairs = ttp_keygen(¶ms, 2, 3)?; @@ -133,12 +133,17 @@ fn main() -> Result<(), CoconutError> { ×tamp, )?; + let theta_covid_bytes = theta_covid.to_bytes(); + println!("Length of theta in bytes: {:?}", theta_covid_bytes.len()); + + let theta_covid_from_bytes = ThetaCovid::from_bytes(&*theta_covid_bytes).unwrap(); + // Verify covid credentials let disclosed_attributes = vec![is_vaccinated, is_over_18, is_over_21]; assert!(verify_covid_credential( ¶ms, &verification_key, - &theta_covid, + &theta_covid_from_bytes, disclosed_attributes.as_ref(), &verifier_id, ×tamp,