Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 651ac4d1 authored by Ricky Wai's avatar Ricky Wai Committed by Android (Google) Code Review
Browse files

Merge "Use sha256 of a string as seed in RapporEncoder.insecureEncoder" into pi-dev

parents a63484c0 b70d84a6
Loading
Loading
Loading
Loading
+16 −1
Original line number Original line Diff line number Diff line
@@ -20,6 +20,10 @@ import android.privacy.DifferentialPrivacyEncoder;


import com.google.android.rappor.Encoder;
import com.google.android.rappor.Encoder;


import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.SecureRandom;
import java.util.Random;
import java.util.Random;


@@ -66,7 +70,7 @@ public class RapporEncoder implements DifferentialPrivacyEncoder {
            random = sSecureRandom;
            random = sSecureRandom;
        } else {
        } else {
            // To have deterministic result by hard coding encoder id as seed.
            // To have deterministic result by hard coding encoder id as seed.
            random = new Random((long) config.mEncoderId.hashCode());
            random = new Random(getInsecureSeed(config.mEncoderId));
            userSecret = INSECURE_SECRET;
            userSecret = INSECURE_SECRET;
        }
        }
        mEncoder = new Encoder(random, null, null,
        mEncoder = new Encoder(random, null, null,
@@ -75,6 +79,17 @@ public class RapporEncoder implements DifferentialPrivacyEncoder {
                config.mNumCohorts, config.mNumBloomHashes);
                config.mNumCohorts, config.mNumBloomHashes);
    }
    }


    private long getInsecureSeed(String input) {
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            byte[] bytes = digest.digest(input.getBytes(StandardCharsets.UTF_8));
            return ByteBuffer.wrap(bytes).getLong();
        } catch (NoSuchAlgorithmException e) {
            // Should not happen
            throw new AssertionError("Unable generate insecure seed");
        }
    }

    /**
    /**
     * Create {@link RapporEncoder} with {@link RapporConfig} and user secret provided.
     * Create {@link RapporEncoder} with {@link RapporConfig} and user secret provided.
     *
     *
+1 −1
Original line number Original line Diff line number Diff line
@@ -8,7 +8,7 @@ LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := \
LOCAL_SRC_FILES := \
    $(call all-java-files-under, src)
    $(call all-java-files-under, src)


LOCAL_STATIC_JAVA_LIBRARIES := junit rappor-tests android-support-test
LOCAL_STATIC_JAVA_LIBRARIES := junit rappor-tests android-support-test truth-prebuilt


LOCAL_JAVA_LIBRARIES := android.test.runner
LOCAL_JAVA_LIBRARIES := android.test.runner
LOCAL_PACKAGE_NAME := FrameworksPrivacyLibraryTests
LOCAL_PACKAGE_NAME := FrameworksPrivacyLibraryTests
+37 −11
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@


package android.privacy;
package android.privacy;


import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertTrue;
@@ -72,27 +73,27 @@ public class LongitudinalReportingEncoderTest {
        final LongitudinalReportingEncoder encoder =
        final LongitudinalReportingEncoder encoder =
                LongitudinalReportingEncoder.createInsecureEncoderForTest(
                LongitudinalReportingEncoder.createInsecureEncoderForTest(
                        config);
                        config);
        assertEquals(0, encoder.encodeBoolean(true)[0]);
        assertEquals(0, encoder.encodeBoolean(true)[0]);
        assertEquals(1, encoder.encodeBoolean(true)[0]);
        assertEquals(1, encoder.encodeBoolean(true)[0]);
        assertEquals(0, encoder.encodeBoolean(true)[0]);
        assertEquals(1, encoder.encodeBoolean(true)[0]);
        assertEquals(1, encoder.encodeBoolean(true)[0]);
        assertEquals(1, encoder.encodeBoolean(true)[0]);
        assertEquals(1, encoder.encodeBoolean(true)[0]);
        assertEquals(0, encoder.encodeBoolean(true)[0]);
        assertEquals(1, encoder.encodeBoolean(true)[0]);
        assertEquals(1, encoder.encodeBoolean(true)[0]);
        assertEquals(1, encoder.encodeBoolean(true)[0]);
        assertEquals(1, encoder.encodeBoolean(true)[0]);
        assertEquals(1, encoder.encodeBoolean(true)[0]);
        assertEquals(1, encoder.encodeBoolean(true)[0]);
        assertEquals(1, encoder.encodeBoolean(true)[0]);
        assertEquals(1, encoder.encodeBoolean(true)[0]);
        assertEquals(0, encoder.encodeBoolean(true)[0]);
        assertEquals(0, encoder.encodeBoolean(true)[0]);


        assertEquals(0, encoder.encodeBoolean(false)[0]);
        assertEquals(0, encoder.encodeBoolean(false)[0]);
        assertEquals(1, encoder.encodeBoolean(false)[0]);
        assertEquals(1, encoder.encodeBoolean(false)[0]);
        assertEquals(1, encoder.encodeBoolean(false)[0]);
        assertEquals(1, encoder.encodeBoolean(false)[0]);
        assertEquals(1, encoder.encodeBoolean(false)[0]);
        assertEquals(0, encoder.encodeBoolean(false)[0]);
        assertEquals(0, encoder.encodeBoolean(false)[0]);
        assertEquals(0, encoder.encodeBoolean(false)[0]);
        assertEquals(0, encoder.encodeBoolean(false)[0]);
        assertEquals(1, encoder.encodeBoolean(false)[0]);
        assertEquals(0, encoder.encodeBoolean(false)[0]);
        assertEquals(0, encoder.encodeBoolean(false)[0]);
        assertEquals(1, encoder.encodeBoolean(false)[0]);
        assertEquals(0, encoder.encodeBoolean(false)[0]);
        assertEquals(1, encoder.encodeBoolean(false)[0]);
        assertEquals(0, encoder.encodeBoolean(false)[0]);
        assertEquals(0, encoder.encodeBoolean(false)[0]);
        assertEquals(0, encoder.encodeBoolean(false)[0]);


        // Test if IRR returns original result when f = 0
        // Test if IRR returns original result when f = 0
        final LongitudinalReportingConfig config2 = new LongitudinalReportingConfig(
        final LongitudinalReportingConfig config2 = new LongitudinalReportingConfig(
@@ -127,6 +128,31 @@ public class LongitudinalReportingEncoderTest {
        }
        }
    }
    }


    @Test
    public void testLongitudinalReportingInsecureEncoder_setSeedCorrectly() throws Exception {
        final int n = 10000;
        final double f = 0.35;
        final double expectedTrueSum = n * f;
        final double valueRange = 5 * Math.sqrt(n * f * (1 - f));
        int trueSum = 0;
        for (int i = 0; i < n; i++) {
            final LongitudinalReportingConfig config = new LongitudinalReportingConfig(
                    "encoder" + i,  // encoderId
                    f,  // probabilityF
                    0,  // probabilityP
                    1);  // probabilityQ
            final LongitudinalReportingEncoder encoder
                    = LongitudinalReportingEncoder.createInsecureEncoderForTest(config);
            boolean encodedFalse = encoder.encodeBoolean(false)[0] > 0;
            if (encodedFalse) {
                trueSum += 1;
            }
        }
        // Total number of true(s) should be around the mean (10000 * 0.35)
        assertThat((double) trueSum).isLessThan(expectedTrueSum + valueRange);
        assertThat((double) trueSum).isAtLeast(expectedTrueSum - valueRange);
    }

    @Test
    @Test
    public void testLongitudinalReportingEncoder_basicPRRTest() throws Exception {
    public void testLongitudinalReportingEncoder_basicPRRTest() throws Exception {
        // Should always return original value when p = 0
        // Should always return original value when p = 0
@@ -290,8 +316,8 @@ public class LongitudinalReportingEncoderTest {
            }
            }
        }
        }
        // Total number of true(s) should be around the mean (1000 * 0.8)
        // Total number of true(s) should be around the mean (1000 * 0.8)
        assertTrue(trueSum1 < expectedTrueSum1 + valueRange1);
        assertThat((double) trueSum1).isLessThan(expectedTrueSum1 + valueRange1);
        assertTrue(trueSum1 > expectedTrueSum1 - valueRange1);
        assertThat((double) trueSum1).isAtLeast(expectedTrueSum1 - valueRange1);


        // Confirm if PRR randomizer is working correctly
        // Confirm if PRR randomizer is working correctly
        final int n2 = 1000;
        final int n2 = 1000;
@@ -314,8 +340,8 @@ public class LongitudinalReportingEncoderTest {
            }
            }
        }
        }
        // Total number of true(s) should be around the mean (1000 * 0.2)
        // Total number of true(s) should be around the mean (1000 * 0.2)
        assertTrue(trueSum2 < expectedTrueSum2 + valueRange2);
        assertThat((double) trueSum2).isLessThan(expectedTrueSum2 + valueRange2);
        assertTrue(trueSum2 > expectedTrueSum2 - valueRange2);
        assertThat((double) trueSum2).isAtLeast(expectedTrueSum2 - valueRange2);
    }
    }


    @Test
    @Test
+9 −8
Original line number Original line Diff line number Diff line
@@ -79,11 +79,11 @@ public class RapporEncoderTest {
    public void testRapporEncoder_IRRWithPRR() throws Exception {
    public void testRapporEncoder_IRRWithPRR() throws Exception {
        int numBits = 8;
        int numBits = 8;
        final long inputValue = 254L;
        final long inputValue = 254L;
        final long prrValue = 250L;
        final long expectedPrrValue = 126L;
        final long prrAndIrrValue = 244L;
        final long expectedPrrAndIrrValue = 79L;


        final RapporConfig config1 = new RapporConfig(
        final RapporConfig config1 = new RapporConfig(
                "Foo", // encoderId
                "Foo2", // encoderId
                numBits, // numBits,
                numBits, // numBits,
                0.25, // probabilityF
                0.25, // probabilityF
                0, // probabilityP
                0, // probabilityP
@@ -93,12 +93,12 @@ public class RapporEncoderTest {
        // Use insecure encoder here as we want to get the exact output.
        // Use insecure encoder here as we want to get the exact output.
        final RapporEncoder encoder1 = RapporEncoder.createInsecureEncoderForTest(config1);
        final RapporEncoder encoder1 = RapporEncoder.createInsecureEncoderForTest(config1);
        // Verify that PRR is working as expected.
        // Verify that PRR is working as expected.
        assertEquals(prrValue, toLong(encoder1.encodeBits(toBytes(inputValue))));
        assertEquals(expectedPrrValue, toLong(encoder1.encodeBits(toBytes(inputValue))));
        assertTrue(encoder1.isInsecureEncoderForTest());
        assertTrue(encoder1.isInsecureEncoderForTest());


        // Verify that IRR is working as expected.
        // Verify that IRR is working as expected.
        final RapporConfig config2 = new RapporConfig(
        final RapporConfig config2 = new RapporConfig(
                "Foo", // encoderId
                "Foo2", // encoderId
                numBits, // numBits,
                numBits, // numBits,
                0, // probabilityF
                0, // probabilityF
                0.3, // probabilityP
                0.3, // probabilityP
@@ -107,11 +107,12 @@ public class RapporEncoderTest {
                2); // numBloomHashes
                2); // numBloomHashes
        // Use insecure encoder here as we want to get the exact output.
        // Use insecure encoder here as we want to get the exact output.
        final RapporEncoder encoder2 = RapporEncoder.createInsecureEncoderForTest(config2);
        final RapporEncoder encoder2 = RapporEncoder.createInsecureEncoderForTest(config2);
        assertEquals(prrAndIrrValue, toLong(encoder2.encodeBits(toBytes(prrValue))));
        assertEquals(expectedPrrAndIrrValue,
                toLong(encoder2.encodeBits(toBytes(expectedPrrValue))));


        // Test that end-to-end is the result of PRR + IRR.
        // Test that end-to-end is the result of PRR + IRR.
        final RapporConfig config3 = new RapporConfig(
        final RapporConfig config3 = new RapporConfig(
                "Foo", // encoderId
                "Foo2", // encoderId
                numBits, // numBits,
                numBits, // numBits,
                0.25, // probabilityF
                0.25, // probabilityF
                0.3, // probabilityP
                0.3, // probabilityP
@@ -120,7 +121,7 @@ public class RapporEncoderTest {
                2); // numBloomHashes
                2); // numBloomHashes
        final RapporEncoder encoder3 = RapporEncoder.createInsecureEncoderForTest(config3);
        final RapporEncoder encoder3 = RapporEncoder.createInsecureEncoderForTest(config3);
        // Verify that PRR is working as expected.
        // Verify that PRR is working as expected.
        assertEquals(prrAndIrrValue, toLong(encoder3.encodeBits(toBytes(inputValue))));
        assertEquals(expectedPrrAndIrrValue, toLong(encoder3.encodeBits(toBytes(inputValue))));
    }
    }


    @Test
    @Test
+3 −3
Original line number Original line Diff line number Diff line
@@ -75,11 +75,11 @@ public class PrivacyUtilsTests {
        Map<String, Boolean> result = PrivacyUtils.createDpEncodedReportMap(false, null,
        Map<String, Boolean> result = PrivacyUtils.createDpEncodedReportMap(false, null,
                TEST_DIGEST_LIST, TEST_AGGREGATED_RESULT1);
                TEST_DIGEST_LIST, TEST_AGGREGATED_RESULT1);
        assertEquals(6, result.size());
        assertEquals(6, result.size());
        assertTrue(result.get("C86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB48"));
        assertFalse(result.get("C86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB48"));
        assertTrue(result.get("C86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB49"));
        assertTrue(result.get("C86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB49"));
        assertTrue(result.get("C86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB47"));
        assertTrue(result.get("C86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB47"));
        assertFalse(result.get("E86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB45"));
        assertTrue(result.get("E86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB45"));
        assertTrue(result.get("C86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB44"));
        assertFalse(result.get("C86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB44"));
        assertTrue(result.get("B86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB43"));
        assertTrue(result.get("B86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB43"));
    }
    }