Пример #1
0
 def test_inverse_monotone_function(self, func, value, lower_x, upper_x,
                                    initial_guess_x, expected_x):
   search_parameters = common.BinarySearchParameters(
       lower_x, upper_x, initial_guess=initial_guess_x)
   self.assertAlmostEqual(
       expected_x,
       common.inverse_monotone_function(
           func,
           value,
           search_parameters))
Пример #2
0
  def from_privacy_guarantee(
      cls,
      privacy_parameters: common.DifferentialPrivacyParameters,
      sensitivity: float = 1,
      pessimistic_estimate: bool = True,
  ) -> 'GaussianPrivacyLoss':
    """Creates the privacy loss for Gaussian mechanism with desired privacy.

    Uses binary search to find the smallest possible standard deviation of the
    Gaussian noise for which the protocol is (epsilon, delta)-differentially
    private.

    Args:
      privacy_parameters: the desired privacy guarantee of the mechanism.
      sensitivity: the sensitivity of function f. (i.e. the maximum absolute
        change in f when an input to a single user changes.)
      pessimistic_estimate: a value indicating whether the rounding is done in
        such a way that the resulting epsilon-hockey stick divergence
        computation gives an upper estimate to the real value.

    Returns:
      The privacy loss of the Gaussian mechanism with the given privacy
      guarantee.
    """
    if privacy_parameters.delta == 0:
      raise ValueError('delta=0 is not allowed for the Gaussian mechanism')

    # The initial standard deviation is set to
    # sqrt(2 * ln(1.5/delta)) * sensitivity / epsilon. It is known that, when
    # epsilon is no more than one, the Gaussian mechanism with this standard
    # deviation is (epsilon, delta)-DP. See e.g. Appendix A in Dwork and Roth
    # book, "The Algorithmic Foundations of Differential Privacy".
    search_parameters = common.BinarySearchParameters(
        0,
        math.inf,
        initial_guess=math.sqrt(2 * math.log(1.5 / privacy_parameters.delta)) *
        sensitivity / privacy_parameters.epsilon)

    def _get_delta_for_standard_deviation(current_standard_deviation):
      return GaussianPrivacyLoss(
          current_standard_deviation,
          sensitivity=sensitivity).get_delta_for_epsilon(
              privacy_parameters.epsilon)

    standard_deviation = common.inverse_monotone_function(
        _get_delta_for_standard_deviation, privacy_parameters.delta,
        search_parameters)

    return GaussianPrivacyLoss(
        standard_deviation,
        sensitivity=sensitivity,
        pessimistic_estimate=pessimistic_estimate)
Пример #3
0
def get_smallest_discrete_laplace_noise(
        privacy_parameters: common.DifferentialPrivacyParameters,
        num_queries: int,
        sensitivity: int = 1) -> float:
    """Finds smallest discrete Laplace noise for which the mechanism satisfies desired privacy.

  Note that from the way discrete Laplace distribution is defined, the amount of
  noise decreases as the parameter increases. (In other words, the mechanism
  becomes less private as the parameter increases.) As a result, the output will
  be the largest parameter (instead of smallest as in Laplace).

  Args:
    privacy_parameters: The desired privacy guarantee.
    num_queries: Number of times the mechanism will be invoked.
    sensitivity: The l1 sensitivity of each query.

  Returns:
    Largest parameter for which the discrete Laplace mechanism with this
    parameter, when applied the given number of times, satisfies the desired
    privacy guarantee.
  """

    # Search for inverse of the parameter instead of the parameter itself.
    def privacy_loss_distribution_constructor(inverse_parameter):
        parameter = 1 / inverse_parameter
        # Setting value_discretization_interval equal to parameter because the
        # privacy loss of discrete Laplace mechanism is always divisible by the
        # parameter.
        return (privacy_loss_distribution.PrivacyLossDistribution.
                from_discrete_laplace_mechanism(
                    parameter,
                    sensitivity=sensitivity,
                    value_discretization_interval=parameter))

    # discrete Laplace mechanism with parameter
    # epsilon / (sensitivity * num_queries) is epsilon-DP (for num_queries
    # queries).
    search_parameters = common.BinarySearchParameters(
        0, num_queries * sensitivity / privacy_parameters.epsilon)

    inverse_parameter = get_smallest_parameter(
        privacy_parameters, num_queries, privacy_loss_distribution_constructor,
        search_parameters)
    if inverse_parameter is None:
        parameter = privacy_parameters.epsilon / (num_queries * sensitivity)
    else:
        parameter = 1 / inverse_parameter
    return parameter
Пример #4
0
 def test_inverse_monotone_function(self,
                                    func,
                                    value,
                                    lower_x,
                                    upper_x,
                                    initial_guess_x,
                                    expected_x,
                                    increasing,
                                    discrete=False):
   search_parameters = common.BinarySearchParameters(
       lower_x, upper_x, initial_guess=initial_guess_x, discrete=discrete)
   x = common.inverse_monotone_function(
       func, value, search_parameters, increasing=increasing)
   if expected_x is None:
     self.assertIsNone(x)
   else:
     self.assertAlmostEqual(expected_x, x)
Пример #5
0
  def from_privacy_guarantee(
      cls,
      privacy_parameters: common.DifferentialPrivacyParameters,
      sensitivity: int = 1,
  ) -> 'DiscreteGaussianPrivacyLoss':
    """Creates the privacy loss for discrete Gaussian mechanism with desired privacy.

    Uses binary search to find the smallest possible standard deviation of the
    discrete Gaussian noise for which the protocol is (epsilon, delta)-DP.

    Args:
      privacy_parameters: the desired privacy guarantee of the mechanism.
      sensitivity: the sensitivity of function f. (i.e. the maximum absolute
        change in f when an input to a single user changes.)

    Returns:
      The privacy loss of the discrete Gaussian mechanism with the given privacy
      guarantee.
    """
    if not isinstance(sensitivity, int):
      raise ValueError(f'Sensitivity is not an integer : {sensitivity}')
    if privacy_parameters.delta == 0:
      raise ValueError('delta=0 is not allowed for discrete Gaussian mechanism')

    # The initial standard deviation is set to
    # sqrt(2 * ln(1.5/delta)) * sensitivity / epsilon. It is known that, when
    # epsilon is no more than one, the (continuous) Gaussian mechanism with this
    # standard deviation is (epsilon, delta)-DP. See e.g. Appendix A in Dwork
    # and Roth book, "The Algorithmic Foundations of Differential Privacy".
    search_parameters = common.BinarySearchParameters(
        0,
        math.inf,
        initial_guess=math.sqrt(2 * math.log(1.5 / privacy_parameters.delta)) *
        sensitivity / privacy_parameters.epsilon)

    def _get_delta_for_sigma(current_sigma):
      return DiscreteGaussianPrivacyLoss(
          current_sigma,
          sensitivity=sensitivity).get_delta_for_epsilon(
              privacy_parameters.epsilon)

    sigma = common.inverse_monotone_function(
        _get_delta_for_sigma, privacy_parameters.delta, search_parameters)

    return DiscreteGaussianPrivacyLoss(sigma, sensitivity=sensitivity)
Пример #6
0
def get_smallest_epsilon_from_advanced_composition(
        total_privacy_parameters: common.DifferentialPrivacyParameters,
        num_queries: int,
        delta: float = 0) -> typing.Optional[float]:
    """Computes DP parameters that after a certain number of queries remain DP with given parameters.

  Using the optimal advanced composition theorem, Theorem 3.3 from the paper
  Kairouz, Oh, Viswanath. "The Composition Theorem for Differential Privacy",
  to compute DP parameter for an algorithm, so that when applied a given number
  of times it remains DP with given privacy parameters.

  Args:
    total_privacy_parameters: The desired privacy guarantee after applying the
      algorithm a given number of times.
    num_queries: Number of times the algorithm is invoked.
    delta: The value of DP parameter delta for the algorithm.

  Returns:
    epsilon such that if an algorithm is (epsilon, delta)-DP, then applying it
    the given number of times remains DP with total_privacy_parameters.

    None when total_privacy_parameters.delta is less than
    1 - (1 - delta)^num_queries for which no guarantee of
    total_privacy_parameters DP is possible for any value of epsilon.
  """
    if 1 - ((1 - delta)**num_queries) > total_privacy_parameters.delta:
        return None

    search_parameters = common.BinarySearchParameters(
        total_privacy_parameters.epsilon / num_queries,
        total_privacy_parameters.epsilon)

    def get_total_epsilon_for_epsilon(epsilon):
        privacy_parameters = common.DifferentialPrivacyParameters(
            epsilon, delta)
        return advanced_composition(privacy_parameters, num_queries,
                                    total_privacy_parameters.delta)

    return common.inverse_monotone_function(get_total_epsilon_for_epsilon,
                                            total_privacy_parameters.epsilon,
                                            search_parameters,
                                            increasing=True)
Пример #7
0
def get_smallest_laplace_noise(
    privacy_parameters: common.DifferentialPrivacyParameters,
    num_queries: int,
    sensitivity: float = 1) -> float:
  """Find smallest Laplace noise for which the mechanism satisfies desired privacy.

  Args:
    privacy_parameters: The desired privacy guarantee.
    num_queries: Number of times the mechanism will be invoked.
    sensitivity: The l1 sensitivity of each query.

  Returns:
    Smallest parameter for which the Laplace mechanism with this parameter, when
    applied the given number of times, satisfies the desired privacy guarantee.
  """

  def privacy_loss_distribution_constructor(parameter):
    # Setting value_discretization_interval equal to 0.001 * epsilon ensures
    # that the resulting parameter is not (epsilon', delta)-DP for epsilon' less
    # than  0.999 * epsilon. This is a heuristic for getting a reasonable
    # pessimistic estimate for the noise parameter.
    return (privacy_loss_distribution.PrivacyLossDistribution
            .from_laplace_mechanism(
                parameter,
                sensitivity=sensitivity,
                value_discretization_interval=0.001 *
                privacy_parameters.epsilon))

  # Laplace mechanism with parameter sensitivity * num_queries / epsilon is
  # epsilon-DP (for num_queries queries).
  search_parameters = common.BinarySearchParameters(
      0, num_queries * sensitivity / privacy_parameters.epsilon)

  parameter = get_smallest_parameter(privacy_parameters, num_queries,
                                     privacy_loss_distribution_constructor,
                                     search_parameters)
  if parameter is None:
    parameter = num_queries * sensitivity / privacy_parameters.epsilon
  return parameter