diff --git a/rust/bridge/shared/src/zkgroup.rs b/rust/bridge/shared/src/zkgroup.rs index 76699808c..2e1110720 100644 --- a/rust/bridge/shared/src/zkgroup.rs +++ b/rust/bridge/shared/src/zkgroup.rs @@ -258,7 +258,7 @@ fn ServerPublicParams_CreateExpiringProfileKeyCredentialPresentationDeterministi *randomness, group_secret_params.into_inner(), profile_key_credential.into_inner(), - ), + ) as &zkgroup::profiles::ExpiringProfileKeyCredentialPresentation, ) } diff --git a/rust/zkgroup/benches/zkgroup_benchmarks.rs b/rust/zkgroup/benches/zkgroup_benchmarks.rs index 537e6b69d..a36489045 100644 --- a/rust/zkgroup/benches/zkgroup_benchmarks.rs +++ b/rust/zkgroup/benches/zkgroup_benchmarks.rs @@ -217,11 +217,12 @@ pub fn benchmark_integration_profile(c: &mut Criterion) { // Create presentation let randomness = zkgroup::TEST_ARRAY_32_5; - let presentation = server_public_params.create_expiring_profile_key_credential_presentation( - randomness, - group_secret_params, - profile_key_credential, - ); + let presentation: zkgroup::profiles::ExpiringProfileKeyCredentialPresentation = + server_public_params.create_expiring_profile_key_credential_presentation( + randomness, + group_secret_params, + profile_key_credential, + ); c.bench_function("create_expiring_profile_key_credential_presentation", |b| { b.iter(|| { @@ -229,7 +230,7 @@ pub fn benchmark_integration_profile(c: &mut Criterion) { randomness, group_secret_params, profile_key_credential, - ) + ) as zkgroup::profiles::ExpiringProfileKeyCredentialPresentation }) }); diff --git a/rust/zkgroup/src/api/profiles/profile_key_credential_presentation.rs b/rust/zkgroup/src/api/profiles/profile_key_credential_presentation.rs index a9f492586..263af53d3 100644 --- a/rust/zkgroup/src/api/profiles/profile_key_credential_presentation.rs +++ b/rust/zkgroup/src/api/profiles/profile_key_credential_presentation.rs @@ -62,15 +62,19 @@ impl ProfileKeyCredentialPresentationV2 { } #[derive(Clone, Serialize, Deserialize, PartialDefault)] -pub struct ExpiringProfileKeyCredentialPresentation { - pub(crate) version: VersionByte, +pub struct ExpiringProfileKeyCredentialPresentation { + pub(crate) version: VersionByte, pub(crate) proof: crypto::proofs::ExpiringProfileKeyCredentialPresentationProof, pub(crate) uid_enc_ciphertext: crypto::uid_encryption::Ciphertext, pub(crate) profile_key_enc_ciphertext: crypto::profile_key_encryption::Ciphertext, pub(crate) credential_expiration_time: Timestamp, } -impl ExpiringProfileKeyCredentialPresentation { +// The only thing that changes in V2 is the proof contents, so we can reuse the same structure. +pub type ExpiringProfileKeyCredentialPresentationV2 = + ExpiringProfileKeyCredentialPresentation; + +impl ExpiringProfileKeyCredentialPresentation { pub fn get_uuid_ciphertext(&self) -> api::groups::UuidCiphertext { api::groups::UuidCiphertext { reserved: Default::default(), @@ -95,6 +99,7 @@ pub enum AnyProfileKeyCredentialPresentation { V1(ProfileKeyCredentialPresentationV1), V2(ProfileKeyCredentialPresentationV2), V3(ExpiringProfileKeyCredentialPresentation), + V4(ExpiringProfileKeyCredentialPresentationV2), } impl AnyProfileKeyCredentialPresentation { @@ -112,6 +117,10 @@ impl AnyProfileKeyCredentialPresentation { crate::deserialize::(presentation_bytes) .map(AnyProfileKeyCredentialPresentation::V3) } + PRESENTATION_VERSION_4 => { + crate::deserialize::(presentation_bytes) + .map(AnyProfileKeyCredentialPresentation::V4) + } _ => Err(ZkGroupDeserializationFailure::new::()), } } @@ -127,6 +136,9 @@ impl AnyProfileKeyCredentialPresentation { AnyProfileKeyCredentialPresentation::V3(presentation) => { presentation.get_uuid_ciphertext() } + AnyProfileKeyCredentialPresentation::V4(presentation) => { + presentation.get_uuid_ciphertext() + } } } @@ -141,6 +153,9 @@ impl AnyProfileKeyCredentialPresentation { AnyProfileKeyCredentialPresentation::V3(presentation) => { presentation.get_profile_key_ciphertext() } + AnyProfileKeyCredentialPresentation::V4(presentation) => { + presentation.get_profile_key_ciphertext() + } } } @@ -175,6 +190,9 @@ impl Serialize for AnyProfileKeyCredentialPresentation { AnyProfileKeyCredentialPresentation::V3(presentation) => { presentation.serialize(serializer) } + AnyProfileKeyCredentialPresentation::V4(presentation) => { + presentation.serialize(serializer) + } } } } diff --git a/rust/zkgroup/src/api/server_params.rs b/rust/zkgroup/src/api/server_params.rs index 933b053b7..3c748318b 100644 --- a/rust/zkgroup/src/api/server_params.rs +++ b/rust/zkgroup/src/api/server_params.rs @@ -209,13 +209,19 @@ impl ServerSecretParams { presentation, current_time, ), + api::profiles::AnyProfileKeyCredentialPresentation::V4(presentation) => self + .verify_expiring_profile_key_credential_presentation( + group_public_params, + presentation, + current_time, + ), } } - pub fn verify_expiring_profile_key_credential_presentation( + pub fn verify_expiring_profile_key_credential_presentation( &self, group_public_params: api::groups::GroupPublicParams, - presentation: &api::profiles::ExpiringProfileKeyCredentialPresentation, + presentation: &api::profiles::ExpiringProfileKeyCredentialPresentation, current_time: Timestamp, ) -> Result<(), ZkGroupVerificationFailure> { let credentials_key_pair = self.expiring_profile_key_credentials_key_pair; @@ -229,6 +235,7 @@ impl ServerSecretParams { presentation.profile_key_enc_ciphertext, profile_key_enc_public_key, presentation.credential_expiration_time, + V >= PRESENTATION_VERSION_4, )?; if presentation.credential_expiration_time <= current_time { @@ -436,12 +443,12 @@ impl ServerPublicParams { }) } - pub fn create_expiring_profile_key_credential_presentation( + pub fn create_expiring_profile_key_credential_presentation( &self, randomness: RandomnessBytes, group_secret_params: api::groups::GroupSecretParams, expiring_profile_key_credential: api::profiles::ExpiringProfileKeyCredential, - ) -> api::profiles::ExpiringProfileKeyCredentialPresentation { + ) -> api::profiles::ExpiringProfileKeyCredentialPresentation { let mut sho = Sho::new( b"Signal_ZKGroup_20220508_Random_ServerPublicParams_CreateExpiringProfileKeyCredentialPresentation", &randomness, @@ -465,6 +472,7 @@ impl ServerPublicParams { profile_key_ciphertext.ciphertext, expiring_profile_key_credential.aci_bytes, expiring_profile_key_credential.profile_key_bytes, + V >= PRESENTATION_VERSION_4, &mut sho, ); diff --git a/rust/zkgroup/src/crypto/proofs.rs b/rust/zkgroup/src/crypto/proofs.rs index e7051e6b3..fbb2baea8 100644 --- a/rust/zkgroup/src/crypto/proofs.rs +++ b/rust/zkgroup/src/crypto/proofs.rs @@ -448,7 +448,7 @@ impl ProfileKeyCredentialPresentationProofV1 { } impl ExpiringProfileKeyCredentialPresentationProof { - pub fn get_poksho_statement() -> poksho::Statement { + pub fn get_poksho_statement(full_checking: bool) -> poksho::Statement { let mut st = poksho::Statement::new(); st.add("Z", &[("z", "I")]); st.add("C_x1", &[("t", "C_x0"), ("z0", "G_x0"), ("z", "G_x1")]); @@ -467,6 +467,9 @@ impl ExpiringProfileKeyCredentialPresentationProof { st.add("E_B1", &[("b1", "C_y3"), ("z2", "G_y3")]); st.add("0", &[("z1", "I"), ("a1", "Z")]); st.add("0", &[("z2", "I"), ("b1", "Z")]); + if full_checking { + st.add("C_y5", &[("z", "G_y5")]); + } st } @@ -480,6 +483,7 @@ impl ExpiringProfileKeyCredentialPresentationProof { profile_key_ciphertext: profile_key_encryption::Ciphertext, aci_bytes: UidBytes, profile_key_bytes: ProfileKeyBytes, + full_checking: bool, sho: &mut Sho, ) -> Self { let credentials_system = credentials::SystemParams::get_hardcoded(); @@ -557,7 +561,12 @@ impl ExpiringProfileKeyCredentialPresentationProof { point_args.add("G_y3", credentials_system.G_y[3]); point_args.add("0", RistrettoPoint::identity()); - let poksho_proof = Self::get_poksho_statement() + if full_checking { + point_args.add("C_y5", C_y5); + point_args.add("G_y5", credentials_system.G_y[5]); + } + + let poksho_proof = Self::get_poksho_statement(full_checking) .prove( &scalar_args, &point_args, @@ -587,6 +596,7 @@ impl ExpiringProfileKeyCredentialPresentationProof { profile_key_ciphertext: profile_key_encryption::Ciphertext, profile_key_enc_public_key: profile_key_encryption::PublicKey, credential_expiration_time: Timestamp, + full_checking: bool, ) -> Result<(), ZkGroupVerificationFailure> { let uid_enc_system = uid_encryption::SystemParams::get_hardcoded(); let profile_key_enc_system = profile_key_encryption::SystemParams::get_hardcoded(); @@ -604,8 +614,8 @@ impl ExpiringProfileKeyCredentialPresentationProof { poksho_proof, } = self; - let (C_x0, C_x1, C_y1, C_y2, C_y3, C_y4, C_V) = - (*C_x0, *C_x1, *C_y1, *C_y2, *C_y3, *C_y4, *C_V); + let (C_x0, C_x1, C_y1, C_y2, C_y3, C_y4, C_y5, C_V) = + (*C_x0, *C_x1, *C_y1, *C_y2, *C_y3, *C_y4, *C_y5, *C_V); let credentials::KeyPair { W, @@ -661,7 +671,13 @@ impl ExpiringProfileKeyCredentialPresentationProof { point_args.add("G_y3", credentials_system.G_y[3]); point_args.add("0", RistrettoPoint::identity()); - match Self::get_poksho_statement().verify_proof(poksho_proof, &point_args, &[]) { + if full_checking { + point_args.add("C_y5", C_y5); + point_args.add("G_y5", credentials_system.G_y[5]); + } + + match Self::get_poksho_statement(full_checking).verify_proof(poksho_proof, &point_args, &[]) + { Err(_) => Err(ZkGroupVerificationFailure), Ok(_) => Ok(()), } diff --git a/rust/zkgroup/tests/integration_tests.rs b/rust/zkgroup/tests/integration_tests.rs index 166375f64..41d2f4637 100644 --- a/rust/zkgroup/tests/integration_tests.rs +++ b/rust/zkgroup/tests/integration_tests.rs @@ -52,6 +52,10 @@ const PROFILE_KEY_CREDENTIAL_PRESENTATION_V3_RESULT: &[u8] = &hex!( "02fc58a4f2c9bd736238abfc28890c8b2363d084bee430692f05ee559bd37dea3378949e72b271fe0d815b6d908035106cd670b45892df40780c62c37fae106c41be38371fe042a4d4f697db112972d79204b3d48d1253d3231c22926e107f661d40897cb7fdb4777c1680a57008655db71efaac1f69cd9ddf8cda33b226662d7ba443416281508fcdbb026d63f83168470a83e12803a6d2ee2c907343f2f6b063fe6bf0f17a032fabe61e77e904dfe7d3042125728c1984c86a094a0e3991ba554c1ebf604c14a8b13c384c5c01909656c114b24f9d3615d3b14bde7ce9cf126aca3e073e804b2016f7c5affa158a3a68ed9024c6880ecb441a346e7e91aedd6240010000000000002e70f27fb3f4c58cb40dfe58ce1d122312969426abb0bbb820bfbc5ff61d400a419d5ddb7c30c546427273d4fca3096ee4dd2fd03ccbbd26304ffcfe54fef50db8538177ebc61117a222253b4d4189f795abbde3b3d8a0a72d97b7750e0394010a01b474c3e942ef1ee807e17421689c6ca793c4f30b09c989b8a9679aee130eb034f64a34dbcaf12616970d2c8d58ca715bf5c4d42475fa6a1b82ba31574e072506652253e86cd783e30e1c06d2e861ba864a5373759472b31c5b26a8e46d062b8b5da2ec0a3ba499648e80f307728b7815aa60d167a0a9d01c2d2cbfb0a60ddc9dfc5343564b5f021fd1adba6d2a389e7c331bfffeed2a5d1887634323840574e49255a62d9e00ffc21f56afbb12fb9660e185f979223ec714c01e403a3a0a3276d0ef78182f12c092f5237befe3f0afea7693370788f854ec697e44c9bd02765de9df4cfa5487f360e29e99343e91811baec331c4680985e608ca5d408e21725c6aa1b61d5a8b48d75f4aaa9a3cbe88d3e0f1a54319081f77c72c8f52547448c03ab4afbf6b8fb0e126c037a0ad4094600dd0e0634d76f88c21087f3cfb485a89bc1e3abc4c95041d1d170eccf02933ec5393d4be1dc573f83c33d3b9a7468069160000000000" ); +const PROFILE_KEY_CREDENTIAL_PRESENTATION_V4_RESULT: &[u8] = &hex!( + "03fc58a4f2c9bd736238abfc28890c8b2363d084bee430692f05ee559bd37dea3378949e72b271fe0d815b6d908035106cd670b45892df40780c62c37fae106c41be38371fe042a4d4f697db112972d79204b3d48d1253d3231c22926e107f661d40897cb7fdb4777c1680a57008655db71efaac1f69cd9ddf8cda33b226662d7ba443416281508fcdbb026d63f83168470a83e12803a6d2ee2c907343f2f6b063fe6bf0f17a032fabe61e77e904dfe7d3042125728c1984c86a094a0e3991ba554c1ebf604c14a8b13c384c5c01909656c114b24f9d3615d3b14bde7ce9cf126aca3e073e804b2016f7c5affa158a3a68ed9024c6880ecb441a346e7e91aedd6240010000000000006b4403e6adc3322acd34eea13fcc1ae971aab14386fa9b4d85ba0490dfca2f0d21de78e92719ad40a6a49d7549551a4bc6f7e4e4f0da81e9d6cc054da9529e053d1360b9d83e3ab9d3c8a9b7d3b07e2bab0979f3912c4bb41f621bf7685ee607fc147670196e009a9cd92b0fb525ca9b8e8fdf4c332732c02ccbcf57b5c19f001df37a5104d367f0f3f5cc0d9a2bd299e1f37872d7580b05596eadd5dec3e80366ab47357205c407bbcac49540a1fd69f36d308d0fdb72d0273f0c7a0d92220fe25daba5885a162bf238495463971c61b380084b7f79ad817d6f343e254722019da9ad32e72f2d864074023096cb8dd615b6fbbb47c6bef0926290a68403340e0a4dfb961e5b9002fc104e480823f12178cb91fafd51eb5dc9eb9fec4e6f7c0a130f31eb84cc70be9e5fd0bfb7d279590bdb49e7a4fe3b156a922fc73f78a50e765de9df4cfa5487f360e29e99343e91811baec331c4680985e608ca5d408e21725c6aa1b61d5a8b48d75f4aaa9a3cbe88d3e0f1a54319081f77c72c8f52547448c03ab4afbf6b8fb0e126c037a0ad4094600dd0e0634d76f88c21087f3cfb485a89bc1e3abc4c95041d1d170eccf02933ec5393d4be1dc573f83c33d3b9a7468069160000000000" +); + #[test] fn test_auth_credential_presentation_v1_is_rejected() { assert!( @@ -160,8 +164,11 @@ fn test_integration_auth_zkc() { auth_credential_bytes.copy_from_slice(&bincode::serialize(&auth_credential).unwrap()); } -#[test] -fn test_integration_expiring_profile() { +fn test_integration_expiring_profile() +where + zkgroup::profiles::AnyProfileKeyCredentialPresentation: + From>, +{ // SERVER let server_secret_params = zkgroup::ServerSecretParams::generate(zkgroup::TEST_ARRAY_32); let server_public_params = server_secret_params.get_public_params(); @@ -226,11 +233,12 @@ fn test_integration_expiring_profile() { // Create presentation let randomness = zkgroup::TEST_ARRAY_32_5; - let presentation = server_public_params.create_expiring_profile_key_credential_presentation( - randomness, - group_secret_params, - profile_key_credential, - ); + let presentation: zkgroup::profiles::ExpiringProfileKeyCredentialPresentation = + server_public_params.create_expiring_profile_key_credential_presentation( + randomness, + group_secret_params, + profile_key_credential, + ); assert_eq!(expiration, presentation.get_expiration_time()); let presentation_bytes = &bincode::serialize(&presentation).unwrap(); @@ -238,15 +246,14 @@ fn test_integration_expiring_profile() { presentation.into(); let presentation_any_bytes = &bincode::serialize(&presentation_any).unwrap(); - assert_hex_eq!( - PROFILE_KEY_CREDENTIAL_PRESENTATION_V3_RESULT[..], - presentation_bytes[..] - ); + let expected_hex = match V { + zkgroup::PRESENTATION_VERSION_3 => PROFILE_KEY_CREDENTIAL_PRESENTATION_V3_RESULT, + zkgroup::PRESENTATION_VERSION_4 => PROFILE_KEY_CREDENTIAL_PRESENTATION_V4_RESULT, + _ => panic!("unexpected ExpiringProfileKeyCredentialPresentation version {V}"), + }; - assert_hex_eq!( - PROFILE_KEY_CREDENTIAL_PRESENTATION_V3_RESULT[..], - presentation_any_bytes[..] - ); + assert_hex_eq!(expected_hex, &presentation_bytes[..]); + assert_hex_eq!(expected_hex, &presentation_any_bytes[..]); server_secret_params .verify_profile_key_credential_presentation( @@ -310,6 +317,16 @@ fn test_integration_expiring_profile() { profile_key_credential_response_bytes.copy_from_slice(&bincode::serialize(&response).unwrap()); } +#[test] +fn test_integration_expiring_profile_v1() { + test_integration_expiring_profile::<{ zkgroup::PRESENTATION_VERSION_3 }>(); +} + +#[test] +fn test_integration_expiring_profile_v2() { + test_integration_expiring_profile::<{ zkgroup::PRESENTATION_VERSION_4 }>(); +} + #[test] fn test_server_sigs() { let server_secret_params =