Skip to content

Commit

Permalink
Merge branch 'main' into tristanvuong-configure-reporting-workflow-to…
Browse files Browse the repository at this point in the history
…-deploy-v2
  • Loading branch information
tristanvuong2021 authored Jan 25, 2024
2 parents e1793ff + 937086a commit f269719
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,8 @@ object Composition {
* Computes total DP delta parameter after applying ACDP composition with given target Epsilon
*
* @param acdpCharges The privacy ACDP charge(rho, theta) of queries.
* @param targetEpsilon The maximum total Epsilon.
* @param targetEpsilon The maximum total Epsilon specified from Privacy Budget Manager.
* Recommended value is below 10.
* @return totalDelta such that, under ACDP composition, the result is still (totalEpsilon,
* totalDelta)-DP.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ class InProcessEdpSimulator(
PrivacyBudgetManager(
PrivacyBucketFilter(TestPrivacyBucketMapper()),
InMemoryBackingStore(),
100.0f,
10.0f,
100.0f,
),
trustedCertificates = trustedCertificates,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,9 +171,12 @@ abstract class InProcessLifeOfAMeasurementIntegrationTest(
// TODO(@renjiez): Add Multi-round test given the same input to verify correctness.

companion object {
// Epsilon can vary from 0.0001 to 1.0, delta = 1e-15 is a realistic value.
// Set epsilon higher without exceeding privacy budget so the noise is smaller in the
// integration test. Check sample values in CompositionTest.kt.
private val OUTPUT_DP_PARAMS = differentialPrivacyParams {
epsilon = 1.0
delta = 1.0
delta = 1e-15
}
private val RESULT_POLLING_DELAY = Duration.ofSeconds(10)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@ abstract class InProcessLifeOfAReportIntegrationTest(
val actualResult =
MeasurementKt.result { reach = MeasurementKt.ResultKt.reach { value = reachResult.value } }
val tolerance = computeErrorMargin(reachResult.univariateStatistics.standardDeviation)
assertThat(actualResult).reachValue().isWithinPercent(tolerance).of(expectedResult.reach.value)
assertThat(actualResult).reachValue().isWithin(tolerance).of(expectedResult.reach.value)
}

@Test
Expand Down Expand Up @@ -574,7 +574,7 @@ abstract class InProcessLifeOfAReportIntegrationTest(
val actualResult =
MeasurementKt.result { reach = MeasurementKt.ResultKt.reach { value = reachResult.value } }
val tolerance = computeErrorMargin(reachResult.univariateStatistics.standardDeviation)
assertThat(actualResult).reachValue().isWithinPercent(tolerance).of(expectedResult.reach.value)
assertThat(actualResult).reachValue().isWithin(tolerance).of(expectedResult.reach.value)
}

@Test
Expand Down Expand Up @@ -1746,10 +1746,12 @@ abstract class InProcessLifeOfAReportIntegrationTest(
private val EVENT_RANGE =
OpenEndTimeRange.fromClosedDateRange(LocalDate.of(2021, 3, 15)..LocalDate.of(2021, 3, 17))

// Set epsilon and delta higher without exceeding privacy budget so the noise is smaller in the
// integration test. Check sample values in CompositionTest.kt.
private val DP_PARAMS =
MetricSpecKt.differentialPrivacyParams {
epsilon = 1.0
delta = 1.0
delta = 1e-15
}

private val VID_SAMPLING_INTERVAL =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ object PrivacyBudgets {
return PrivacyBudgetManager(
PrivacyBucketFilter(TestPrivacyBucketMapper()),
InMemoryBackingStore(),
1000.0f,
10.0f,
1000.0f,
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,15 @@ class AcdpParamsConverterTest {
assertThat(acdpCharge.theta).isWithin(TOLERANCE).of(expectedAcdpCharge.theta)
}

@Test
fun `llv2 rho and theta should be correct when epsilon is 1 in dpParams and three contributors`() {
val acdpCharge = AcdpParamsConverter.getLlv2AcdpCharge(DpParams(1.0, 1e-15), 3)
val expectedAcdpCharge = AcdpCharge(0.007051178301426351, 3.0946438646612866E-17)

assertThat(acdpCharge.rho).isWithin(TOLERANCE).of(expectedAcdpCharge.rho)
assertThat(acdpCharge.theta).isWithin(TOLERANCE).of(expectedAcdpCharge.theta)
}

@Test
fun `direct rho and theta should be correct with given dpParams`() {
val acdpCharge = AcdpParamsConverter.getDirectAcdpCharge(DP_PARAMS, SENSITIVITY)
Expand All @@ -88,6 +97,25 @@ class AcdpParamsConverterTest {
assertThat(acdpCharge.theta).isWithin(TOLERANCE).of(expectedAcdpCharge.theta)
}

@Test
fun `direct rho and theta should be correct when epsilon is 1 in dpParams`() {
// epsilon should be generally smaller than 1.0.
val acdpCharge = AcdpParamsConverter.getDirectAcdpCharge(DpParams(1.0, 1e-15), SENSITIVITY)
val expectedAcdpCharge = AcdpCharge(0.00887936992063019, 0.0)

assertThat(acdpCharge.rho).isWithin(TOLERANCE).of(expectedAcdpCharge.rho)
assertThat(acdpCharge.theta).isWithin(TOLERANCE).of(expectedAcdpCharge.theta)
}

@Test
fun `direct rho is large with large delta in dpParams`() {
val acdpCharge = AcdpParamsConverter.getDirectAcdpCharge(DpParams(0.1, 1.0), SENSITIVITY)
val expectedAcdpCharge = AcdpCharge(1996099.4646044022, 0.0)

assertThat(acdpCharge.rho).isWithin(TOLERANCE).of(expectedAcdpCharge.rho)
assertThat(acdpCharge.theta).isWithin(TOLERANCE).of(expectedAcdpCharge.theta)
}

companion object {
// ln(3.0) / 10 = 0.1098
private val DP_PARAMS = DpParams(ln(3.0) / 10, 0.2 / 100000)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ package org.wfanet.measurement.eventdataprovider.privacybudgetmanagement

import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.wfanet.measurement.eventdataprovider.noiser.DpParams

class CompositionTest {
@Test
Expand Down Expand Up @@ -97,6 +98,7 @@ class CompositionTest {
val targetEpsilon = 0.5
// (exp(epsilon) + 1) * theta = 2.6487212181091307E-12
val delta = Composition.totalPrivacyBudgetUsageUnderAcdpComposition(acdpCharges, targetEpsilon)

val expectedDelta = 0.26509576368586407

assertThat(delta).isEqualTo(expectedDelta)
Expand All @@ -111,4 +113,44 @@ class CompositionTest {

assertThat(delta).isEqualTo(expectedDelta)
}

@Test
fun `computed delta from totalPrivacyBudgetUsageUnderAcdpComposition is too large when targetEpsilon is large`() {
val acdpCharges = listOf(AcdpCharge(0.04, 5.0E-6))
val targetEpsilon = 100.0
val delta = Composition.totalPrivacyBudgetUsageUnderAcdpComposition(acdpCharges, targetEpsilon)
val expectedDelta = 1.344058570908068E38

assertThat(delta).isEqualTo(expectedDelta)
}

@Test
fun `acdp composition for direct measurement works as expected from sample dpParams and targetEpsilon`() {
val acdpCharges = listOf(AcdpParamsConverter.getDirectAcdpCharge(DpParams(1.0, 1e-5), 1.0))
val targetEpsilon = 10.0
val delta = Composition.totalPrivacyBudgetUsageUnderAcdpComposition(acdpCharges, targetEpsilon)
val expectedDelta = 2.3594607405220148E-303

assertThat(delta).isEqualTo(expectedDelta)
}

@Test
fun `acdp composition for llv2 measurement works as expected from sample dpParams and targetEpsilon`() {
val acdpCharges = listOf(AcdpParamsConverter.getLlv2AcdpCharge(DpParams(1.0, 1e-5), 3))
val targetEpsilon = 10.0
val delta = Composition.totalPrivacyBudgetUsageUnderAcdpComposition(acdpCharges, targetEpsilon)
val expectedDelta = 0.012922093064440253

assertThat(delta).isEqualTo(expectedDelta)
}

@Test
fun `computed delta for llv2 measurement from totalPrivacyBudgetUsageUnderAcdpComposition is large when delta is large in dpParams`() {
val acdpCharges = listOf(AcdpParamsConverter.getLlv2AcdpCharge(DpParams(1.0, 0.1), 3))
val targetEpsilon = 10.0
val delta = Composition.totalPrivacyBudgetUsageUnderAcdpComposition(acdpCharges, targetEpsilon)
val expectedDelta = 195.12544824856639

assertThat(delta).isEqualTo(expectedDelta)
}
}

0 comments on commit f269719

Please sign in to comment.